home *** CD-ROM | disk | FTP | other *** search
/ MORE WinGames / WINGAMES.iso / hearts / codedemo.txt next >
Text File  |  1993-03-22  |  16KB  |  447 lines

  1. You need to create a number of variables
  2.  
  3. HANDLE    ghMyInstance;         //my instance, simple
  4. short     gnMyInstanceCount;    //2 bytes 
  5. HWND      hwndMain;             //the main visible window
  6. HWND      hwndDDE;              //The invisible DDE window.
  7. HWND      hwndMyContact;        //the DDE window our DDE window talks to
  8. BOOL      bTerminating;         //Boolean. Any number of bytes.
  9. BOOL      bAlreadyConversing;   //Tre or False, whether or not we are already playing
  10. ATOM      atomPlayerNotReady;   //atom
  11. ATOM      atomPlayerReady;      //atom
  12. ATOM      atomMyName;           //atom
  13. ATOM      atomNewHeartsPlayer;  //atom
  14. HANDLE    hDDEInformation;      //Handle to a Globally allocated memory, allocated by dealer.
  15.  
  16.  
  17.  
  18.  
  19. You need a number of core functions to get off the ground
  20.  
  21. int  PASCAL     WinMain                     (HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);
  22. long FAR PASCAL MainWndProc                 (HWND, unsigned, WORD, LONG);
  23. long FAR PASCAL DDEWndProc                  (HWND, unsigned, WORD, LONG);
  24. BOOL            InitApplication             (HANDLE);
  25. void            UnInitApplication           ();
  26. BOOL            InitInstance                (HANDLE,HANDLE, int);
  27. BOOL FAR PASCAL AboutDlgProc                (HWND, unsigned, WORD, LONG);
  28. char*           ConvertCardToText           (cardtype* cardToConvert, char* szResultText);
  29. short           ProcessInitiate             (HWND hwnd, unsigned message, WORD wParam, LONG lParam);
  30. short           ProcessTermination          (HWND hwnd, unsigned message, WORD wParam, LONG lParam);
  31. short           ProcessDealerMessage        (HWND hwnd, unsigned message, WORD wParam, LONG lParam);
  32. void            CauseConversationTermination(short bMakeSelfAvailableAgain);
  33.  
  34.  
  35.  
  36.  
  37.  
  38. This is what each of the functions need to do.
  39.  
  40.  
  41. int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){
  42. //  All you have to do is simply initialize your code.
  43. //  Create the main window and the DDE window.
  44. //  Run the message loop
  45. //
  46.     //example C code.
  47.     MSG   msg;
  48.     if(!hPrevInstance){
  49.        if(!InitApplication(hInstance))
  50.           return (FALSE);
  51.     }
  52.     if(!InitInstance(hInstance, hPrevInstance, nCmdShow))
  53.         return (FALSE);
  54.     while (GetMessage(&msg, NULL, NULL, NULL)){
  55.        TranslateMessage(&msg);
  56.        DispatchMessage(&msg);
  57.     }
  58.     UnInitApplication();
  59.     return (msg.wParam);
  60. }
  61.  
  62.  
  63.  
  64.  
  65. BOOL InitApplication(HANDLE hInstance){
  66. //  If there was no previous instance of this program, then call this function.
  67. //  Register the main window and DDE window classes.
  68.  
  69.     //example C code
  70.     WNDCLASS  wc;
  71.     wc.style         = NULL;
  72.     wc.lpfnWndProc   = (long(pascal*)(unsigned int,unsigned int,unsigned int,long))MainWndProc;
  73.     wc.cbClsExtra    = 0;
  74.     wc.cbWndExtra    = 0;
  75.     wc.hInstance     = hInstance;
  76.     wc.hIcon         = 0;
  77.     wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  78.     wc.hbrBackground = GetStockObject(WHITE_BRUSH); 
  79.     wc.lpszMenuName  = SZ_CLIENT_WINDOW_CLASS;
  80.     wc.lpszClassName = SZ_CLIENT_WINDOW_CLASS;
  81.     if(!RegisterClass(&wc))
  82.         return FALSE;
  83.     wc.style         = NULL;
  84.     wc.lpfnWndProc   = (long(pascal*)(unsigned int,unsigned int,unsigned int,long))DDEWndProc;
  85.     wc.cbClsExtra    = 0;
  86.     wc.cbWndExtra    = 0;
  87.     wc.hInstance     = hInstance;
  88.     wc.hIcon         = NULL;
  89.     wc.hCursor       = NULL;
  90.     wc.hbrBackground = NULL;
  91.     wc.lpszMenuName  = NULL;
  92.     wc.lpszClassName = SZ_CLIENT_DDE_WINDOW_CLASS;
  93.     return RegisterClass(&wc);
  94. }
  95.  
  96.  
  97.  
  98.  
  99.  
  100. BOOL InitInstance(HANDLE hInstance, HANDLE hPrevInstance, int nCmdShow){
  101. //Create the two windows, the main and DDE windows.  
  102. //Show the main window.
  103. //Create the four necessary atoms.
  104. //Send a message to all 'overlapped' windows telling them we are here.
  105. //In the example code, we get the count of ourselves by asking any previous
  106. //  instance what its count was.  This is useful if we want to play two or 
  107. //  more of them at the same time.  Giving ourselves a count makes it easier
  108. //  to identify which player is which.  
  109.  
  110.     //example C code
  111.     HDC         hDC;
  112.     ghMyInstance = hInstance;
  113.     hwndMain = CreateWindow(SZ_CLIENT_WINDOW_CLASS,SZ_CLIENT_WINDOW_NAME,
  114.                             WS_OVERLAPPEDWINDOW,100,100,100,100,                                    //Height
  115.                             NULL,NULL,hInstance,NULL);
  116.     if(!hwndMain)
  117.        return FALSE;
  118.     ShowWindow(hwndMain, nCmdShow);
  119.     hwndDDE = CreateWindow(SZ_CLIENT_DDE_WINDOW_CLASS,
  120.                            SZ_CLIENT_DDE_WINDOW_NAME,
  121.                            WS_OVERLAPPED,0,0,1,1,NULL,NULL,hInstance, NULL);
  122.     if(!hwndDDE){
  123.        DestroyWindow(hwndMain);
  124.        return FALSE;
  125.     }
  126.     if(hPrevInstance)
  127.        gnMyInstanceCount  =SendMessage(hPrevInstance,WM_WHATS_YOUR_INSTANCE_COUNT, 0, 0L)+1;
  128.     if(gnMyInstanceCount>0) //only put this count if there is more than a single instance of me.
  129.        wsprintf(ATOM_MY_NAME+N_ATOM_MY_NAME, "%d",gnMyInstanceCount+1); //'+1' converts to 1-based counting
  130.     atomPlayerNotReady =GlobalAddAtom(ATOM_TOPIC_YOUR_CONTACT);
  131.     atomPlayerReady    =GlobalAddAtom(ATOM_TOPIC_PLAYER_READY);
  132.     atomMyName         =GlobalAddAtom(ATOM_MY_NAME);
  133.     atomNewHeartsPlayer=GlobalAddAtom(ATOM_TOPIC_NEW_HEARTS_PLAYER);
  134.     //We send out a message to everyone (especially any Hearts games playing) that we are here.
  135.     SendMessage(SEND_TO_ALL_WINDOWS, HM_INITIATE_CONVERSATION, hwndDDE, MAKELONG(atomMyName,atomNewHeartsPlayer));
  136.     return TRUE;
  137. }
  138.  
  139.  
  140.  
  141.  
  142.  
  143.  
  144. void UnInitApplication(){
  145. //This is called when the user quits the external player application.
  146. //If we are still in a game with the dealer, then 'cause it to stop' 
  147. //destroy the DDE window.  We don't destroy the main window here becuase
  148. //  presumably the destruction of it by other means is what caused this
  149. //  function to be called.
  150. //Delete the four all-important atoms.
  151.  
  152.    //example C code.
  153.    if(bAlreadyConversing)
  154.       CauseConversationTermination(FALSE);
  155.    if(hwndDDE)
  156.       DestroyWindow(hwndDDE);
  157.    GlobalDeleteAtom(atomPlayerNotReady);
  158.    GlobalDeleteAtom(atomPlayerReady);
  159.    GlobalDeleteAtom(atomMyName);
  160.    GlobalDeleteAtom(atomNewHeartsPlayer);
  161. }
  162.  
  163.  
  164.  
  165.  
  166. long FAR PASCAL MainWndProc(HWND hwnd, unsigned message, WORD wParam, LONG lParam){
  167. //This is our main window procedure.
  168. //We don't do anything unusual here except respond to the WM_WHATS_YOUR_INSTANCE_COUNT
  169. //  message and call the 'CauseConversationTermination()' function in the 
  170. //  WM_DESTROY message.
  171.  
  172.     //example C code
  173.     PAINTSTRUCT paintstructTemp;
  174.     HDC         hdcTemp;
  175.     FARPROC     procAboutBox;
  176.     switch (message){
  177.         case WM_PAINT:
  178.             hdcTemp = BeginPaint(hwnd, &paintstructTemp);
  179.             //Put whatever you want here. 
  180.             EndPaint(hwnd, &paintstructTemp);
  181.             break;
  182.         case WM_DESTROY:
  183.         bTerminating = TRUE;
  184.         CauseConversationTermination(FALSE);  //Save This Function Call.
  185.             PostQuitMessage(0);
  186.             break;
  187.         case WM_COMMAND:
  188.            switch (wParam){
  189.               case ID_ABOUT:
  190.                  procAboutBox = MakeProcInstance((FARPROC)AboutDlgProc, ghMyInstance);
  191.                  if(procAboutBox){
  192.                     DialogBox(ghMyInstance, SZ_ABOUT_DIALOG_NAME, hwndMain, procAboutBox);
  193.                     FreeProcInstance(procAboutBox);
  194.                  }
  195.                  break;
  196.               case ID_QUIT:
  197.                  PostQuitMessage(0);
  198.                  break;
  199.               case ID_END_PLAY:
  200.                  CauseConversationTermination(TRUE);
  201.                  break;
  202.            }
  203.            break;
  204.         case WM_WHATS_YOUR_INSTANCE_COUNT:
  205.            return gnMyInstanceCount;
  206.     default:
  207.         return DefWindowProc(hwnd, message, wParam, lParam);
  208.     }
  209.     return 1L;
  210. }
  211.  
  212.  
  213.  
  214.  
  215.  
  216. BOOL FAR PASCAL AboutDlgProc(HWND hDlg, unsigned message, WORD wParam, LONG lParam){
  217. //This is the 'About' dialog procedure.  You may want to make an 'About box' that
  218. //  gives some information about the external player.  Then give it an OK button
  219.  
  220.    //example C code
  221.    switch (message) {
  222.       case WM_INITDIALOG:
  223.         return TRUE;
  224.       case WM_COMMAND:
  225.         if(wParam == IDOK || wParam == IDCANCEL) {
  226.            EndDialog(hDlg, TRUE);
  227.               return TRUE;
  228.         }
  229.         break;
  230.    }
  231.    return FALSE;
  232. }
  233.  
  234.  
  235.  
  236.  
  237. long FAR PASCAL DDEWndProc(HWND hwnd, unsigned message, WORD wParam, LONG lParam){
  238. //This is the DDE window's procedure.  It must respond to the three important 
  239. //  DDE messages from the dealer.  It doesn't need to paint becuase it is invisible.
  240. //  Each of the three messages from the dealer have an associated function that 
  241. //  we call.  See the example below.
  242.  
  243.     //example C code
  244.     switch (message){
  245.        case HM_INITIATE_CONVERSATION:      //(same as WM_DDE_INITIATE)
  246.           return ProcessInitiate(hwnd, message, wParam, lParam);
  247.        case HM_TERMINATE_CONVERSATION:     //(same as WM_DDE_TERMINATE)
  248.           return ProcessTermination(hwnd, message, wParam, lParam);
  249.        case HM_DLR_PROCESS_THIS_MESSAGE:   //(same as WM_DDE_DATA)
  250.           return ProcessDealerMessage(hwnd, message, wParam, lParam);
  251.        default:
  252.           return DefWindowProc(hwnd, message, wParam, lParam);
  253.     }
  254. }
  255.  
  256.  
  257.  
  258.  
  259. short ProcessInitiate(HWND hwnd, unsigned message, WORD wParam, LONG lParam){
  260. //This is called from the DDE window procedure.  There are two types of 
  261. //  initiate messages, one for the NEW_GAME, and one for a NEW_CONTACT.  See
  262. //  the documentation for the description of the initiation procedure.
  263. //Essentially, we must see if it is a new game initiation.  If so then 
  264. //  ignore it if we are already playing.  Also, ignore the message if it is 
  265. //  coming from ourselves.  The HWND sending is in the wParam of the message.
  266. //If it is a NEW_CONTACT message, then if we are not already playing with 
  267. //  another dealer, set the contact HWND (in wParam) to be our contact.
  268. //Send acknowledgment messages back if OK in both cases.
  269.  
  270.    //example C code
  271.    char szAtomText[256];
  272.    WORD wApplication=LOWORD(lParam);
  273.    WORD wTopic      =HIWORD(lParam);
  274.    if(wParam == hwndDDE)   //Return if the sender is myself.
  275.       return NOT_OK;
  276.    GlobalGetAtomName(wTopic, szAtomText, 255);
  277.    if(!lstrcmp(szAtomText, ATOM_TOPIC_NEW_HEARTS_GAME)){
  278.       if(!bAlreadyConversing){
  279.          //Send message back to the sender that we can converse with him.
  280.          SendMessage((HWND)wParam, HM_ACKNOWLEDGEMENT, hwndDDE, MAKELONG(atomMyName, wTopic));
  281.          return OK;
  282.       }
  283.       //otherwise ignore the initiation, we are busy already with someone else
  284.    }
  285.    else if(!lstrcmp(szAtomText,ATOM_TOPIC_YOUR_CONTACT)){
  286.       //This means that we are being called into the conversation for good.
  287.       if(!bAlreadyConversing){
  288.          bAlreadyConversing =TRUE;
  289.          hwndMyContact=(HWND)wParam;
  290.          SendMessage((HWND)wParam, HM_ACKNOWLEDGEMENT, hwndDDE, MAKELONG(atomMyName, atomPlayerReady));
  291.          return OK;
  292.       }
  293.       else{
  294.          return NOT_OK;
  295.       }
  296.    }
  297.    //Otherwise we cannot be a client for the message sender.
  298.    return NOT_OK;
  299. }
  300.  
  301.  
  302.  
  303.  
  304.  
  305.  
  306. short ProcessTermination(HWND hwnd, unsigned message, WORD wParam, LONG lParam){
  307. //We are being told to terminate.
  308. //This means our conversation is over and we can prepare to make a conversation
  309. //  with someone else if they ask.
  310. //All we have to do is set everything to zero.  Since the Contact told us to close, we
  311. //  don't have to send it anything back.
  312.  
  313.    //example C code
  314.    hwndMyContact      =
  315.    hDDEInformation    =
  316.    bTerminating       =
  317.    bAlreadyConversing =0;
  318.    return OK;
  319. }
  320.  
  321.  
  322.  
  323.  
  324. void CauseConversationTermination(short bMakeSelfAvailableAgain){
  325. //Tell the contact that we are OUTTA HERE.
  326. //Don't tell anyone unless we are actually in a conversation with them.
  327.  
  328.    //example C code
  329.    if(bAlreadyConversing){
  330.       PostMessage(hwndMyContact, HM_TERMINATE_CONVERSATION, hwndDDE, 0L);
  331.    }
  332.    hwndMyContact      =0;   //Not necessary if we are closing our app, of course.
  333.    bTerminating       =0;
  334.    bAlreadyConversing =0;
  335.    hDDEInformation    =0;
  336.    if(bMakeSelfAvailableAgain)
  337.       SendMessage(SEND_TO_ALL_WINDOWS, HM_INITIATE_CONVERSATION, hwndDDE, MAKELONG(atomMyName,atomNewHeartsPlayer));
  338. }
  339.  
  340.  
  341.  
  342.  
  343. short ProcessDealerMessage(HWND hwnd, unsigned message, WORD wParam, LONG lParam){
  344. //loword is hData, hiword is atomItem. Same as WM_DDE_DATA.
  345. //This function is the main card playing function of importance.  
  346. //There should be a function (or equivalent) for each message from the dealer
  347. //  that you want to respond to.  You MUST respond to the 5 required messages.
  348. //  You don't have to respond to the other 'notify' messages.  
  349. //You want to first make sure the message sender is your contact.
  350. //Then lock the global memory share so you can read the message.
  351. //Then test if it is a notify message.  If so then do what you want with it.
  352. //If instead it is a 'your turn' message, then you must call functions to 
  353. //  come up with your answer and put your answer into the appropriate place 
  354. //  in the global share and then return to this function and post your 
  355. //  answer message to the dealer.  
  356. //Below the example code shows everything except the filling in of the 
  357. //  global share with the answer.  
  358.  
  359.    //example C code.
  360.    MessageStruct far* messageStructFromDealer;
  361.    short i;
  362.    char szAtomText[256];
  363.    WORD hData =LOWORD(lParam);
  364.    WORD wTopic=HIWORD(lParam);
  365.  
  366.    if(wParam != hwndMyContact)
  367.       return NOT_OK;
  368.    if(!hDDEInformation)
  369.       hDDEInformation = LOWORD(lParam);
  370.    if(!hDDEInformation)
  371.       return NOT_OK;
  372.    messageStructFromDealer = (MessageStruct far*) GlobalLock(hDDEInformation);
  373.    GlobalGetAtomName(wTopic, szAtomText, 255);
  374.    if(!lstrcmp(szAtomText, ATOM_TOPIC_NOTIFY)){
  375.  
  376.       //Call a function(s) here to process the notification. 
  377.  
  378.    }
  379.    else if(!lstrcmp(szAtomText, ATOM_TOPIC_YOUR_TURN)){
  380.       //Call a function here depending on exactly which message was sent.
  381.       //The global storage should be filled in with the answer.
  382.       
  383.       //Call the all important functions here.        
  384.  
  385.       if(nearMessageStruct.nQueryMessage == P_DO_PASS         ||
  386.          nearMessageStruct.nQueryMessage == P_LEAD_CARD       ||
  387.          nearMessageStruct.nQueryMessage == P_PLAY_CARD       ||
  388.          nearMessageStruct.nQueryMessage == P_REGISTER_PLAYER)
  389.       {
  390.          messageStructFromDealer->nReturnMessage = messageStructFromDealer->nQueryMessage;
  391.          //In this case we must send our answer back to the dealer.
  392.          //For this PostMessage, loword is hData and  hiword is atomItem. Same as sending WM_DDE_POKE.
  393.          //Normally, in DDE, we put the anwser (hData) in LOWORD(lParam) and topic in HIWORD(lParam)
  394.          //  Since these values are already known by both parties, this is not necessary.
  395.          PostMessage(hwndMyContact, HM_PLR_HERE_IS_MY_ANSWER, hwndDDE, 0L);
  396.       }                             //same as WM_DDE_POKE
  397.    }
  398.    GlobalUnlock(hDDEInformation);
  399.    return OK;
  400. }
  401.  
  402.  
  403.  
  404.  
  405.  
  406. char* ConvertCardToText(cardtype* cardToConvert, char* szResultText){
  407. //This function is not necessary but may be useful for debugging. It 
  408. //  converts a 'cardtype' (see external.txt/doc) to a text string for
  409. //  display (possibly in the main window) to show at run-time.  Since
  410. //  DDE is a real-time system, you cannot sit in a debugger while the
  411. //  messages are trying to be passed around and time-outs are happening.
  412.  
  413.    //example C code
  414.    //The return is a pointer to the 'szResultText'
  415.    //The result text is an array of characters (min of 4) to be filled in with the text.
  416.    //The card text is in the format of: 10H, JD, QS, 4C, 9H, AD, etc.
  417.    char szSuitChars[4][2]    = {"S","D","C","H"};
  418.    char szNumberChars[13][3] = {"2","3","4","5","6","7","8","9","10","J","Q","K","A"};
  419.  
  420.    lstrcpy(szResultText,szNumberChars[cardToConvert->kind.number-2]);
  421.    lstrcat(szResultText,szSuitChars[cardToConvert->kind.suit-1]);
  422.    return szResultText;
  423. }
  424.  
  425.  
  426.  
  427.  
  428.  
  429.  
  430.  
  431.  
  432.  
  433.  
  434.  
  435.  
  436.  
  437.  
  438.  
  439.  
  440.  
  441.  
  442.  
  443.  
  444.  
  445.  
  446.  
  447.