home *** CD-ROM | disk | FTP | other *** search
/ C Programming Starter Kit 2.0 / SamsPublishing-CProgrammingStarterKit-v2.0-Win31.iso / bc45 / ddeml.pak / DDESVR.CPP < prev    next >
C/C++ Source or Header  |  1997-07-23  |  11KB  |  390 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows - (C) Copyright 1991, 1993 by Borland International
  3. //
  4. //
  5. // This is a sample application using the OWL library that demonstrats the
  6. // use of the Windows 3.1 DDEML API in a server application.  You should
  7. // first build this application and run it.  Run the client application,
  8. // DDECLI.EXE, to start a conversation with this Server.  Detailed
  9. // information on DDEML can found in the online help and is suggested
  10. // reading for anyone interested in writing DDEML applications.  Search on
  11. // the keyword DDEML.
  12. //----------------------------------------------------------------------------
  13. #include <owl\owlpch.h>
  14. #include <owl\applicat.h>
  15. #include <owl\framewin.h>
  16. #include <owl\menu.h>
  17. #include <ddeml.h>
  18. #include <string.h>
  19.  
  20. #define CM_ABOUT 0x100
  21.  
  22.  
  23. class TDMLSrApp : public TApplication {
  24.   public:
  25.     TDMLSrApp() : TApplication(),CallBackProc((FARPROC)CallBack) {
  26.       nCmdShow = SW_SHOWMINIMIZED;
  27.       InstId=0;
  28.       }
  29.  
  30.     void InitMainWindow();
  31.     BOOL IdleAction(long);
  32.  
  33.     void InitInstance();
  34.     int TermInstance(int status);
  35.  
  36.     DWORD   InstId;
  37.     static HDDEDATA FAR PASCAL _export CallBack(WORD, WORD, HCONV, HSZ, HSZ,
  38.                                                 HDDEDATA, DWORD, DWORD);
  39.  
  40.     TProcInstance CallBackProc;
  41.  
  42. };
  43.  
  44.  
  45. class TDMLSrWnd : public TFrameWindow {
  46.   public:
  47.     TDMLSrWnd(TWindow*, const char*);
  48.     ~TDMLSrWnd();
  49.     void SetupWindow();
  50.  
  51.     void EvSysCommand(UINT cmdType, TPoint&);
  52.     BOOL EvQueryOpen();
  53.  
  54.     virtual BOOL MatchTopicAndService(HSZ, HSZ);
  55.     virtual BOOL MatchTopicAndItem(HSZ, HSZ);
  56.     virtual HDDEDATA WildConnect(HSZ, HSZ, WORD);
  57.     virtual HDDEDATA DataRequested(WORD);
  58.     virtual void UpdateData();
  59.  
  60.     DWORD   InstId() {
  61.       return ((TDMLSrApp*)GetApplication())->InstId;
  62.       }
  63.  
  64.     HCONV   HConv;
  65.     BOOL    Loop;
  66.     HSZ     Service;
  67.     HSZ     Topic;
  68.     HSZ     Item;
  69.  
  70.   DECLARE_RESPONSE_TABLE(TDMLSrWnd);
  71.   DECLARE_CASTABLE;
  72. };
  73.  
  74. DEFINE_RESPONSE_TABLE1(TDMLSrWnd, TFrameWindow)
  75.   EV_WM_SYSCOMMAND,
  76.   EV_WM_QUERYOPEN,
  77. END_RESPONSE_TABLE;
  78.  
  79. IMPLEMENT_CASTABLE1(TDMLSrWnd, TFrameWindow);
  80.  
  81.  
  82. TDMLSrWnd* This = 0;
  83.  
  84. TDMLSrWnd::TDMLSrWnd(TWindow* parent, const char* title)
  85.   : TFrameWindow(parent, title)
  86. {
  87.   HConv = 0;
  88.   Loop = FALSE;
  89. }
  90.  
  91. TDMLSrWnd::~TDMLSrWnd()
  92. {
  93.   // This clean up is required for those resources that were allocated during
  94.   // the DDE conversation.
  95.   //
  96.   if (HConv)
  97.     DdeDisconnect(HConv);   // Let the other party know we are leaving
  98.  
  99.   if (InstId()) {
  100.     DdeNameService(InstId(), Service, 0, DNS_UNREGISTER);
  101.     if (Service)
  102.       DdeFreeStringHandle(InstId(), Service);
  103.     if (Topic)
  104.       DdeFreeStringHandle(InstId(), Topic);
  105.     if (Item)
  106.       DdeFreeStringHandle(InstId(), Item);
  107.   }
  108. }
  109.  
  110. void
  111. TDMLSrWnd::SetupWindow()
  112. {
  113.   This = this;
  114.  
  115.   TFrameWindow::SetupWindow();
  116.  
  117.   Service = Topic = Item = 0;
  118.  
  119.   // The strings below are the 'Service', 'Topic' and 'Item' identifiers
  120.   // that this application makes available, through DDE, to other
  121.   // applications.
  122.   //
  123.   Service = DdeCreateStringHandle(InstId(), "TDMLSR_Server", CP_WINANSI);
  124.   Topic = DdeCreateStringHandle(InstId(), "Borland", CP_WINANSI);
  125.   Item = DdeCreateStringHandle(InstId(), "Products", CP_WINANSI);
  126.   if (Service && Topic && Item) {
  127.     if (DdeNameService(InstId(), Service, 0, DNS_REGISTER) != 0) {
  128.       // If everything is successful then an About choice is added to the
  129.       // system menu.
  130.       //
  131.       TMenu menu(GetSystemMenu());
  132.       menu.AppendMenu(MF_BYCOMMAND | MF_SEPARATOR, -1, "");
  133.       menu.AppendMenu(MF_BYCOMMAND | MF_STRING, CM_ABOUT, "&About DDESVR");
  134.     } else {
  135.       MessageBox("Registration failed.", Title, MB_ICONSTOP);
  136.       PostQuitMessage(0);
  137.     }
  138.   } else {
  139.     MessageBox("String creation failed.", Title, MB_ICONSTOP);
  140.     PostQuitMessage(0);
  141.   }
  142. }
  143.  
  144. //
  145. // The code below is used to trap the About menu choice when it is selected
  146. // from the system menu.
  147. //
  148. void
  149. TDMLSrWnd::EvSysCommand(UINT cmdType, TPoint&)
  150. {
  151.   if ((cmdType & 0xFFF0) == CM_ABOUT)
  152.     MessageBox("DDESVR.EXE\nWritten using ObjectWindows\nCopyright (c) 1991, 1993 by Borland International", "About DDESVR", MB_ICONINFORMATION);
  153.   else
  154.     DefaultProcessing();
  155. }
  156.  
  157. //
  158. // This seemingly insignificant function is what keeps this program
  159. // minimized, no matter what the user might try to do.
  160. //
  161. BOOL
  162. TDMLSrWnd::EvQueryOpen()
  163. {
  164.   return FALSE;
  165. }
  166.  
  167. //
  168. // This function is used to compare incoming Topic and Service requests.
  169. // This example DDE Server only makes one Service and one Topic available
  170. // so the logic is simple for this case but could be more complex for
  171. // Servers that offer multiple Services or Topics.
  172. //
  173. BOOL
  174. TDMLSrWnd::MatchTopicAndService(HSZ topic, HSZ service)
  175. {
  176.   if (DdeCmpStringHandles(Topic, topic) == 0)
  177.     if (DdeCmpStringHandles(Service, service) == 0)
  178.       return TRUE;
  179.   return FALSE;
  180. }
  181.  
  182. //
  183. // This function is used to compare incoming Topic and Item pair requests.
  184. // This Server only makes one Topic with one Item available so the logic is
  185. // simple for this case but could be more complex if the Server offered
  186. // multiple Items for multiple Topics.
  187. //
  188. BOOL
  189. TDMLSrWnd::MatchTopicAndItem(HSZ hsz1, HSZ hsz2)
  190. {
  191.   if (DdeCmpStringHandles(Topic, hsz1) == 0)
  192.     if (DdeCmpStringHandles(Item, hsz2) == 0)
  193.       return TRUE;
  194.   return FALSE;
  195. }
  196.  
  197. //
  198. // This function responds to 'system wide' polling of any available
  199. // Services with specific Topics, any Topics with specific Services or any
  200. // Services with any Topics.  It simply replies with a match, if there is
  201. // one, so that the polling application can open data discussions later, if
  202. // desired.
  203. //
  204. HDDEDATA
  205. TDMLSrWnd::WildConnect(HSZ hsz1, HSZ hsz2, WORD wFmt)
  206. {
  207.   HSZPAIR hszpTemp[] = { { Service, Topic }, { 0, 0 } };
  208.  
  209.   if (!hsz1 && !hsz2)    // Returns all if true
  210.     return DdeCreateDataHandle(InstId(), (LPBYTE)&hszpTemp[0], sizeof(hszpTemp), 0L, 0, wFmt, 0);
  211.  
  212.   if (!hsz1 && DdeCmpStringHandles(hsz2, Service) == 0)
  213.     return DdeCreateDataHandle(InstId(), (LPBYTE)&hszpTemp[0], sizeof(hszpTemp), 0L, 0, wFmt, 0);
  214.  
  215.   if (DdeCmpStringHandles(hsz1, Topic) == 0 && !hsz2)
  216.     return DdeCreateDataHandle(InstId(), (LPBYTE)&hszpTemp[0], sizeof(hszpTemp), 0L, 0, wFmt, 0);
  217.  
  218.   return 0;
  219. }
  220.  
  221. //
  222. //
  223. //
  224. HDDEDATA
  225. TDMLSrWnd::DataRequested(WORD wFmt)
  226. {
  227.   static char szItems[][42] = {
  228.     "Borland C++ with Object Windows",
  229.     "Turbo C++",
  230.     "Borland Pascal with Objects",
  231.     "Paradox For Windows",
  232.     "dBase",
  233.     "Quattro Pro For Windows"
  234.   };
  235.  
  236.   static int iLoop = 0;
  237.   if (wFmt == CF_TEXT) {
  238.     iLoop++;
  239.     iLoop %= sizeof(szItems) / sizeof(szItems[0]);
  240.     return DdeCreateDataHandle(InstId(), (unsigned char *)szItems[iLoop], sizeof(szItems[iLoop]), 0, Item, wFmt, 0);
  241.   }
  242.   return 0;
  243. }
  244.  
  245. //
  246. // This is triggered by the IdleAction() loop above whenever the user
  247. // enters an advise loop.
  248. //
  249. void
  250. TDMLSrWnd::UpdateData()
  251. {
  252.   DdePostAdvise(InstId(), Topic, Item);
  253. }
  254.  
  255. //
  256. // This call back function is the heart of interaction between this program
  257. // and DDE.  Because Windows doesn't pass C++ 'this' pointers to call
  258. // back functions, a static 'this' pointer was used.  If you wanted to
  259. // create a Server that would allow for more than one conversation, using a
  260. // List of conversations and their associated 'this' pointers would be one
  261. // possible method to try.  The XTYP_ constants are described in detail in
  262. // the online help.
  263. //
  264. HDDEDATA FAR PASCAL
  265. TDMLSrApp::CallBack(WORD wType, WORD wFmt, HCONV hConv, HSZ hsz1, HSZ hsz2,
  266.                     HDDEDATA hData, DWORD, DWORD)
  267. {
  268.   switch (wType) {
  269.     case XTYP_ADVREQ:
  270.       if (This->MatchTopicAndItem(hsz1, hsz2))
  271.         return This->DataRequested(wFmt);
  272.       return 0;
  273.  
  274.     case XTYP_ADVSTART:
  275.       if (!This->Loop && This->MatchTopicAndItem(hsz1, hsz2)) {
  276.         This->Loop = TRUE;
  277.         return (HDDEDATA)1;
  278.       }
  279.       return 0;
  280.  
  281.     case XTYP_ADVSTOP:
  282.       if (This->Loop && This->MatchTopicAndItem(hsz1, hsz2))
  283.         This->Loop = FALSE;
  284.       break;
  285.  
  286.     case XTYP_CONNECT:
  287.       if (!This->HConv)
  288.         if (This->MatchTopicAndService(hsz1, hsz2))
  289.           return (HDDEDATA)1;
  290.       return 0;
  291.  
  292.     case XTYP_CONNECT_CONFIRM:
  293.       This->HConv = hConv;
  294.       break;
  295.  
  296.     case XTYP_DISCONNECT:
  297.       if (hConv == This->HConv) {
  298.         This->HConv = 0;
  299.         This->Loop = FALSE;
  300.       }
  301.       break;
  302.  
  303.     case XTYP_ERROR:
  304.       This->MessageBox("A critical DDE error has occured.", This->Title, MB_ICONINFORMATION);
  305.       break;
  306.  
  307.     case XTYP_EXECUTE:
  308.       return DDE_FNOTPROCESSED;
  309.  
  310.     case XTYP_POKE: {
  311.       char temp[128];
  312.       strcpy(temp, "The server received: ");
  313.       int size = strlen(temp);
  314.       DdeGetData(hData, (unsigned char *)&temp[size], sizeof(temp) - size, 0);
  315.       ::MessageBox(GetFocus(), temp, This->Title, MB_ICONINFORMATION);
  316.       return (HDDEDATA)DDE_FACK;
  317.      }
  318.  
  319.     case XTYP_REQUEST:
  320.       if (This->MatchTopicAndItem(hsz1, hsz2))
  321.         return This->DataRequested(wFmt);
  322.       return 0;
  323.  
  324.     case XTYP_WILDCONNECT:
  325.       return This->WildConnect(hsz1, hsz2, wFmt);
  326.   }
  327.   return 0;
  328. }
  329.  
  330.  
  331. //
  332. // Make server window, and start it off minimized--it will keep itself like
  333. // that.
  334. //
  335. void
  336. TDMLSrApp::InitMainWindow()
  337. {
  338.   MainWindow = new TDMLSrWnd(0, "DDESVR (A DDE Server)");
  339. }
  340.  
  341. //
  342. // There are 16 available timers in Windows.  This little trick uses the
  343. // OWL IdleAction() member function to save that scarce resource.
  344. //
  345. BOOL
  346. TDMLSrApp::IdleAction(long)
  347. {
  348.   static DWORD dwTime = GetTickCount();
  349.   TDMLSrWnd* win = TYPESAFE_DOWNCAST(MainWindow, TDMLSrWnd);
  350.   if (MainWindow && win->Loop)
  351.     if (GetTickCount() - dwTime > 1000) {
  352.       dwTime = GetTickCount();
  353.       win->UpdateData();
  354.     }
  355.   return TRUE;
  356. }
  357.  
  358. void
  359. TDMLSrApp::InitInstance()
  360. {
  361.   // The code below sets up the DDEML call back function that is used by the
  362.   // DDE Management Library to carry out data transfers between
  363.   // applications.
  364.   //
  365.   if (DdeInitialize(&InstId, (PFNCALLBACK)(FARPROC)CallBackProc, 0, 0) != DMLERR_NO_ERROR) {
  366.       ::MessageBox(0,"Initialization failed.", "DDEML Server", MB_ICONSTOP|MB_TASKMODAL);
  367.       PostQuitMessage(0);
  368.     }
  369.  
  370.   // Must come after we've initialized DDE since InitInstance will trigger
  371.   // SetupWindow
  372.   TApplication::InitInstance();
  373. }
  374.  
  375. int
  376. TDMLSrApp::TermInstance(int status)
  377. {
  378.   if (InstId) {
  379.     DdeUninitialize(InstId);
  380.   }
  381.   return TApplication::TermInstance(status);
  382. }
  383.  
  384.  
  385. int
  386. OwlMain(int /*argc*/, char* /*argv*/ [])
  387. {
  388.   return TDMLSrApp().Run();
  389. }
  390.