home *** CD-ROM | disk | FTP | other *** search
/ C Programming Starter Kit 2.0 / SamsPublishing-CProgrammingStarterKit-v2.0-Win31.iso / bc45 / ddeml.pak / DDECLI.CPP next >
C/C++ Source or Header  |  1997-07-23  |  9KB  |  321 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 client application.  You should
  7. // first build the server application, DDESVR.EXE, and run it.  Then run the
  8. // client application, DDECLI.EXE, to start a conversation.  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\dc.h>
  17. #include <owl\menu.h>
  18. #include <owl\inputdia.h>
  19. #include "ddecli.rh"
  20. #include <ddeml.h>
  21. #include <stdio.h>
  22. #include <string.h>
  23.  
  24. class TDMLClWnd;
  25.  
  26. class TDMLClApp : public TApplication {
  27.   public:
  28.     TDMLClApp() : TApplication(),CallBackProc((FARPROC)CallBack) {
  29.       InstId = 0;
  30.       }
  31.     void InitMainWindow();
  32.     void InitInstance();
  33.     int TermInstance(int status);
  34.  
  35.     DWORD   InstId;
  36.     static HDDEDATA FAR PASCAL _export CallBack(WORD, WORD, HCONV, HSZ, HSZ,
  37.                                                 HDDEDATA, DWORD, DWORD);
  38.  
  39.     TProcInstance CallBackProc;
  40. };
  41.  
  42.  
  43. class TDMLClWnd : public TFrameWindow {
  44.   public:
  45.     TDMLClWnd(TWindow*, const char*);
  46.     virtual ~TDMLClWnd();
  47.  
  48.     virtual void SetupWindow();
  49.  
  50.     void EvPaint();
  51.     void EvInitMenu(HMENU);
  52.     void CmConnect();
  53.     void CmRequest();
  54.     void CmPoke();
  55.     void CmAdvise(WPARAM id);
  56.     void CmHelpAbout();
  57.  
  58.     void ReceivedData(HDDEDATA);
  59.  
  60.     DWORD   InstId() {
  61.       return ((TDMLClApp*)GetApplication())->InstId;
  62.       }
  63.  
  64.     char    Data[128];
  65.     HCONV   HConv;
  66.     BOOL    Loop;
  67.     HSZ     Service;
  68.     HSZ     Topic;
  69.     HSZ     Item;
  70.  
  71.   DECLARE_RESPONSE_TABLE(TDMLClWnd);
  72. };
  73.  
  74. DEFINE_RESPONSE_TABLE1(TDMLClWnd, TFrameWindow)
  75.   EV_WM_PAINT,
  76.   EV_WM_INITMENU,
  77.   EV_COMMAND(CM_CONNECT, CmConnect),
  78.   EV_COMMAND(CM_REQUEST, CmRequest),
  79.   EV_COMMAND(CM_POKE, CmPoke),
  80.   EV_COMMAND_AND_ID(CM_ADVISE, CmAdvise),
  81.   EV_COMMAND(CM_HELPABOUT, CmHelpAbout),
  82. END_RESPONSE_TABLE;
  83.  
  84. static TDMLClWnd* This = 0;
  85.  
  86. TDMLClWnd::TDMLClWnd(TWindow* parent, const char* title)
  87.   : TFrameWindow(parent, title),
  88.     TWindow(parent, title)
  89. {
  90.   Data[0] = 0;
  91.   HConv = 0;
  92.   Loop = 0;
  93. }
  94.  
  95. TDMLClWnd::~TDMLClWnd()
  96. {
  97.   // This clean up is required for those resources that were allocated during
  98.   // the DDEML conversation.
  99.   //
  100.   if (HConv)
  101.     DdeDisconnect(HConv);     // Let the other party know we are leaving
  102.  
  103.   if (InstId()) {
  104.     DdeFreeStringHandle(InstId(), Service);
  105.     DdeFreeStringHandle(InstId(), Topic);
  106.     DdeFreeStringHandle(InstId(), Item);
  107.     }
  108. }
  109.  
  110. void
  111. TDMLClWnd::SetupWindow()
  112. {
  113.   This = this;
  114.   TFrameWindow::SetupWindow();
  115.  
  116.   AssignMenu(TDMLClWnd_MENU);
  117.  
  118.   Service = Topic = Item = 0;
  119.  
  120.   Service = DdeCreateStringHandle(InstId(), "TDMLSR_Server", CP_WINANSI);
  121.   Topic = DdeCreateStringHandle(InstId(), "Borland", CP_WINANSI);
  122.   Item = DdeCreateStringHandle(InstId(), "Products", CP_WINANSI);
  123.   if (!Service || !Topic || !Item) {
  124.     MessageBox("Creation of strings failed.", Title, MB_ICONSTOP);
  125.     PostQuitMessage(0);
  126.   }
  127. }
  128.  
  129. void
  130. TDMLClWnd::EvPaint()
  131. {
  132.   TPaintDC paintDC(HWindow);
  133.   TRect rect;
  134.   char msg[] = "This example of the Dynamic Data Exchange Management "
  135.                "Library obtains the names of various Borland products "
  136.                "from the server DDESVR.EXE. To get started, first run "
  137.                "DDESVR.EXE and then select the \"Connect!\" menu item.";
  138.  
  139.   GetClientRect(rect);
  140.   if (*Data)
  141.     // The Data string is obtained from the DDESVR.EXE DDE Server.
  142.     paintDC.DrawText(Data, strlen(Data), rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
  143.   else
  144.     paintDC.DrawText(msg, strlen(msg), rect, DT_WORDBREAK);
  145. }
  146.  
  147. void
  148. TDMLClWnd::EvInitMenu(HMENU menuHandle)
  149. {
  150.   // This technique is used to automatically update the status of the various
  151.   // menu choices just before the menu is displayed.
  152.   //
  153.   TMenu menu(menuHandle);
  154.   menu.EnableMenuItem(CM_CONNECT, !HConv ? MF_ENABLED : MF_GRAYED);
  155.   menu.EnableMenuItem(CM_REQUEST, HConv ? MF_ENABLED : MF_GRAYED);
  156.   menu.EnableMenuItem(CM_POKE, HConv ? MF_ENABLED : MF_GRAYED);
  157.   menu.EnableMenuItem(CM_ADVISE, HConv ? MF_ENABLED : MF_GRAYED);
  158.   menu.CheckMenuItem(CM_ADVISE, MF_BYCOMMAND | Loop ? MF_CHECKED : MF_UNCHECKED);
  159.   DrawMenuBar();
  160. }
  161.  
  162. //
  163. // The following 4 functions are used to communicate with DDE Server(s).
  164. //
  165.  
  166. void
  167. TDMLClWnd::CmConnect()
  168. {
  169.   HConv = DdeConnect(InstId(),Service, Topic, 0);
  170.   if (HConv)
  171.     PostMessage(WM_INITMENU, WPARAM(GetMenu()));
  172.   else
  173.     MessageBox("Can't start conversation.\nTry running DDESVR (the server).",
  174.                Title,
  175.                MB_ICONSTOP);
  176. }
  177.  
  178. //
  179. // Request a data item. ReceiveData will be called asynchronously by the
  180. // callback 
  181. //
  182. void
  183. TDMLClWnd::CmRequest()
  184. {
  185.   DdeClientTransaction(0, 0, HConv, Item, CF_TEXT, XTYP_REQUEST, TIMEOUT_ASYNC, 0);
  186. }
  187.  
  188. //
  189. // Poke a string over to the server
  190. //
  191. void
  192. TDMLClWnd::CmPoke()
  193. {
  194.   char buff[42] = "";
  195.   if (TInputDialog(this, Title, "Poke string: ", buff, sizeof buff).Execute() == IDOK)
  196.     DdeClientTransaction((unsigned char*)buff, strlen(buff)+1, HConv, Item, CF_TEXT, XTYP_POKE, 1000, 0);
  197. }
  198.  
  199. //
  200. // Start or stop a continuous advise loop.
  201. //
  202. void
  203. TDMLClWnd::CmAdvise(WPARAM id)
  204. {
  205.   TMenu menu(GetMenu());
  206.   if (menu.GetMenuState(id, MF_BYCOMMAND) == MF_UNCHECKED) {
  207.     DWORD temp;
  208.     if (DdeClientTransaction(0, 0, HConv, Item, CF_TEXT, XTYP_ADVSTART | XTYPF_ACKREQ, 1000, &temp)) {
  209.       menu.CheckMenuItem(id, MF_BYCOMMAND | MF_CHECKED);
  210.       Loop = TRUE;
  211.     }
  212.   } else {
  213.     DWORD temp;
  214.     if (DdeClientTransaction(0, 0, HConv, Item, CF_TEXT, XTYP_ADVSTOP, 1000, &temp)) {
  215.       menu.CheckMenuItem(id, MF_BYCOMMAND | MF_UNCHECKED);
  216.       Loop = FALSE;
  217.     }
  218.   }
  219.   DrawMenuBar();
  220. }
  221.  
  222. void
  223. TDMLClWnd::CmHelpAbout()
  224. {
  225.   MessageBox("DDECLI.EXE\nWritten using ObjectWindows\n"
  226.              "Copyright (c) 1991, 1993 by Borland International",
  227.              "About DDECLI", MB_ICONINFORMATION);
  228. }
  229.  
  230. //
  231. // This function is called when the callback function is notified of
  232. // available data.
  233. //
  234. void
  235. TDMLClWnd::ReceivedData(HDDEDATA hData)
  236. {
  237.   if (hData) {
  238.     DdeGetData(hData, (unsigned char*)Data, sizeof Data, 0);
  239.     Invalidate(TRUE);
  240.   }
  241. }
  242.  
  243.  
  244. //
  245. // This call back function is the heart of interaction between this program
  246. // and DDEML.  Because Windows doesn't pass C++ 'this' pointers to call
  247. // back functions, a static 'this' pointer was used.  If you wanted to
  248. // create a Client that would allow for more than one conversation, using a
  249. // List of conversations and their associated 'this' pointers would be one
  250. // possible method to try.  The XTYP_ constants are described in detail in
  251. // the online help.
  252. //
  253. HDDEDATA FAR PASCAL _export
  254. TDMLClApp::CallBack(WORD type, WORD, HCONV hConv, HSZ, HSZ, HDDEDATA hData,
  255.                     DWORD, DWORD)
  256. {
  257.   switch (type) {
  258.     case XTYP_ADVDATA:
  259.       if (hConv == This->HConv)
  260.         This->ReceivedData(hData);
  261.       return (HDDEDATA)DDE_FACK;
  262.  
  263.     case XTYP_XACT_COMPLETE:
  264.       if (hConv == This->HConv)
  265.         This->ReceivedData(hData);
  266.       break;
  267.  
  268.     case XTYP_DISCONNECT:
  269.       This->MessageBox("Disconnected.", This->Title, MB_ICONINFORMATION);
  270.       This->HConv = 0;
  271.       This->Loop = 0;
  272.       This->PostMessage(WM_INITMENU, WPARAM(This->GetMenu()));
  273.       break;
  274.  
  275.     case XTYP_ERROR:
  276.       This->MessageBox("A critical DDE error has occured.", This->Title, MB_ICONINFORMATION);
  277.   }
  278.   return 0;
  279. }
  280.  
  281.  
  282. void 
  283. TDMLClApp::InitMainWindow()
  284. {
  285.   MainWindow = new TDMLClWnd(0, "DDECLI (A DDE Client)");
  286. }
  287.  
  288. void
  289. TDMLClApp::InitInstance()
  290. {
  291.  
  292.   // The code below sets up the DDEML call back function that is used by the
  293.   // DDE Management Library to carry out data transfers between
  294.   // applications.
  295.   //
  296.   if (DdeInitialize(&InstId, (PFNCALLBACK)(FARPROC)CallBackProc, APPCMD_CLIENTONLY, 0) != DMLERR_NO_ERROR) {
  297.       ::MessageBox(0,"Initialization failed.", "DDEML Client", MB_ICONSTOP|MB_TASKMODAL);
  298.       PostQuitMessage(0);
  299.     }
  300.  
  301.   // Must come after we've initialized DDE since InitInstance will trigger
  302.   // SetupWindow
  303.   TApplication::InitInstance();
  304. }
  305.  
  306. int
  307. TDMLClApp::TermInstance(int status)
  308. {
  309.   if (InstId) {
  310.     DdeUninitialize(InstId);
  311.   }
  312.   return TApplication::TermInstance(status);
  313. }
  314.  
  315.  
  316. int
  317. OwlMain(int /*argc*/, char* /*argv*/ [])
  318. {
  319.   return TDMLClApp().Run();
  320. }
  321.