home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c082_122 / 7.ddi / DDEML.ZIP / DDESVR.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-10  |  11.1 KB  |  354 lines

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