1857 lines
42 KiB
C
1857 lines
42 KiB
C
#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;
|
||
|
||
}
|
||
|
||
|