|
|
#include <windows.h>
#include <port1632.h>
#include <ddeml.h>
#include "wrapper.h"
#include "ddestrs.h"
VOID PaintTest(HWND,PAINTSTRUCT *); HWND CreateButton(HWND); HANDLE hExtraMem=0; LPSTR pszNetName=NULL; HANDLE hmemNet=NULL; BOOL fnoClose=TRUE;
LONG FAR PASCAL MainWndProc( HWND hwnd, UINT message, WPARAM wParam, LONG lParam) { PAINTSTRUCT ps; HBRUSH hBrush; MSG msg; LONG l; LONG lflags; HWND hbutton;
#ifdef WIN32
HANDLE hmem; LPCRITICAL_SECTION lpcs; #endif
switch (message) { case WM_COMMAND:
#ifdef WIN32
if(LOWORD(wParam)==0 && HIWORD(wParam)==BN_CLICKED) SendMessage(hwnd,WM_CLOSE,0,0L);
if(LOWORD(wParam)==1 && HIWORD(wParam)==BN_CLICKED) {
hbutton=GetDlgItem(hwnd,1); lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
if(lflags&FLAG_PAUSE) { SetFlag(hwnd,FLAG_PAUSE,OFF); SetWindowText(hbutton,"Pause"); CheckDlgButton(hwnd,1,0); SetFocus(hwnd); UpdateWindow(hbutton); TimerFunc(hwndMain,WM_TIMER,1,0); } else { SetFlag(hwnd,FLAG_PAUSE,ON); SetWindowText(hbutton,"Start"); CheckDlgButton(hwnd,1,0); SetFocus(hwnd); InvalidateRect(hbutton,NULL,FALSE); UpdateWindow(hbutton); } }
#else
if(wParam==1 && HIWORD(lParam)==BN_CLICKED) {
hbutton=GetDlgItem(hwnd,1); lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
if(lflags&FLAG_PAUSE) { SetFlag(hwnd,FLAG_PAUSE,OFF); SetWindowText(GetDlgItem(hwnd,1),"Pause"); TimerFunc(hwndMain,WM_TIMER,1,0); CheckDlgButton(hwnd,1,0); SetFocus(hwnd); InvalidateRect(hbutton,NULL,FALSE); UpdateWindow(hbutton); } else { SetFlag(hwnd,FLAG_PAUSE,ON); SetWindowText(GetDlgItem(hwnd,1),"Start"); CheckDlgButton(hwnd,1,0); SetFocus(hwnd); InvalidateRect(hbutton,NULL,FALSE); UpdateWindow(hbutton); } }
if(wParam==0 && HIWORD(lParam)==BN_CLICKED) SendMessage(hwnd,WM_CLOSE,0,0L); #endif
break;
case WM_ENDSESSION: case WM_CLOSE:
// Shutdown timers
if (fClient) { CloseClient(); } else { KillTimer(hwndMain,(UINT)GetThreadLong(GETCURRENTTHREADID(),OFFSET_SERVERTIMER)); }
l=GetWindowLong(hwndMain,OFFSET_FLAGS);
#ifdef WIN32
if(l&FLAG_MULTTHREAD) {
// Start conversations disconnecting.
ThreadDisconnect();
// Start child thread exit
ThreadShutdown();
} #endif
// This will stop us using hwndDisplay and hwndMain
// after there destroyed.
SetFlag(hwnd,FLAG_STOP,ON);
UninitializeDDE();
// Free memory allocated for Net address.
if(l&FLAG_NET) { if(hmemNet) FreeMem(hmemNet); hmemNet=0; }
// Clean out message queue (main thread)
while (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { if(msg.message!=WM_TIMER) { TranslateMessage (&msg); DispatchMessage (&msg); } }
#ifdef WIN32
// Can Not rely on the critical section for our flag update
// after this point.
SetFlag(hwnd,FLAG_SYNCPAINT,OFF);
// OK, Shutdown is now under way. We need to wait until
// all child threads exit before removing our critical section
// and completing shutdown for main thread.
if(l&FLAG_MULTTHREAD) {
ThreadWait(hwndMain);
hmem=(HANDLE)GetWindowLong(hwndMain,OFFSET_CRITICALSECT); SetWindowLong(hwndMain,OFFSET_CRITICALSECT,0L);
if(hmem) { lpcs=GlobalLock(hmem); if(lpcs) DeleteCriticalSection(lpcs); GlobalUnlock(hmem); GlobalFree(hmem); } } #endif
FreeThreadInfo(GETCURRENTTHREADID());
// Say goodbye to main window. Child threads must be finished
// before making this call.
DestroyWindow(hwnd); break;
case WM_DESTROY: PostQuitMessage(0); break;
case WM_ERASEBKGND: return 1;
case WM_PAINT: BeginPaint(hwnd, &ps); hBrush=CreateSolidBrush(WHITE); FillRect(ps.hdc,&ps.rcPaint,hBrush); DeleteObject(hBrush); PaintTest(hwnd,&ps); EndPaint(hwnd, &ps); break;
default: return(DefWindowProc(hwnd, message, wParam, lParam)); } return(0L); }
#ifdef WIN32
BOOL ThreadShutdown( VOID ) { INT i,nCount,nId,nOffset;
nCount=GetWindowLong(hwndMain,OFFSET_THRDCOUNT);
nOffset=OFFSET_THRD2ID;
for(i=0;i<nCount-1;i++) { nId=GetWindowLong(hwndMain,nOffset);
if(!PostThreadMessage(nId,EXIT_THREAD,0,0L)) { Sleep(200); if(!PostThreadMessage(nId,EXIT_THREAD,0,0L)) { DOut(hwndMain,"DdeStrs.Exe -- ERR:PostThreadMessage failed 4 EXIT_THREAD\r\n",NULL,0); } }
nOffset=nOffset+4; }
return TRUE;
}
BOOL ThreadDisconnect( VOID ) { INT i,nCount,nId,nOffset;
nCount=GetWindowLong(hwndMain,OFFSET_THRDCOUNT);
nOffset=OFFSET_THRD2ID;
for(i=0;i<nCount-1;i++) { nId=GetWindowLong(hwndMain,nOffset);
if(!PostThreadMessage(nId,START_DISCONNECT,0,0L)) { Sleep(200); if(!PostThreadMessage(nId,START_DISCONNECT,0,0L)) { DOut(hwndMain,"DdeStrs.Exe -- ERR:PostThreadMessage failed 4 START_DISCONNECT\r\n",NULL,0); } }
nOffset=nOffset+4; }
return TRUE;
}
#endif
VOID PaintTest( HWND hwnd, PAINTSTRUCT *pps) { RECT rc,r; static CHAR szT[40]; LONG cClienthConvs,cServerhConvs;
GetClientRect(hwnd, &rc); OffsetRect(&rc, 0, cyText); rc.bottom = rc.top + cyText;
#ifdef WIN16
// Test Mode
if(IntersectRect(&r,&(pps->rcPaint),&rc)) { if(fServer && fClient) { DrawText(pps->hdc, "Client/Server (w16)", -1, &rc, DT_LEFT); } else { if(fServer) { DrawText(pps->hdc, "Server (w16)", -1, &rc, DT_LEFT); } else { DrawText(pps->hdc, "Client (w16)", -1, &rc, DT_LEFT); } } }
OffsetRect(&rc, 0, 2*cyText); // Skip a line before next item
#else
// Test Mode
if(IntersectRect(&r,&(pps->rcPaint),&rc)) { if(fServer && fClient) { DrawText(pps->hdc, "Client/Server (w32)", -1, &rc, DT_LEFT); } else { if(fServer) { DrawText(pps->hdc, "Server (w32)", -1, &rc, DT_LEFT); } else { DrawText(pps->hdc, "Client (w32)", -1, &rc, DT_LEFT); } } }
OffsetRect(&rc, 0, 2*cyText); // Skip a line before next item
#endif
// Stress Percentage
if(IntersectRect(&r,&(pps->rcPaint),&rc)) { DrawText(pps->hdc,"Stress %", -1, &rc, DT_LEFT);
#ifdef WIN32
wsprintf(szT, "%d", GetWindowLong(hwndMain,OFFSET_STRESS)); #else
wsprintf(szT, "%ld", GetWindowLong(hwndMain,OFFSET_STRESS)); #endif
CopyRect(&r,&rc); r.left=cxText*LONGEST_LINE; DrawText(pps->hdc, szT, -1, &r, DT_LEFT);
}
OffsetRect(&rc, 0, cyText);
// Run Time
if(IntersectRect(&r,&(pps->rcPaint),&rc)) { DrawText(pps->hdc,"Run Time", -1, &rc, DT_LEFT);
#ifdef WIN32
wsprintf(szT, "%d", GetWindowLong(hwndMain,OFFSET_RUNTIME)); #else
wsprintf(szT, "%ld", GetWindowLong(hwndMain,OFFSET_RUNTIME)); #endif
CopyRect(&r,&rc); r.left=cxText*LONGEST_LINE; DrawText(pps->hdc, szT, -1, &r, DT_LEFT); }
OffsetRect(&rc, 0, cyText);
// Time Elapsed
if(IntersectRect(&r,&(pps->rcPaint),&rc)) { DrawText(pps->hdc, "Time Elapsed", -1, &rc, DT_LEFT);
#ifdef WIN32
wsprintf(szT, "%d", GetWindowLong(hwndMain,OFFSET_TIME_ELAPSED)); #else
wsprintf(szT, "%ld", GetWindowLong(hwndMain,OFFSET_TIME_ELAPSED)); #endif
CopyRect(&r,&rc); r.left=cxText*LONGEST_LINE; DrawText(pps->hdc, szT, -1, &r, DT_LEFT);
}
OffsetRect(&rc, 0, cyText);
// *** Count Client Connections ****
if(IntersectRect(&r,&(pps->rcPaint),&rc)) {
cClienthConvs=GetCurrentCount(hwnd,OFFSET_CCLIENTCONVS); DrawText(pps->hdc,"Client Connect", -1, &rc, DT_LEFT);
#ifdef WIN32
wsprintf(szT, "%d", cClienthConvs); #else
wsprintf(szT, "%ld", cClienthConvs); #endif
CopyRect(&r,&rc); r.left=cxText*LONGEST_LINE; DrawText(pps->hdc, szT, -1, &r, DT_LEFT);
} // if IntersectRect
OffsetRect(&rc, 0, cyText);
// *** Server Connections ***
if(IntersectRect(&r,&(pps->rcPaint),&rc)) { DrawText(pps->hdc,"Server Connect", -1, &rc, DT_LEFT);
cServerhConvs=GetCurrentCount(hwnd,OFFSET_CSERVERCONVS);
#ifdef WIN32
wsprintf(szT, "%d", cServerhConvs ); #else
wsprintf(szT, "%ld", cServerhConvs ); #endif
CopyRect(&r,&rc); r.left=cxText*LONGEST_LINE; DrawText(pps->hdc, szT, -1, &r, DT_LEFT); }
OffsetRect(&rc, 0, cyText);
// Client Count (for checking balence between apps)
if(IntersectRect(&r,&(pps->rcPaint),&rc)) { DrawText(pps->hdc,"Client Count", -1, &rc, DT_LEFT);
#ifdef WIN32
wsprintf(szT, "%d",GetWindowLong(hwnd,OFFSET_CLIENT)); #else
wsprintf(szT, "%ld",GetWindowLong(hwnd,OFFSET_CLIENT)); #endif
CopyRect(&r,&rc); r.left=cxText*LONGEST_LINE; DrawText(pps->hdc, szT, -1, &r, DT_LEFT); }
OffsetRect(&rc, 0, cyText);
// Server Count (for checking balence between apps)
if(IntersectRect(&r,&(pps->rcPaint),&rc)) { DrawText(pps->hdc,"Server Count", -1, &rc, DT_LEFT);
#ifdef WIN32
wsprintf(szT, "%d", GetWindowLong(hwnd,OFFSET_SERVER)); #else
wsprintf(szT, "%ld", GetWindowLong(hwnd,OFFSET_SERVER)); #endif
CopyRect(&r,&rc); r.left=cxText*LONGEST_LINE; DrawText(pps->hdc, szT, -1, &r, DT_LEFT); }
OffsetRect(&rc, 0, cyText);
// Delay
if(IntersectRect(&r,&(pps->rcPaint),&rc)) { DrawText(pps->hdc,"Delay", -1, &rc, DT_LEFT);
#ifdef WIN32
wsprintf(szT, "%d", GetWindowLong(hwndMain,OFFSET_DELAY)); #else
wsprintf(szT, "%ld", GetWindowLong(hwndMain,OFFSET_DELAY)); #endif
CopyRect(&r,&rc); r.left=cxText*LONGEST_LINE; DrawText(pps->hdc, szT, -1, &r, DT_LEFT); }
OffsetRect(&rc, 0, cyText);
}
int PASCAL WinMain( HINSTANCE hInstance, HINSTANCE hPrev, LPSTR lpszCmdLine, int cmdShow) { MSG msg; HDC hdc; WNDCLASS wc; TEXTMETRIC tm; INT x,y,cx,cy; #ifdef WIN32
LONG lflags; #endif
DWORD idI; HWND hwndDisplay; INT nThrd;
CHAR sz[250]; CHAR sz2[250]; LPSTR lpszOut=&sz[0]; LPSTR lpsz=&sz2[0];
#ifdef WIN32
DWORD dwer; #endif
hInst=hInstance;
if(!SetMessageQueue(100)) { MessageBox(NULL,"SetMessageQueue failed. Test aborting.","Error:DdeStrs",MB_ICONSTOP|MB_OK); return FALSE; }
wc.style = 0; wc.lpfnWndProc = MainWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = WND; wc.hInstance = hInst; wc.hIcon = LoadIcon(hInst,MAKEINTRESOURCE(IDR_ICON)); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE+1); wc.lpszMenuName = NULL; wc.lpszClassName = szClass;
if(!hPrev) { if (!RegisterClass(&wc) ) { #if 0
// This was removed because the system was running out of resources (ALPHA only)
// which caused this occasionaly to fail. Rather than continue to bring
// the message box up (for a known stress situation) the test will abort
// and try again.
MessageBox(NULL,"RegisterClass failed. Test aborting.","Error:DdeStrs",MB_ICONSTOP|MB_OK); #endif
return FALSE; } }
hwndMain = CreateWindowEx( WS_EX_DLGMODALFRAME, szClass, szClass, WS_OVERLAPPED|WS_MINIMIZEBOX|WS_CLIPCHILDREN, 0, 0, 0, 0, NULL, NULL, hInst, NULL);
#ifdef WIN32
dwer=GetLastError(); // We want LastError Associated with CW call
#endif
if (!hwndMain) { MessageBox(NULL,"Could Not Create Main Window. Test aborting.","Error:DdeStrs",MB_ICONSTOP|MB_OK); UnregisterClass(szClass,hInst); return FALSE; }
#ifdef WIN32
if (!IsWindow(hwndMain)) { TStrCpy(lpsz,"CreateWindowEx failed for Main Window but did not return NULL! Test aborting. HWND=%u, LastEr=%u"); wsprintf(lpszOut,lpsz,hwndMain,dwer); MessageBox(NULL,lpszOut,"Error:DdeStrs",MB_ICONSTOP|MB_OK); UnregisterClass(szClass,hInst); return FALSE; } #else
if (!IsWindow(hwndMain)) { TStrCpy(lpsz,"CreateWindowEx failed for Main Window but did not return NULL! Test aborting. HWND=%u"); wsprintf(lpszOut,lpsz,hwndMain); MessageBox(NULL,lpszOut,"Error:DdeStrs",MB_ICONSTOP|MB_OK); UnregisterClass(szClass,hInst); return FALSE; } #endif
if (!ParseCommandLine(hwndMain,lpszCmdLine)) { DestroyWindow(hwndMain); UnregisterClass(szClass,hInst); return FALSE; }
// Note: This needs to be there even for win 16 execution. The
// name may be confusing. for win 16 there is obviously only
// a single thread. This is handled by the call.
nThrd=GetWindowLong(hwndMain,OFFSET_THRDCOUNT);
// Currently ddestrs has a hardcoded thread limit (at THREADLIMIT). So
// this should NEVER be less than one or greater than THREADLIMIT.
#ifdef WIN32
if(nThrd<1 || nThrd>THREADLIMIT) { BOOL fVal;
dwer=GetLastError();
if(IsWindow(hwndMain)) fVal=TRUE; else fVal=FALSE;
TStrCpy(lpsz,"GetWindowLong failed querying thread count!. Test aborting... INFO:hwnd=%u, LastEr=%u, Is hwnd valid=%u, nThrd=%u");
wsprintf(lpszOut,lpsz,hwndMain,dwer,fVal,nThrd); MessageBox(NULL,lpszOut,"Error:DdeStrs",MB_ICONSTOP|MB_OK);
DestroyWindow(hwndMain); UnregisterClass(szClass,hInst); return FALSE; } #endif
if(!CreateThreadExtraMem( EXTRA_THREAD_MEM,nThrd)) { MessageBox(NULL,"Could Not Alocate Get/SetThreadLong(). Test aborting.","Error:DdeStrs",MB_ICONSTOP|MB_OK); DestroyWindow(hwndMain); UnregisterClass(szClass,hInst); return FALSE; }
// We always need the thread id for the main thread. (for use
// in Get/SetThreadLong(). Other thread id's are initialized in
// ThreadInit().
SetWindowLong(hwndMain,OFFSET_THRDMID,GETCURRENTTHREADID());
if(!InitThreadInfo(GETCURRENTTHREADID())) { MessageBox(NULL,"Could Not Alocate Thread Local Storage. Test aborting.","Error:DdeStrs",MB_ICONSTOP|MB_OK); DestroyWindow(hwndMain); UnregisterClass(szClass,hInst); return FALSE; }
hdc = GetDC(hwndMain); GetTextMetrics(hdc, &tm);
cyText = tm.tmHeight; cxText = tm.tmAveCharWidth;
// We need to add in extra area for each additional DisplayWindow
// used for each addtional thread.
nThrd=(INT)GetWindowLong(hwndMain,OFFSET_THRDCOUNT); cy = tm.tmHeight*NUM_ROWS+((nThrd-1)*(3*cyText)); cx = tm.tmAveCharWidth*NUM_COLUMNS;
ReleaseDC(hwndMain,hdc);
// Old ways of positioning.
// y=DIV((GetSystemMetrics(SM_CYSCREEN)-cy),3)*2;
// y=(DIV(GetSystemMetrics(SM_CYSCREEN),10)*3);
// Position as if 5 threads with bottom of window at bottom of
// screen.
y=GetSystemMetrics(SM_CYSCREEN)-(tm.tmHeight*NUM_ROWS+(12*cyText));
x=GetSystemMetrics(SM_CXSCREEN);
if(fServer && fClient) { x=x-(cx*3); // Init for standard values.
} else { if(fServer) { x=x-cx; } else { x=x-(cx*2); } }
SetWindowPos( hwndMain, NULL, x, y, cx, cy, SWP_NOZORDER|SWP_NOACTIVATE );
ShowWindow (hwndMain, cmdShow);
CreateButton(hwndMain);
UpdateWindow (hwndMain);
#ifdef WIN32
SetFlag(hwndMain,FLAG_SYNCPAINT,ON);
lflags=GetWindowLong(hwndMain,OFFSET_FLAGS); if(lflags&FLAG_MULTTHREAD) { // CreateThreads
if(!ThreadInit(hwndMain)) { DestroyWindow(hwndMain); UnregisterClass(szClass,hInst); return FALSE; } } #endif
hwndDisplay=CreateDisplayWindow(hwndMain,1);
if(!hwndDisplay) { MessageBox(NULL,"Could Not Create Test Display Window. Test aborting.","Error:DdeStrs",MB_ICONSTOP|MB_OK); DestroyWindow(hwndMain); UnregisterClass(szClass,hInst); return FALSE; } else { SetThreadLong(GETCURRENTTHREADID(),OFFSET_HWNDDISPLAY,(LONG)hwndDisplay); }
if (!InitializeDDE((PFNCALLBACK)CustomCallback, &idI, ServiceInfoTable, fServer ? APPCLASS_STANDARD : APPCLASS_STANDARD | APPCMD_CLIENTONLY, hInst)) { DDEMLERROR("DdeStrs.Exe -- Error Dde inititialization failed\r\n"); DestroyWindow(hwndMain); UnregisterClass(szClass,hInst); return(FALSE); }
SetThreadLong(GETCURRENTTHREADID(),OFFSET_IDINST,idI);
if (fClient) { InitClient(); } else {
// Only needed if we are not a client. In case of
// client/server only call InitClient() which start
// a timer which can be used for time checks.
SetTimer( hwndMain, (UINT)GetThreadLong(GETCURRENTTHREADID(),OFFSET_SERVERTIMER), PNT_INTERVAL, TimerFunc); }
while (GetMessage(&msg, NULL, 0, 0)) {
if(IsTimeExpired(hwndMain)) {
// We only want to send a single WM_CLOSE
if(fnoClose) { fnoClose=FALSE; PostMessage(hwndMain,WM_CLOSE,0,0L); } }
TranslateMessage (&msg); DispatchMessage (&msg); }
FreeThreadExtraMem();
return(TRUE); }
#ifdef WIN32
/************************** Private Function ****************************\
* * ThreadInit * * Create secondary test threads * \**************************************************************************/
BOOL ThreadInit( HWND hwnd ) { LONG l,ll; PLONG lpIDThread=≪ HANDLE hthrd; INT nOffset,nCount,i,n; HANDLE hmem; HANDLE *lph; char sz[20]; LPSTR lpsz=&sz[0];
nCount=GetWindowLong(hwnd,OFFSET_THRDCOUNT); nOffset=OFFSET_THRD2;
for(i=1;i<nCount;i++) {
hmem=GetMemHandle(((sizeof(HANDLE)*2)+sizeof(INT))); lph=(HANDLE *)GlobalLock(hmem);
*lph=hwnd; *(lph+1)=hmem; *(lph+2)=(HANDLE)(i+1);
hthrd=CreateThread(NULL,0,SecondaryThreadMain,(LPVOID)lph,0,lpIDThread);
if (!hthrd) {
DOut(hwnd,"DdeStrs.Exe -- ERR:Could not Create Thread #%u\r\n",0,i+1);
GlobalUnlock(hmem); FreeMemHandle(hmem);
// it's important we turn this flag off since no threads
// where successfully created (cleanup code)
SetFlag(hwnd,FLAG_MULTTHREAD,OFF);
if (i==1) return FALSE; else {
// Cleanup threads before we abort.
for(n=1;n<i;n++) { nOffset=OFFSET_THRD2; TerminateThread((HANDLE)GetWindowLong(hwnd,nOffset),0); SetWindowLong(hwnd,nOffset,0L); nOffset=nOffset+4; } // for
return FALSE;
} // else
} // if
SetWindowLong(hwnd,nOffset+ID_OFFSET,(LONG)(*lpIDThread)); SetWindowLong(hwnd,nOffset,(LONG)hthrd);
nOffset=nOffset+4;
} // for
return TRUE;
} // ThreadInit
/*************************** Private Function ******************************\
SecondaryThreadMain
Effects: Start of execution for second thread. First order of buisness is create the test window and start queue processing.
Return value:
\***************************************************************************/
DWORD SecondaryThreadMain( DWORD dw ) { HWND hwndMain; MSG msg; HANDLE * lph; HANDLE hmem; INT nThrd; DWORD idI; HWND hwndDisplay; LONG nTc;
lph=(HANDLE *)dw;
hwndMain=(HWND)*lph; hmem =(HANDLE)*(lph+1); nThrd =(INT)*(lph+2);
GlobalUnlock(hmem); FreeMemHandle(hmem);
if(!InitThreadInfo(GETCURRENTTHREADID())) { DDEMLERROR("DdeStrs.Exe -- Error InitThreadInfo failed, Aborting thread\r\n"); nTc=GetWindowLong(hwndMain,OFFSET_THRDCOUNT); SetWindowLong(hwndMain,OFFSET_THRDCOUNT,(LONG)(nTc-1)); ExitThread(1L); }
SetThreadLong(GETCURRENTTHREADID(),OFFSET_IDINST,idI);
hwndDisplay=CreateDisplayWindow( hwndMain, IDtoTHREADNUM(GETCURRENTTHREADID()));
if(!IsWindow(hwndDisplay)) { DDEMLERROR("DdeStrs.Exe -- ERR:Could not create Display Window, Thread aborting\r\n"); nTc=GetWindowLong(hwndMain,OFFSET_THRDCOUNT); SetWindowLong(hwndMain,OFFSET_THRDCOUNT,(LONG)(nTc-1)); ExitThread(1L); return FALSE; } else { SetThreadLong(GETCURRENTTHREADID(),OFFSET_HWNDDISPLAY,hwndDisplay); }
if (!InitializeDDE((PFNCALLBACK)CustomCallback, &idI, ServiceInfoTable, fServer ? APPCLASS_STANDARD : APPCLASS_STANDARD | APPCMD_CLIENTONLY, hInst)) { DDEMLERROR("DdeStrs.Exe -- Error Dde inititialization failed for secondary thread!\r\n"); FreeThreadInfo(GETCURRENTTHREADID()); nTc=GetWindowLong(hwndMain,OFFSET_THRDCOUNT); SetWindowLong(hwndMain,OFFSET_THRDCOUNT,(LONG)(nTc-1)); ExitThread(1L); }
if (fClient) { InitClient(); } else {
// Only needed if we are not a client. In case of
// client/server only call InitClient() which start
// a timer which can be used for time checks.
SetTimer( hwndMain, (UINT)GetThreadLong(GETCURRENTTHREADID(),OFFSET_SERVERTIMER), PNT_INTERVAL, TimerFunc); }
while (GetMessage(&msg,NULL,0,0)) {
if(msg.message==START_DISCONNECT) { if (fClient) { CloseClient(); } } else { if(msg.message==EXIT_THREAD) { PostQuitMessage(1); } else { TranslateMessage(&msg); DispatchMessage(&msg); } // EXIT_THREAD
} // START_DISCONNECT
} // while
SetFlag(hwndMain,FLAG_STOP,ON);
// Shutdown timers
if (!fClient) { KillTimer(hwndMain,GetThreadLong(GETCURRENTTHREADID(),OFFSET_SERVERTIMER)); }
UninitializeDDE();
FreeThreadInfo(GETCURRENTTHREADID());
// This is to release the semaphore set before completing
// exit on main thread.
switch (nThrd) {
case 2: SetFlag(hwndMain,FLAG_THRD2,ON); break; case 3: SetFlag(hwndMain,FLAG_THRD3,ON); break; case 4: SetFlag(hwndMain,FLAG_THRD4,ON); break; case 5: SetFlag(hwndMain,FLAG_THRD5,ON); break; default: DOut(hwndMain,"DdeStrs.Exe -- ERR: Unexpected switch value in SecondaryThreadMain, value=%u\r\n",0,nThrd); break;
} // switch
ExitThread(1L);
return 1;
}
#endif
/************************** Public Function *****************************\
* * InitThrdInfo - This routine allocates memory needed for storage for * thread local variables. This routine needs to be called * for each thread. * * Note: I am relying on the fact that the call GetMemHandle() calls * GlobalAlloc() specifying the GMEM_ZEROINIT flag. These value need * to be zero starting off. \**************************************************************************/
BOOL InitThreadInfo( DWORD dwid ) { HANDLE hmem; INT nThrd;
hmem = GetMemHandle(sizeof(HCONV)*MAX_SERVER_HCONVS); SetThreadLong(dwid,OFFSET_HSERVERCONVS,(LONG)hmem);
if( hmem==NULL ) { DOut(hwndMain,"DdeStrs.Exe -- ERR: Could not allocate thread local storage(Server Conversation List)\r\n",0,0); return FALSE; }
hmem = GetMemHandle(sizeof(HANDLE)*NUM_FORMATS); SetThreadLong(dwid,OFFSET_HAPPOWNED,(LONG)hmem);
if( hmem==NULL ) { DOut(hwndMain,"DdeStrs.Exe -- ERR: Could not allocate thread local storage(AppOwned Flag List)\r\n",0,0); FreeMemHandle((HANDLE)GetThreadLong(dwid,OFFSET_HSERVERCONVS)); return FALSE; }
nThrd=IDtoTHREADNUM(dwid);
SetThreadLong(dwid,OFFSET_SERVERTIMER,nThrd*2); SetThreadLong(dwid,OFFSET_CLIENTTIMER,(nThrd*2)+1);
return TRUE;
}
#ifdef WIN32
/************************** Private Function ****************************\
* * IDtoTHREADNUM - Find out current thread. * \**************************************************************************/
INT IDtoTHREADNUM( DWORD dwid ) { INT nWndOff,nThrd,nThrdCount,n;
nWndOff=OFFSET_THRDMID; nThrdCount=GetWindowLong(hwndMain,OFFSET_THRDCOUNT); n=nThrdCount; nThrd=1;
while( n>0 ) {
if(dwid==(DWORD)GetWindowLong(hwndMain,nWndOff)) { n=-1; // Exit loop
} // if
else { nWndOff=nWndOff+4; nThrd++; n--; } } // while
if(nThrd>nThrdCount) { DDEMLERROR("DdeStrs.Exe -- ERR:Thread Count exceeded!!! in IDtoTHREADNUM()\r\n"); nThrd=nThrdCount; }
return nThrd;
}
#else
/************************** Private Function ****************************\
* * IDtoTHREADNUM - Find out current thread. * \**************************************************************************/
INT IDtoTHREADNUM( DWORD dwid ) {
return 1;
}
#endif
/************************** Public Function *****************************\
* * FreeThreadInfo - Free thread information memory. * \**************************************************************************/
BOOL FreeThreadInfo( DWORD dwid ) { HANDLE hmem;
hmem=(HANDLE)GetThreadLong(dwid,OFFSET_HSERVERCONVS); FreeMemHandle(hmem); return TRUE;
}
#ifdef WIN32
/************************** Public Function *****************************\
* * ThreadWait - This routine waits while processing messages until the * other threads signal they've completed work that must * be finished before preceeding. * \**************************************************************************/
VOID ThreadWait( HWND hwnd ) { LONG lflags; INT nCount,nWait; MSG msg;
lflags=GetWindowLong(hwnd,OFFSET_FLAGS); nCount=GetWindowLong(hwnd,OFFSET_THRDCOUNT);
nWait=nCount-1;
if(lflags&FLAG_THRD2) nWait-=1; if(lflags&FLAG_THRD3) nWait-=1; if(lflags&FLAG_THRD4) nWait-=1; if(lflags&FLAG_THRD5) nWait-=1;
while (nWait>0) {
while(PeekMessage(&msg,NULL,0,WM_USER-1,PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } // while peekmessage
nWait=nCount-1; lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
if(lflags&FLAG_THRD2) nWait-=1; if(lflags&FLAG_THRD3) nWait-=1; if(lflags&FLAG_THRD4) nWait-=1; if(lflags&FLAG_THRD5) nWait-=1;
} // while nWait
// Reset for next wait
SetFlag(hwnd,(FLAG_THRD5|FLAG_THRD4|FLAG_THRD3|FLAG_THRD2),OFF);
}
#endif // WIN32
/************************** Private Function ****************************\
* * SetCount * * This routine updates the count under semaphore protection. Not needed for * one thread, but a must for multithread execution. * \**************************************************************************/
LONG SetCount( HWND hwnd, INT nOffset, LONG l, INT ntype ) { LONG ll;
#if 0
LONG lflags; #endif
#ifdef WIN32
LPCRITICAL_SECTION lpcs; HANDLE hmem; BOOL f=FALSE; #endif
#if 0
lflags=GetWindowLong(hwnd,OFFSET_FLAGS); if(ll&FLAG_MULTTHREAD) { f=TRUE; hmem=(HANDLE)GetWindowLong(hwnd,OFFSET_CRITICALSECT);
// If we have a valid handle then enter critical section. If
// the handle is still null proceed without a critical section.
// The first calls to this routine are used to setup the
// critical section so we do expect those first calls (while
// we are still sencronized ) for the hmem to be null.
if(hmem) { lpcs=GlobalLock(hmem); EnterCriticalSection(lpcs); } }
#endif
// This second GetWindowLong call is needed in the critical
// section. The test relies very hevily on the flags and
// it's important to be accurate.
ll=GetWindowLong(hwnd,nOffset);
if(ntype==INC) l=SetWindowLong(hwnd,nOffset,ll+l); else l=SetWindowLong(hwnd,nOffset,ll-l);
#if 0
if(f) { if(hmem) { LeaveCriticalSection(lpcs); GlobalUnlock(hmem); } }
#endif
return l; }
/************************** Private Function ****************************\
* * SetFlag * * This routine sets a flag under semaphore protection. Not needed for * one thread, but a must for multithread execution. * \**************************************************************************/
LONG SetFlag( HWND hwnd, LONG l, INT ntype ) { LONG lflags;
#ifdef WIN32
BOOL fCriticalSect=TRUE; LPCRITICAL_SECTION lpcs; HANDLE hmem; BOOL f=FALSE; #endif
#ifdef WIN32
lflags=GetWindowLong(hwnd,OFFSET_FLAGS); if(lflags&FLAG_MULTTHREAD && lflags&FLAG_SYNCPAINT) { f=TRUE; hmem=(HANDLE)GetWindowLong(hwnd,OFFSET_CRITICALSECT); if(hmem) { lpcs=GlobalLock(hmem); EnterCriticalSection(lpcs); } else { fCriticalSect=FALSE; } }
#endif
// This second GetWindowLong call is needed in the critical
// section. The test relies very hevily on the flags and
// it's important to be accurate.
lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
if(ntype==ON) l=SetWindowLong(hwnd,OFFSET_FLAGS,FLAGON(lflags,l)); else l=SetWindowLong(hwnd,OFFSET_FLAGS,FLAGOFF(lflags,l));
#ifdef WIN32
if(f) { if(fCriticalSect) { LeaveCriticalSection(lpcs); GlobalUnlock(hmem); } }
#endif
return l; }
/******************************************************************\
* DIV * 05/06/91 * * Performs integer division (format x/y) where DIV(x,y) * Works for negative numbers and y==0; * \******************************************************************/
INT DIV( INT x, INT y) { INT i=0; BOOL fNgOn=FALSE;
if (!y) return 0; // if div by 0 retrun error.
if (x<0 && y>0) fNgOn=TRUE; // keep tabs for negitive numbers
if (x>0 && y<0) fNgOn=TRUE;
if (x<0) x=x*-1; if (y<0) y=y*-1;
x=x-y;
while (x>=0) { // count
x=x-y; i++; }
if (fNgOn) i=i*(-1); // should result be negative
return( i ); }
/*************************** Private Function ******************************\
* * CreateButton * \***************************************************************************/
HWND CreateButton( HWND hwnd ) { RECT r; HWND hwndB; HWND hwndP; INT iButWidth; LONG lflags;
GetClientRect(hwnd,&r);
lflags=GetWindowLong(hwnd,OFFSET_FLAGS); if(lflags&FLAG_PAUSE_BUTTON) {
iButWidth=DIV(r.right-r.left,2);
hwndP=CreateWindow("button", "Start", BS_PUSHBUTTON|WS_VISIBLE|WS_CHILD|WS_CLIPSIBLINGS, iButWidth, 0, r.right-iButWidth, cyText, hwnd, 1, GetHINSTANCE(hwnd), 0L);
if (!hwndP) { DDEMLERROR("DdeStrs.Exe -- ERR:Failed to create exit button: Continuing...\r\n"); SetFlag(hwnd,FLAG_PAUSE_BUTTON,OFF); iButWidth=r.right-r.left; }
hwndB=CreateWindow("button", "Exit", BS_PUSHBUTTON|WS_VISIBLE|WS_CHILD|WS_CLIPSIBLINGS, 0, 0, iButWidth, cyText, hwnd, 0, GetHINSTANCE(hwnd), 0L);
} else {
hwndB=CreateWindow("button", "Exit", BS_PUSHBUTTON|WS_VISIBLE|WS_CHILD|WS_CLIPSIBLINGS, 0, 0, r.right-r.left, cyText, hwnd, 0, GetHINSTANCE(hwnd), 0L); }
if (!hwndB) { DDEMLERROR("DdeStrs.Exe -- ERR:Failed to create exit button: Continuing...\r\n"); }
return hwndB; }
/***************************************************************************\
* * UpdClient * * The purpose of this routine update only the area invalidated * by the test statistics update. If an error occurs in the area * calcualation then update the whole client areaa. * \***************************************************************************/
BOOL UpdClient( HWND hwnd, INT iOffset ) { RECT r; INT iCH,iCW,nThrd;
#ifdef WIN32
DWORD dw; #endif
// This call aquires the r.right value.
GetClientRect(hwnd,&r);
// We need text information for the monitor being used. This
// was initialized in CreateFrame.
iCH=cyText; iCW=cxText;
// Do a quick check, if either of these values are NULL then
// update the whole client area. This is slower and less
// elegant but will work in the case of an error.
if((!iCH) || (!iCW)) InvalidateRect(hwnd,NULL,TRUE); else {
// Next Calculate r.top and r.bottom
switch(iOffset) {
case ALL: // Update all values.
break;
case OFFSET_STRESS: r.bottom =iCH*4; r.top =iCH*3; break;
case OFFSET_RUNTIME: r.bottom =iCH*5; r.top =iCH*4; break;
case OFFSET_TIME_ELAPSED: r.bottom =iCH*6; r.top =iCH*5; break;
case OFFSET_CLIENT_CONNECT: r.bottom =iCH*7; r.top =iCH*6; break;
case OFFSET_SERVER_CONNECT: r.bottom =iCH*8; r.top =iCH*7; break;
case OFFSET_CLIENT: nThrd=(INT)GetWindowLong(hwnd,OFFSET_THRDCOUNT); if((GetWindowLong(hwnd,OFFSET_CLIENT)%(NUM_FORMATS*nThrd))==0) { r.bottom =iCH*9; r.top =iCH*8; } else return TRUE; break;
case OFFSET_SERVER: nThrd=(INT)GetWindowLong(hwnd,OFFSET_THRDCOUNT); if((GetWindowLong(hwnd,OFFSET_SERVER)%(NUM_FORMATS*nThrd))==0) { r.bottom =iCH*10; r.top =iCH*9; } else return TRUE; break;
case OFFSET_DELAY: r.bottom =iCH*11; r.top =iCH*10; break; default: break;
} // switch
// Last we set the r.left and the update rect is complete
if(iOffset!=OFFSET_FLAGS) r.left = iCW*LONGEST_LINE;
InvalidateRect(hwnd,&r,TRUE);
} // else
#ifdef WIN16
UpdateWindow(hwnd); #else
SendMessageTimeout(hwnd,WM_PAINT,0,0L,SMTO_NORMAL,500,&dw); #endif
return TRUE;
} // UpdClient
/***************************************************************************\
* * GetCurrentCount * \***************************************************************************/
LONG GetCurrentCount( HWND hwnd, INT nOffset ) { LONG cClienthConvs =0L; INT nThrd,i; DWORD dwid;
nThrd=(INT)GetWindowLong(hwnd,OFFSET_THRDCOUNT); for(i=0;i<nThrd;i++) { dwid=(DWORD)GetWindowLong(hwnd,OFFSET_THRDMID+(i*4)); if(nOffset==OFFSET_CCLIENTCONVS) cClienthConvs=cClienthConvs+(INT)GetThreadLong(dwid,OFFSET_CCLIENTCONVS); else cClienthConvs=cClienthConvs+(INT)GetThreadLong(dwid,OFFSET_CSERVERCONVS); } // for i
return cClienthConvs;
}
/***************************************************************************\
* * UpdateCount * \***************************************************************************/
BOOL UpdateCount( HWND hwnd, INT iOffset, INT i) { LONG ll;
if(iOffset!=ALL) { ll=GetWindowLong(hwnd,iOffset);
switch(i) {
case INC: SetCount(hwnd,iOffset,1,INC); break;
case DEC: SetCount(hwnd,iOffset,1,DEC); break;
case STP: SetFlag(hwnd,FLAG_STOP,ON); break;
case PNT: // Paint only!
break;
default: DDEMLERROR("DdeStrs.Exe - UpdateCount - Unexpected value"); break;
} // switch
} // if
UpdClient(hwnd,iOffset);
return TRUE;
}
/*****************************************************************************\
| DOUT | | created: 29-Jul-91 | history: 03-Aug-91 <johnsp> created. | \*****************************************************************************/
BOOL DOut( HWND hwnd, LPSTR lpsz, LPSTR lpszi, INT i ) { char sz[MAX_TITLE_LENGTH]; LPSTR lpszOut=&sz[0]; LONG lflags;
#ifdef WIN32
LPCRITICAL_SECTION lpcs; HANDLE hmem; DWORD dwer=0L; BOOL fCriticalSect=TRUE; BOOL f=FALSE;
if(!hwnd) hwnd=hwndMain; lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
// FLAG_SYNCPAINT implies FLAG_MULTTHREAD with the addition that
// we have allocated needed resources to start using the
// critical section code.
if(lflags&FLAG_SYNCPAINT) { f=TRUE; hmem=(HANDLE)GetWindowLong(hwnd,OFFSET_CRITICALSECT); if(hmem) { lpcs=GlobalLock(hmem); EnterCriticalSection(lpcs); } else { fCriticalSect=FALSE; } }
#endif
if (lflags&FLAG_DEBUG) {
if (lpszi) wsprintf(lpszOut,lpsz,lpszi); else wsprintf(lpszOut,lpsz,i);
OutputDebugString(lpszOut);
#ifdef WIN32
dwer=GetLastError(); wsprintf(lpszOut,"DdeStrs.Exe -- ERR:Val from GetLastError()=%u\n\r",dwer); OutputDebugString(lpszOut);
#endif
} // if FLAG_DEBUG
#ifdef WIN32
// FLAG_SYNCPAINT implies FLAG_MULTTHREAD with the addition that
// we have allocated needed resources to start using the
// critical section code.
if(f) { if(fCriticalSect) { LeaveCriticalSection(lpcs); GlobalUnlock(hmem); } }
#endif
return TRUE;
}
/*****************************************************************************\
| EOUT | | created: 19-Aug-92 | history: 19-Aug-92 <johnsp> created. | \*****************************************************************************/
BOOL EOut( LPSTR lpsz ) {
DOut((HWND)NULL,lpsz,(LPSTR)NULL,0);
return TRUE; }
/*************************** Private Function ******************************\
GetMemHandle
\***************************************************************************/
HANDLE GetMemHandle( INT ic ) { HANDLE hmem;
hmem=GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT,ic);
if(hmem) { SetCount(hwndMain,OFFSET_MEM_ALLOCATED,GlobalSize(hmem),INC); } else { DOut(hwndMain,"DdeStrs.Exe -- ERR:GlobalAlloc ret=%u\n\r",0,0); }
return hmem;
}
/*************************** Private Function ******************************\
GetMem
\***************************************************************************/
LPSTR GetMem( INT ic, LPHANDLE lphmem) { LPSTR lpsz;
*lphmem=GetMemHandle(ic); lpsz=GlobalLock(*lphmem);
if(!lpsz) { DOut(hwndMain,"DdeStrs.Exe -- ERR:GlobalLock ret=%u (not locked)\n\r",0,0); FreeMemHandle(*lphmem); return NULL; }
return lpsz;
}
/*************************** Private Function ******************************\
FreeMem
\***************************************************************************/
BOOL FreeMem( HANDLE hmem ) {
if(GlobalUnlock(hmem)) { DOut(hwndMain,"DdeStrs.Exe -- ERR:GlobalUnlock ret=%u (still locked)\n\r",0,(INT)TRUE); }
FreeMemHandle(hmem);
return TRUE;
}
/*************************** Private Function ******************************\
FreeMemHandle
\***************************************************************************/
BOOL FreeMemHandle( HANDLE hmem ) { LONG ll;
ll=GlobalSize(hmem);
if(!GlobalFree(hmem)) { SetCount(hwndMain,OFFSET_MEM_ALLOCATED,ll,DEC); } else { DOut(hwndMain,"DdeStrs.Exe -- ERR:GlobalFree returned %u (not free'd)\n\r",0,(INT)hmem); return FALSE; }
return TRUE;
}
/**************************** Private *******************************\
* CreateThreadExtraMem - This routine creates extra thread memory * to be used in conjuction with the functions * Get/SetThreadLong. * \********************************************************************/
BOOL CreateThreadExtraMem( INT nExtra, INT nThrds ) {
hExtraMem=GetMemHandle(nExtra*nThrds); SetWindowLong(hwndMain,OFFSET_EXTRAMEM,nExtra);
if(hExtraMem==NULL) return FALSE; else return TRUE;
}
/**************************** Private *******************************\
* FreeThreadExtraMem - This routine frees extra thread memory * to be used in conjuction with the functions * Get/SetThreadLong. * * Note: FreeMemHandle can not be used here because it relies on * the main window still being around. At this point our * main window has already been destroied. * \********************************************************************/
BOOL FreeThreadExtraMem( void ) {
GlobalFree(hExtraMem);
return TRUE;
}
/**************************** Private *******************************\
* GetThreadLong - This routine queries the value specified by the * nOffset parameter from the threads memory areas * specified by the dwid value. * * Memory layout - thread 1: OFFSET1, OFFSET2, ..., OFFSETN * thread 2: OFFSET1, OFFSET2, ..., OFFSETN * . * . * thread n: OFFSET1, OFFSET2, ..., OFFSETN * \********************************************************************/
LONG GetThreadLong( DWORD dwid, INT nOffset ) { INT nThrd; LONG l,lExMem; LPBYTE lp; LONG FAR *lpl;
lp=GlobalLock(hExtraMem);
// Find out which thread is making the call.
nThrd=IDtoTHREADNUM(dwid);
// This is the amount of extra memory for one thread.
lExMem=GetWindowLong(hwndMain,OFFSET_EXTRAMEM);
// Value at thread and offset. See above for storage layout.
lpl=(LONG FAR *)(lp+((nThrd-1)*lExMem)+nOffset);
l=*lpl;
GlobalUnlock(hExtraMem);
return l;
}
/**************************** Private *******************************\
* SetThreadLong - This routine sets the value specified by the * nOffset parameter from the threads memory areas * specified by the dwid value. * * Memory layout - thread 1: OFFSET1, OFFSET2, ..., OFFSETN * thread 2: OFFSET1, OFFSET2, ..., OFFSETN * . * . * thread n: OFFSET1, OFFSET2, ..., OFFSETN * \********************************************************************/
LONG SetThreadLong( DWORD dwid, INT nOffset, LONG l ) { INT nThrd; LONG lPrevValue,lExMem; LPBYTE lp; LPLONG lpl;
lp=GlobalLock(hExtraMem);
// Find out which thread is making the call.
nThrd=IDtoTHREADNUM(dwid);
// This is the amount of extra memory for one thread.
lExMem=GetWindowLong(hwndMain,OFFSET_EXTRAMEM);
// Value at thread and offset. See above for storage layout.
lPrevValue=(LONG)(*(lp+((nThrd-1)*lExMem)+nOffset)); lpl=(LPLONG)(lp+((nThrd-1)*lExMem)+nOffset);
*lpl=l;
GlobalUnlock(hExtraMem);
return lPrevValue;
}
|