home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Supergames for Windows 2
/
WinGames2.iso
/
d-i
/
hrts
/
codedemo.txt
next >
Wrap
Text File
|
1993-03-22
|
16KB
|
447 lines
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;
}