home *** CD-ROM | disk | FTP | other *** search
- You need to create a number of variables
-
- HANDLE ghMyInstance; //my instance, simple
- short gnMyInstanceCount; //2 bytes
- HWND hwndMain; //the main visible window
- HWND hwndDDE; //The invisible DDE window.
- HWND hwndMyContact; //the DDE window our DDE window talks to
- BOOL bTerminating; //Boolean. Any number of bytes.
- BOOL bAlreadyConversing; //Tre or False, whether or not we are already playing
- ATOM atomPlayerNotReady; //atom
- ATOM atomPlayerReady; //atom
- ATOM atomMyName; //atom
- ATOM atomNewHeartsPlayer; //atom
- HANDLE hDDEInformation; //Handle to a Globally allocated memory, allocated by dealer.
-
-
-
-
- You need a number of core functions to get off the ground
-
- int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);
- long FAR PASCAL MainWndProc (HWND, unsigned, WORD, LONG);
- long FAR PASCAL DDEWndProc (HWND, unsigned, WORD, LONG);
- BOOL InitApplication (HANDLE);
- void UnInitApplication ();
- BOOL InitInstance (HANDLE,HANDLE, int);
- BOOL FAR PASCAL AboutDlgProc (HWND, unsigned, WORD, LONG);
- char* ConvertCardToText (cardtype* cardToConvert, char* szResultText);
- short ProcessInitiate (HWND hwnd, unsigned message, WORD wParam, LONG lParam);
- short ProcessTermination (HWND hwnd, unsigned message, WORD wParam, LONG lParam);
- short ProcessDealerMessage (HWND hwnd, unsigned message, WORD wParam, LONG lParam);
- void CauseConversationTermination(short bMakeSelfAvailableAgain);
-
-
-
-
-
- This is what each of the functions need to do.
-
-
- int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){
- // All you have to do is simply initialize your code.
- // Create the main window and the DDE window.
- // Run the message loop
- //
- //example C code.
- MSG msg;
- if(!hPrevInstance){
- if(!InitApplication(hInstance))
- return (FALSE);
- }
- if(!InitInstance(hInstance, hPrevInstance, nCmdShow))
- return (FALSE);
- while (GetMessage(&msg, NULL, NULL, NULL)){
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- UnInitApplication();
- return (msg.wParam);
- }
-
-
-
-
- BOOL InitApplication(HANDLE hInstance){
- // If there was no previous instance of this program, then call this function.
- // Register the main window and DDE window classes.
-
- //example C code
- WNDCLASS wc;
- wc.style = NULL;
- wc.lpfnWndProc = (long(pascal*)(unsigned int,unsigned int,unsigned int,long))MainWndProc;
- wc.cbClsExtra = 0;
- wc.cbWndExtra = 0;
- wc.hInstance = hInstance;
- wc.hIcon = 0;
- wc.hCursor = LoadCursor(NULL, IDC_ARROW);
- wc.hbrBackground = GetStockObject(WHITE_BRUSH);
- wc.lpszMenuName = SZ_CLIENT_WINDOW_CLASS;
- wc.lpszClassName = SZ_CLIENT_WINDOW_CLASS;
- if(!RegisterClass(&wc))
- return FALSE;
- wc.style = NULL;
- wc.lpfnWndProc = (long(pascal*)(unsigned int,unsigned int,unsigned int,long))DDEWndProc;
- wc.cbClsExtra = 0;
- wc.cbWndExtra = 0;
- wc.hInstance = hInstance;
- wc.hIcon = NULL;
- wc.hCursor = NULL;
- wc.hbrBackground = NULL;
- wc.lpszMenuName = NULL;
- wc.lpszClassName = SZ_CLIENT_DDE_WINDOW_CLASS;
- return RegisterClass(&wc);
- }
-
-
-
-
-
- BOOL InitInstance(HANDLE hInstance, HANDLE hPrevInstance, int nCmdShow){
- //Create the two windows, the main and DDE windows.
- //Show the main window.
- //Create the four necessary atoms.
- //Send a message to all 'overlapped' windows telling them we are here.
- //In the example code, we get the count of ourselves by asking any previous
- // instance what its count was. This is useful if we want to play two or
- // more of them at the same time. Giving ourselves a count makes it easier
- // to identify which player is which.
-
- //example C code
- HDC hDC;
- ghMyInstance = hInstance;
- hwndMain = CreateWindow(SZ_CLIENT_WINDOW_CLASS,SZ_CLIENT_WINDOW_NAME,
- WS_OVERLAPPEDWINDOW,100,100,100,100, //Height
- NULL,NULL,hInstance,NULL);
- if(!hwndMain)
- return FALSE;
- ShowWindow(hwndMain, nCmdShow);
- hwndDDE = CreateWindow(SZ_CLIENT_DDE_WINDOW_CLASS,
- SZ_CLIENT_DDE_WINDOW_NAME,
- WS_OVERLAPPED,0,0,1,1,NULL,NULL,hInstance, NULL);
- if(!hwndDDE){
- DestroyWindow(hwndMain);
- return FALSE;
- }
- if(hPrevInstance)
- gnMyInstanceCount =SendMessage(hPrevInstance,WM_WHATS_YOUR_INSTANCE_COUNT, 0, 0L)+1;
- if(gnMyInstanceCount>0) //only put this count if there is more than a single instance of me.
- wsprintf(ATOM_MY_NAME+N_ATOM_MY_NAME, "%d",gnMyInstanceCount+1); //'+1' converts to 1-based counting
- atomPlayerNotReady =GlobalAddAtom(ATOM_TOPIC_YOUR_CONTACT);
- atomPlayerReady =GlobalAddAtom(ATOM_TOPIC_PLAYER_READY);
- atomMyName =GlobalAddAtom(ATOM_MY_NAME);
- atomNewHeartsPlayer=GlobalAddAtom(ATOM_TOPIC_NEW_HEARTS_PLAYER);
- //We send out a message to everyone (especially any Hearts games playing) that we are here.
- SendMessage(SEND_TO_ALL_WINDOWS, HM_INITIATE_CONVERSATION, hwndDDE, MAKELONG(atomMyName,atomNewHeartsPlayer));
- return TRUE;
- }
-
-
-
-
-
-
- void UnInitApplication(){
- //This is called when the user quits the external player application.
- //If we are still in a game with the dealer, then 'cause it to stop'
- //destroy the DDE window. We don't destroy the main window here becuase
- // presumably the destruction of it by other means is what caused this
- // function to be called.
- //Delete the four all-important atoms.
-
- //example C code.
- if(bAlreadyConversing)
- CauseConversationTermination(FALSE);
- if(hwndDDE)
- DestroyWindow(hwndDDE);
- GlobalDeleteAtom(atomPlayerNotReady);
- GlobalDeleteAtom(atomPlayerReady);
- GlobalDeleteAtom(atomMyName);
- GlobalDeleteAtom(atomNewHeartsPlayer);
- }
-
-
-
-
- long FAR PASCAL MainWndProc(HWND hwnd, unsigned message, WORD wParam, LONG lParam){
- //This is our main window procedure.
- //We don't do anything unusual here except respond to the WM_WHATS_YOUR_INSTANCE_COUNT
- // message and call the 'CauseConversationTermination()' function in the
- // WM_DESTROY message.
-
- //example C code
- PAINTSTRUCT paintstructTemp;
- HDC hdcTemp;
- FARPROC procAboutBox;
- switch (message){
- case WM_PAINT:
- hdcTemp = BeginPaint(hwnd, &paintstructTemp);
- //Put whatever you want here.
- EndPaint(hwnd, &paintstructTemp);
- break;
- case WM_DESTROY:
- bTerminating = TRUE;
- CauseConversationTermination(FALSE); //Save This Function Call.
- PostQuitMessage(0);
- break;
- case WM_COMMAND:
- switch (wParam){
- case ID_ABOUT:
- procAboutBox = MakeProcInstance((FARPROC)AboutDlgProc, ghMyInstance);
- if(procAboutBox){
- DialogBox(ghMyInstance, SZ_ABOUT_DIALOG_NAME, hwndMain, procAboutBox);
- FreeProcInstance(procAboutBox);
- }
- break;
- case ID_QUIT:
- PostQuitMessage(0);
- break;
- case ID_END_PLAY:
- CauseConversationTermination(TRUE);
- break;
- }
- break;
- case WM_WHATS_YOUR_INSTANCE_COUNT:
- return gnMyInstanceCount;
- default:
- return DefWindowProc(hwnd, message, wParam, lParam);
- }
- return 1L;
- }
-
-
-
-
-
- BOOL FAR PASCAL AboutDlgProc(HWND hDlg, unsigned message, WORD wParam, LONG lParam){
- //This is the 'About' dialog procedure. You may want to make an 'About box' that
- // gives some information about the external player. Then give it an OK button
-
- //example C code
- switch (message) {
- case WM_INITDIALOG:
- return TRUE;
- case WM_COMMAND:
- if(wParam == IDOK || wParam == IDCANCEL) {
- EndDialog(hDlg, TRUE);
- return TRUE;
- }
- break;
- }
- return FALSE;
- }
-
-
-
-
- long FAR PASCAL DDEWndProc(HWND hwnd, unsigned message, WORD wParam, LONG lParam){
- //This is the DDE window's procedure. It must respond to the three important
- // DDE messages from the dealer. It doesn't need to paint becuase it is invisible.
- // Each of the three messages from the dealer have an associated function that
- // we call. See the example below.
-
- //example C code
- switch (message){
- case HM_INITIATE_CONVERSATION: //(same as WM_DDE_INITIATE)
- return ProcessInitiate(hwnd, message, wParam, lParam);
- case HM_TERMINATE_CONVERSATION: //(same as WM_DDE_TERMINATE)
- return ProcessTermination(hwnd, message, wParam, lParam);
- case HM_DLR_PROCESS_THIS_MESSAGE: //(same as WM_DDE_DATA)
- return ProcessDealerMessage(hwnd, message, wParam, lParam);
- default:
- return DefWindowProc(hwnd, message, wParam, lParam);
- }
- }
-
-
-
-
- short ProcessInitiate(HWND hwnd, unsigned message, WORD wParam, LONG lParam){
- //This is called from the DDE window procedure. There are two types of
- // initiate messages, one for the NEW_GAME, and one for a NEW_CONTACT. See
- // the documentation for the description of the initiation procedure.
- //Essentially, we must see if it is a new game initiation. If so then
- // ignore it if we are already playing. Also, ignore the message if it is
- // coming from ourselves. The HWND sending is in the wParam of the message.
- //If it is a NEW_CONTACT message, then if we are not already playing with
- // another dealer, set the contact HWND (in wParam) to be our contact.
- //Send acknowledgment messages back if OK in both cases.
-
- //example C code
- char szAtomText[256];
- WORD wApplication=LOWORD(lParam);
- WORD wTopic =HIWORD(lParam);
- if(wParam == hwndDDE) //Return if the sender is myself.
- return NOT_OK;
- GlobalGetAtomName(wTopic, szAtomText, 255);
- if(!lstrcmp(szAtomText, ATOM_TOPIC_NEW_HEARTS_GAME)){
- if(!bAlreadyConversing){
- //Send message back to the sender that we can converse with him.
- SendMessage((HWND)wParam, HM_ACKNOWLEDGEMENT, hwndDDE, MAKELONG(atomMyName, wTopic));
- return OK;
- }
- //otherwise ignore the initiation, we are busy already with someone else
- }
- else if(!lstrcmp(szAtomText,ATOM_TOPIC_YOUR_CONTACT)){
- //This means that we are being called into the conversation for good.
- if(!bAlreadyConversing){
- bAlreadyConversing =TRUE;
- hwndMyContact=(HWND)wParam;
- SendMessage((HWND)wParam, HM_ACKNOWLEDGEMENT, hwndDDE, MAKELONG(atomMyName, atomPlayerReady));
- return OK;
- }
- else{
- return NOT_OK;
- }
- }
- //Otherwise we cannot be a client for the message sender.
- return NOT_OK;
- }
-
-
-
-
-
-
- short ProcessTermination(HWND hwnd, unsigned message, WORD wParam, LONG lParam){
- //We are being told to terminate.
- //This means our conversation is over and we can prepare to make a conversation
- // with someone else if they ask.
- //All we have to do is set everything to zero. Since the Contact told us to close, we
- // don't have to send it anything back.
-
- //example C code
- hwndMyContact =
- hDDEInformation =
- bTerminating =
- bAlreadyConversing =0;
- return OK;
- }
-
-
-
-
- void CauseConversationTermination(short bMakeSelfAvailableAgain){
- //Tell the contact that we are OUTTA HERE.
- //Don't tell anyone unless we are actually in a conversation with them.
-
- //example C code
- if(bAlreadyConversing){
- PostMessage(hwndMyContact, HM_TERMINATE_CONVERSATION, hwndDDE, 0L);
- }
- hwndMyContact =0; //Not necessary if we are closing our app, of course.
- bTerminating =0;
- bAlreadyConversing =0;
- hDDEInformation =0;
- if(bMakeSelfAvailableAgain)
- SendMessage(SEND_TO_ALL_WINDOWS, HM_INITIATE_CONVERSATION, hwndDDE, MAKELONG(atomMyName,atomNewHeartsPlayer));
- }
-
-
-
-
- short ProcessDealerMessage(HWND hwnd, unsigned message, WORD wParam, LONG lParam){
- //loword is hData, hiword is atomItem. Same as WM_DDE_DATA.
- //This function is the main card playing function of importance.
- //There should be a function (or equivalent) for each message from the dealer
- // that you want to respond to. You MUST respond to the 5 required messages.
- // You don't have to respond to the other 'notify' messages.
- //You want to first make sure the message sender is your contact.
- //Then lock the global memory share so you can read the message.
- //Then test if it is a notify message. If so then do what you want with it.
- //If instead it is a 'your turn' message, then you must call functions to
- // come up with your answer and put your answer into the appropriate place
- // in the global share and then return to this function and post your
- // answer message to the dealer.
- //Below the example code shows everything except the filling in of the
- // global share with the answer.
-
- //example C code.
- MessageStruct far* messageStructFromDealer;
- short i;
- char szAtomText[256];
- WORD hData =LOWORD(lParam);
- WORD wTopic=HIWORD(lParam);
-
- if(wParam != hwndMyContact)
- return NOT_OK;
- if(!hDDEInformation)
- hDDEInformation = LOWORD(lParam);
- if(!hDDEInformation)
- return NOT_OK;
- messageStructFromDealer = (MessageStruct far*) GlobalLock(hDDEInformation);
- GlobalGetAtomName(wTopic, szAtomText, 255);
- if(!lstrcmp(szAtomText, ATOM_TOPIC_NOTIFY)){
-
- //Call a function(s) here to process the notification.
-
- }
- else if(!lstrcmp(szAtomText, ATOM_TOPIC_YOUR_TURN)){
- //Call a function here depending on exactly which message was sent.
- //The global storage should be filled in with the answer.
-
- //Call the all important functions here.
-
- if(nearMessageStruct.nQueryMessage == P_DO_PASS ||
- nearMessageStruct.nQueryMessage == P_LEAD_CARD ||
- nearMessageStruct.nQueryMessage == P_PLAY_CARD ||
- nearMessageStruct.nQueryMessage == P_REGISTER_PLAYER)
- {
- messageStructFromDealer->nReturnMessage = messageStructFromDealer->nQueryMessage;
- //In this case we must send our answer back to the dealer.
- //For this PostMessage, loword is hData and hiword is atomItem. Same as sending WM_DDE_POKE.
- //Normally, in DDE, we put the anwser (hData) in LOWORD(lParam) and topic in HIWORD(lParam)
- // Since these values are already known by both parties, this is not necessary.
- PostMessage(hwndMyContact, HM_PLR_HERE_IS_MY_ANSWER, hwndDDE, 0L);
- } //same as WM_DDE_POKE
- }
- GlobalUnlock(hDDEInformation);
- return OK;
- }
-
-
-
-
-
- char* ConvertCardToText(cardtype* cardToConvert, char* szResultText){
- //This function is not necessary but may be useful for debugging. It
- // converts a 'cardtype' (see external.txt/doc) to a text string for
- // display (possibly in the main window) to show at run-time. Since
- // DDE is a real-time system, you cannot sit in a debugger while the
- // messages are trying to be passed around and time-outs are happening.
-
- //example C code
- //The return is a pointer to the 'szResultText'
- //The result text is an array of characters (min of 4) to be filled in with the text.
- //The card text is in the format of: 10H, JD, QS, 4C, 9H, AD, etc.
- char szSuitChars[4][2] = {"S","D","C","H"};
- char szNumberChars[13][3] = {"2","3","4","5","6","7","8","9","10","J","Q","K","A"};
-
- lstrcpy(szResultText,szNumberChars[cardToConvert->kind.number-2]);
- lstrcat(szResultText,szSuitChars[cardToConvert->kind.suit-1]);
- return szResultText;
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-