summaryrefslogtreecommitdiffstats
path: root/private/mvdm/wow16/ddeml/tests/ddestrs
diff options
context:
space:
mode:
Diffstat (limited to 'private/mvdm/wow16/ddeml/tests/ddestrs')
-rw-r--r--private/mvdm/wow16/ddeml/tests/ddestrs/client.c160
-rw-r--r--private/mvdm/wow16/ddeml/tests/ddestrs/cmdln.c990
-rw-r--r--private/mvdm/wow16/ddeml/tests/ddestrs/ddesorg.icobin0 -> 766 bytes
-rw-r--r--private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.c1856
-rw-r--r--private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.def17
-rw-r--r--private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.h287
-rw-r--r--private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.icobin0 -> 766 bytes
-rw-r--r--private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.rc13
-rw-r--r--private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.txt110
-rw-r--r--private/mvdm/wow16/ddeml/tests/ddestrs/globals.c106
-rw-r--r--private/mvdm/wow16/ddeml/tests/ddestrs/globals.h19
-rw-r--r--private/mvdm/wow16/ddeml/tests/ddestrs/makefile6
-rw-r--r--private/mvdm/wow16/ddeml/tests/ddestrs/makefile.dos50
-rw-r--r--private/mvdm/wow16/ddeml/tests/ddestrs/mk.cmd1
-rw-r--r--private/mvdm/wow16/ddeml/tests/ddestrs/mk4dos.cmd13
-rw-r--r--private/mvdm/wow16/ddeml/tests/ddestrs/runddes.bat12
-rw-r--r--private/mvdm/wow16/ddeml/tests/ddestrs/server.c1372
-rw-r--r--private/mvdm/wow16/ddeml/tests/ddestrs/sources24
-rw-r--r--private/mvdm/wow16/ddeml/tests/ddestrs/wrapper.c793
-rw-r--r--private/mvdm/wow16/ddeml/tests/ddestrs/wrapper.h80
20 files changed, 5909 insertions, 0 deletions
diff --git a/private/mvdm/wow16/ddeml/tests/ddestrs/client.c b/private/mvdm/wow16/ddeml/tests/ddestrs/client.c
new file mode 100644
index 000000000..726f50831
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/ddestrs/client.c
@@ -0,0 +1,160 @@
+
+#include <windows.h>
+#include <port1632.h>
+#include <ddeml.h>
+#include <string.h>
+#include "wrapper.h"
+#include "ddestrs.h"
+
+extern INT iAvailFormats[];
+extern BOOL UpdateCount(HWND,INT,INT);
+extern HANDLE hmemNet;
+
+void CALLBACK TimerFunc( HWND hwnd, UINT msg, UINT id, DWORD dwTime)
+{
+ HCONV hConv;
+ HCONVLIST hConvList;
+ LONG lflags;
+
+ switch (id%2) {
+ case 1:
+ hConv = 0;
+ hConvList=(HCONVLIST)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HCONVLIST);
+ while (hConv = DdeQueryNextServer(hConvList, hConv)) {
+
+// POKE CHANGES
+#if 0
+ idI=GetThreadLong(GETCURRENTTHREADID(),OFFSET_IDINST);
+
+ if(DdeClientTransaction("Poke Transaction",
+ strlen("Poke Transaction")+1,
+ hConv,
+ DdeCreateStringHandle(idI,"TestItem",CP_WINANSI),
+ CF_TEXT,
+ XTYP_POKE,
+ TIMEOUT_ASYNC,
+ NULL)==0){
+ DDEMLERROR("DdeStrs.Exe -- DdeClientTransaction failed:XTYP_POKE\r\n");
+ }
+#endif
+
+// END OF POKE CHANGES
+
+ // Allow 'Pause' functionality -p on command line.
+
+ lflags=GetWindowLong(hwndMain,OFFSET_FLAGS);
+ if((lflags&FLAG_PAUSE)!=FLAG_PAUSE)
+ {
+
+ if(DdeClientTransaction(szExecRefresh,
+ strlen(szExecRefresh) + 1,
+ hConv,
+ 0,
+ 0,
+ XTYP_EXECUTE,
+ TIMEOUT_ASYNC,
+ NULL)==0){
+ DDEMLERROR("DdeStrs.Exe -- DdeClientTransaction failed:XTYP_EXECUTE\r\n");
+ }
+ }
+ }
+ }
+ return;
+}
+
+BOOL InitClient()
+{
+UINT uid;
+
+ ReconnectList();
+
+ uid = SetTimer( hwndMain,
+ (UINT)GetThreadLong(GETCURRENTTHREADID(),OFFSET_CLIENTTIMER),
+ (UINT)(GetWindowLong(hwndMain,OFFSET_DELAY)),
+ TimerFunc);
+
+ // This starts the test immidiatly. No delay waiting for the first
+ // WM_TIMER call.
+
+ TimerFunc(hwndMain,WM_TIMER,uid,0);
+
+ return(TRUE);
+}
+
+VOID CloseClient()
+{
+HCONVLIST hConvList;
+
+ hConvList=(HCONVLIST)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HCONVLIST);
+ KillTimer(hwndMain,(UINT)GetThreadLong(GETCURRENTTHREADID(),OFFSET_CLIENTTIMER));
+ if (!DdeDisconnectList(hConvList)) {
+ DDEMLERROR("DdeStrs.Exe -- DdeDisconnectList failed\r\n");
+ }
+
+}
+
+VOID ReconnectList()
+{
+ HCONV hConv;
+ HCONVLIST hConvList=0;
+ LONG cClienthConvs;
+ INT i;
+ DWORD dwid;
+
+ dwid=GetThreadLong(GETCURRENTTHREADID(),OFFSET_IDINST);
+ if(dwid==0) {
+ DDEMLERROR("DdeStrs.Exe -- Null IdInst, aborting Connect!\r\n");
+ return;
+ }
+
+ hConvList = DdeConnectList(dwid,
+ ServiceInfoTable[0].hszService,
+ Topics[0].hszTopic,
+ GetThreadLong(GETCURRENTTHREADID(),OFFSET_HCONVLIST),
+ NULL);
+ if (hConvList == 0) {
+
+ // This call is expected to fail in the case of a client
+ // starting when there is no available server. Just return
+ // from the routine and continue.
+
+ return;
+ }
+
+ SetThreadLong(GETCURRENTTHREADID(),OFFSET_HCONVLIST,hConvList);
+
+ hConv = 0;
+ cClienthConvs = 0L;
+
+ while (hConv = DdeQueryNextServer(hConvList, hConv)) {
+ for (i=0; i<(int)Items[0].cFormats; i++) {
+ if (iAvailFormats[i]) {
+ if (!DdeClientTransaction( NULL,
+ 0,
+ hConv,
+ Items[0].hszItem,
+ TestItemFormats[i].wFmt,
+ XTYP_ADVSTART|XTYPF_ACKREQ,
+ TIMEOUT_ASYNC,
+ NULL)){
+ DDEMLERROR("DdeStrs.Exe -- Error DdeClientTransaction failed\r\n");
+ return;
+ } // if
+
+ } // if
+
+ } // for
+
+ cClienthConvs++;
+
+ } // while
+
+ // Update the client count for the current thread.
+
+ dwid=GETCURRENTTHREADID();
+
+ SetThreadLong(dwid,OFFSET_CCLIENTCONVS,cClienthConvs);
+
+ UpdateCount(hwndMain,OFFSET_CLIENT_CONNECT,PNT);
+}
+
diff --git a/private/mvdm/wow16/ddeml/tests/ddestrs/cmdln.c b/private/mvdm/wow16/ddeml/tests/ddestrs/cmdln.c
new file mode 100644
index 000000000..84504b1bb
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/ddestrs/cmdln.c
@@ -0,0 +1,990 @@
+#include <windows.h>
+#include <port1632.h>
+#include <ddeml.h>
+#include "wrapper.h"
+#include "ddestrs.h"
+
+#ifdef WIN16
+#include <time.h>
+#endif
+
+extern BOOL fServer;
+extern BOOL fClient;
+extern INT iAvailFormats[];
+extern BOOL UpdateCount(HWND,INT,INT);
+extern LPSTR pszNetName;
+extern HANDLE hmemNet;
+BOOL IsTopicNameFromNetDde(LPSTR,LPSTR);
+BOOL FixForNetDdeStartup(HWND,LPSTR);
+BOOL FixForStressPercentage(HWND,LPSTR);
+BOOL SetStress(HWND,LONG);
+
+
+/***************************************************************************\
+*
+* InitArgsError
+*
+\***************************************************************************/
+
+VOID InitArgsError(HWND hwnd, unsigned at)
+{
+ /* This function informs the user of an error. */
+
+ static char *mpatszError[] = {
+ "DdeStrs.Exe -- Invalid command line\r\nTry DdeStrs -5% for standard run or DdeStrs -? for help",
+ "DdeStrs.Exe -- Invalid number, possibly missing option value",
+ "DdeStrs.Exe -- Invalid log level",
+ "DdeStrs.Exe -- Invalid number of test to execute",
+ "DdeStrs.Exe -- Invalid starting test number"
+ };
+
+ MessageBox(NULL,mpatszError[at],"Error:DdeStrs",MB_OK|MB_ICONEXCLAMATION);
+}
+
+/***************************************************************************\
+*
+* SysTime - This routine is intended to hide the differences between
+* the 16 bit time routines and win 32. All time queries
+* come through this point.
+*
+\***************************************************************************/
+
+VOID SysTime( LPSYSTEMTIME lpst ) {
+
+#ifdef WIN32
+ GetSystemTime( lpst );
+#else
+
+time_t t;
+struct tm ttmm;
+struct tm far *ptm=&ttmm;
+
+ t=time(&t);
+ ptm=localtime(&t);
+
+ lpst->wYear =ptm->tm_year;
+ lpst->wMonth =ptm->tm_mon;
+ lpst->wDayOfWeek =ptm->tm_wday;
+ lpst->wDay =ptm->tm_yday;
+ lpst->wHour =ptm->tm_hour;
+ lpst->wMinute =ptm->tm_min;
+ lpst->wSecond =ptm->tm_sec;
+ lpst->wMilliseconds =0;
+
+#endif
+
+}
+
+/************************** Private Function ****************************\
+*
+* ParseCommandLine - This routine controls parsing the command line and
+* initializing command line settings.
+*
+\**************************************************************************/
+
+BOOL ParseCommandLine( HWND hwnd, LPSTR lpcmd ) {
+SYSTEMTIME t;
+LPSYSTEMTIME lptime=&t;
+LONG lflags=0L;
+INT i,nThrd,num,nFmts;
+BOOL fSelect=FALSE;
+
+#ifdef WIN32
+LPCRITICAL_SECTION lpcs;
+HANDLE hmem;
+#endif
+
+ // Defaults
+
+ SetWindowLong(hwnd,OFFSET_FLAGS,FLAG_AUTO);
+ SetWindowLong(hwnd,OFFSET_RUNTIME,_1WEEKEND);
+ SetWindowLong(hwnd,OFFSET_STRESS,5L);
+ SetWindowLong(hwnd,OFFSET_DELAY,(100-GetWindowLong(hwnd,OFFSET_STRESS))*DELAY_METRIC);
+ SetWindowLong(hwnd,OFFSET_TIME_ELAPSED,0L);
+ SetWindowLong(hwnd,OFFSET_THRDCOUNT,1L);
+ SetWindowLong(hwnd,OFFSET_CRITICALSECT,0L);
+
+ if(!get_cmd_arg(hwnd,lpcmd))
+ return FALSE;
+
+ // We need to make a change at this point for the
+ // default client/server settings. If at this point
+ // fClient==fServer==FALSE then we want to turn on
+ // both of these as the default.
+
+ if(!fClient && !fServer) {
+ fClient=TRUE;
+ fServer=TRUE;
+ }
+
+ // We need to check to see if specific formats where
+ // specified. If not then select all of them.
+
+ nFmts=0;
+ for(i=0;i<NUM_FORMATS;i++)
+ if(iAvailFormats[i]) {
+ nFmts=nFmts++;
+ fSelect=TRUE;
+ }
+
+ if(!fSelect) {
+ for(i=0;i<NUM_FORMATS;i++) iAvailFormats[i]=1;
+ nFmts=NUM_FORMATS;
+ }
+
+ // We have now read all of the command line. Make needed adjustment
+ // to the delay as needed by addtional threads.
+
+ // This adjustment code works with the routine SetStress. It
+ // does not simply recalculate values. A change to SetStress will
+ // cause changes in the final value.
+
+ lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
+ if(!(lflags&FLAG_USRDELAY)) {
+
+ num=(INT)GetWindowLong(hwnd,OFFSET_DELAY);
+ nThrd=(INT)GetWindowLong(hwnd,OFFSET_THRDCOUNT);
+
+ // 200 is the base value for basic overhead.
+
+ num=(200)+(num*(nThrd*nThrd)*nFmts);
+
+ SetWindowLong(hwnd,OFFSET_DELAY,num);
+ }
+
+ SetWindowLong(hwnd,OFFSET_BASE_DELAY,GetWindowLong(hwnd,OFFSET_DELAY));
+
+ // We need to know the starting time to calculate
+ // time to quit test.
+
+ SysTime(lptime);
+
+ SetWindowLong(hwnd,OFFSET_STARTTIME_SEC,lptime->wSecond);
+ SetWindowLong(hwnd,OFFSET_STARTTIME_MIN,lptime->wMinute);
+ SetWindowLong(hwnd,OFFSET_STARTTIME_HOUR,lptime->wHour);
+ SetWindowLong(hwnd,OFFSET_STARTTIME_DAY,lptime->wDay);
+
+ SetWindowLong(hwnd,OFFSET_LAST_MIN,lptime->wMinute);
+ SetWindowLong(hwnd,OFFSET_LAST_HOUR,lptime->wHour);
+ SetWindowLong(hwnd,OFFSET_TIME_ELAPSED,0L);
+
+#ifdef WIN32
+ /* Setup our critical section if in multi-thread mode */
+
+ lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
+ if(lflags&FLAG_MULTTHREAD) {
+ hmem=GetMemHandle(sizeof(CRITICAL_SECTION));
+ lpcs=GlobalLock(hmem);
+
+ InitializeCriticalSection(lpcs);
+
+ GlobalUnlock(hmem);
+ SetWindowLong(hwnd,OFFSET_CRITICALSECT,(LONG)hmem);
+ }
+#endif
+
+ return TRUE;
+
+}
+
+/***************************************************************************\
+*
+* SetupArgv - This is a conversion routine to go from the window worlds
+* command line format to the more standard argv, argc
+* format. The routine get_cmd_arg was setup for the
+* argv/argc format.
+*
+\***************************************************************************/
+
+int SetupArgv( char *argv[], char *buff, LPSTR cmdline )
+{
+int i=1;
+
+ while( *cmdline != '\0' ) {
+ argv[i] = &buff[0];
+ while ( *cmdline != ' ' && *cmdline != '\0')
+ *buff++ = *cmdline++;
+ *buff++='\0';
+ while(*cmdline == ' ') cmdline++;
+ i++;
+ }
+
+ return i;
+
+}
+
+/***************************************************************************\
+*
+* get_cmd_arg - This routine parses a argv\argc formatted command
+* line and stores away the values.
+*
+\***************************************************************************/
+
+BOOL PASCAL get_cmd_arg( HWND hwnd, LPSTR cmdline ) {
+
+/* This function parses the command line for valid options. TRUE is
+ returned if all of the options are valid; otherwise, FALSE is returned. */
+
+char *pch;
+int iarg;
+unsigned at = AT_SWITCH;
+unsigned num;
+int argc;
+char *argv[10];
+char buff[200];
+LONG lflags=0L;
+
+#ifdef WIN32
+int nThrd;
+#endif
+
+ FixForStressPercentage(hwnd,cmdline);
+ FixForNetDdeStartup(hwnd,cmdline);
+
+ argc = SetupArgv( argv, buff, cmdline );
+
+ /* Iterate over the arguments in the command line. */
+ iarg=1;
+ while(iarg<argc && argv[iarg]!='\0') {
+
+ /* Get the next argument. */
+ pch = argv[iarg];
+
+ /* Process the argument depending upon the arguement
+ * type we are looking for.
+ */
+
+ switch (at) {
+
+ case AT_SWITCH:
+
+ /* All options begin with a switch character. */
+
+ if (*pch != '-' && *pch != '/') {
+ InitArgsError(hwnd,0);
+ return FALSE;
+ }
+
+ /* Skip over the switch character. */
+ pch++;
+
+ /* Look for an option character. */
+ do {
+ switch (*pch) {
+ case 'a':
+ /* Run the test in the background */
+ lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
+ SetWindowLong(hwnd,OFFSET_FLAGS,FLAGON(lflags,FLAG_APPOWNED));
+ break;
+
+ case 'p':
+ /* Run the test in the background */
+ lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
+ SetWindowLong(hwnd,OFFSET_FLAGS,FLAGON(lflags,FLAG_PAUSE_BUTTON|FLAG_PAUSE));
+ break;
+
+ case '?':
+ /* Give brief help. For more detailed information see ddestrs.txt in source directory */
+ MessageBox(NULL,"DdeStrs Options...\r\n-#% stress\r\n-e# delay\r\n-t# run time\r\n-d debug\r\n-a appowned\r\n-s server\r\n-c client\r\n-f# format\r\n-nNAME netdde\r\n-i# threads\r\n-p pause\r\n\nSee DdeStrs.Txt","DdeStrs Help",MB_OK);
+ return FALSE;
+ break;
+
+
+ case 'b':
+ /* Run the test in the background */
+ lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
+ SetWindowLong(hwnd,OFFSET_FLAGS,FLAGON(lflags,FLAG_BACKGROUND));
+ break;
+
+ case 'l':
+ /* Set the name of the log file. */
+ if (*(++pch) == '\0') {
+ /* The next argument should be a filename. */
+ at = AT_FILE;
+ goto NextArg;
+ }
+
+ case 'c':
+ /* This is a client */
+ fClient = TRUE;
+ break;
+
+ case 's':
+ /* This is a server */
+ fServer = TRUE;
+ break;
+
+ case 'i':
+
+ /* The next argument should be the number of threads (w32 only) The
+ range for this = [1...5] */
+#ifdef WIN32
+ lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
+ SetWindowLong(hwnd,OFFSET_FLAGS,FLAGON(lflags,FLAG_MULTTHREAD));
+#endif
+ at = AT_THRD;
+ goto ParseNumber;
+
+ case 'x':
+ /* The next argument should be the stress level. */
+ at = AT_STRESS;
+ goto ParseNumber;
+
+ case 'e':
+ /* The next argument is the delay in milliseconds */
+ lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
+ SetWindowLong(hwnd,OFFSET_FLAGS,FLAGON(lflags,FLAG_USRDELAY));
+ at = AT_DELAY;
+ goto ParseNumber;
+
+ case 'd':
+ /* The next argument is whether we are in debug mode */
+ lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
+ SetWindowLong(hwnd,OFFSET_FLAGS,FLAGON(lflags,FLAG_DEBUG));
+ break;
+
+ case 'n':
+ /* Process the network name */
+ pch++;
+
+ while( *pch==' ' ||
+ *pch=='\\') pch++;
+
+ pszNetName=GetMem(MAX_TITLE_LENGTH,&hmemNet);
+ pszNetName=TStrCpy(pszNetName,pch);
+
+ lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
+ SetWindowLong(hwnd,OFFSET_FLAGS,FLAGON(lflags,FLAG_NET));
+
+ while(*pch!='\0') {
+ pch++;
+ }
+
+ pch--;
+
+ break;
+
+ case 'f':
+ at = AT_FORMAT;
+ goto ParseNumber;
+
+ case 't':
+ lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
+ SetWindowLong(hwnd,OFFSET_FLAGS,FLAGON(lflags,FLAG_TIME));
+
+ /* The next argument is the time (in minutes)
+ to run the test. */
+
+ at = AT_TIME;
+ goto ParseNumber;
+
+ default:
+ InitArgsError(hwnd,0);
+ return FALSE;
+
+ } // switch
+
+ } while (*(++pch) != '\0'); // do-while loop
+
+ break;
+
+ case AT_FILE:
+
+ /* The next argument should be a switch. */
+ at = AT_SWITCH;
+
+ break;
+
+ParseNumber:
+ /* Does this arg have the number? */
+ if (*(++pch) == '\0') goto NextArg;
+
+ case AT_STRESS:
+ case AT_DELAY:
+ case AT_TIME:
+ case AT_WND:
+ case AT_MSG:
+ case AT_THRD:
+
+ /* Set the number of tests to run. */
+
+ if ((num = latoi(pch))==0) {
+ /* Indicate that an invalid number has been specified. */
+ if(at!=AT_DELAY) {
+ InitArgsError(hwnd,0);
+ return FALSE;
+ }
+ }
+
+ switch (at) {
+ case AT_FORMAT:
+ if (num>0 && num<=NUM_FORMATS) {
+ iAvailFormats[num-1]=1;
+ }
+ break;
+
+ case AT_STRESS:
+ SetStress(hwnd,num);
+ break;
+
+ case AT_DELAY:
+ SetWindowLong(hwnd,OFFSET_DELAY,num);
+ lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
+ SetWindowLong(hwnd,OFFSET_FLAGS,FLAGON(lflags,FLAG_USRDELAY));
+ break;
+
+ case AT_TIME:
+ SetWindowLong(hwnd,OFFSET_RUNTIME,num);
+ break;
+
+ case AT_THRD:
+#ifdef WIN32
+ if(num>THREADLIMIT) num=THREADLIMIT;
+
+ // One is not really Mult-thread, shutoff the thread
+ // code and run in normal form.
+
+ if(num==1)
+ {
+ lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
+
+ lflags=FLAGOFF(lflags,FLAG_MULTTHREAD);
+ lflags=FLAGON(lflags,FLAG_USRTHRDCOUNT);
+
+ SetWindowLong(hwnd,OFFSET_FLAGS,lflags);
+
+ SetWindowLong(hwnd,OFFSET_THRDCOUNT,num);
+ }
+ else {
+ SetWindowLong(hwnd,OFFSET_THRDCOUNT,num);
+ lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
+ SetWindowLong(hwnd,OFFSET_FLAGS,FLAGON(lflags,FLAG_USRTHRDCOUNT));
+ }
+#endif
+ break;
+
+ default:
+ InitArgsError(hwnd,0);
+ return FALSE;
+ break;
+
+ } //switch (inside)
+
+ /* The next argument should be a switch. */
+ at = AT_SWITCH;
+ break;
+
+ } // switch (outside)
+
+NextArg:;
+ iarg++;
+ } // While loop
+
+
+ /* Are we still looking for a filename or number? */
+ if (at != AT_SWITCH) {
+ /* Tell the user about the filename or number not found. */
+ InitArgsError(hwnd,0);
+ return FALSE;
+ }
+
+ return TRUE;
+
+} // end get_cmd_args
+
+/***************************************************************************\
+*
+* SetStress
+*
+\***************************************************************************/
+
+BOOL SetStress(HWND hwnd, LONG num) {
+LONG lflags;
+
+#ifdef WIN32
+LONG l;
+#endif
+
+INT n;
+
+ lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
+ SetWindowLong(hwnd,OFFSET_STRESS,num);
+
+#ifdef WIN32
+
+ if(!(lflags&FLAG_USRTHRDCOUNT)) {
+
+ l=S2L(DIV(num,20)+1);
+ if(num>9 && num<20) l++;
+
+ if(l>5) l=5;
+ if(l<1) l=1;
+
+ SetWindowLong(hwnd,OFFSET_THRDCOUNT,l);
+
+ if(l>1) {
+ lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
+ SetWindowLong(hwnd,OFFSET_FLAGS,FLAGON(lflags,FLAG_MULTTHREAD));
+ }
+ }
+#endif
+
+ if(!(lflags&FLAG_USRDELAY)) {
+ n=(int)(100-num)*DELAY_METRIC;
+ SetWindowLong(hwnd,OFFSET_DELAY,n);
+
+ // since dde messages have highest priority we don't
+ // want to swamp the system. Always have some
+ // minimal delay.
+
+ if(n<10) {
+ SetWindowLong(hwnd,OFFSET_DELAY,10);
+ lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
+ SetWindowLong(hwnd,OFFSET_FLAGS,FLAGOFF(lflags,FLAG_DELAYON));
+ }
+ }
+
+ return TRUE;
+}
+
+/******************************************************************\
+* TStrLen
+* 11/20/88
+*
+* Finds the length of a string
+\******************************************************************/
+
+INT TStrLen( LPSTR pStr )
+{
+INT len = 0;
+
+ while( *pStr++!='\0' ) len++;
+
+ return( len );
+}
+
+/******************************************************************\
+* TStrCat
+* 7/16/92
+*
+* Appends source string to destination string. Source string and
+* destination string must be zero terminated!
+\******************************************************************/
+
+LPSTR TStrCat( LPSTR dest, LPSTR source)
+{
+LPSTR start_source;
+LPSTR start_dest;
+INT i=0;
+
+ /* If we have a NULL pointer set destination to NULL and
+ continue */
+
+ if (!dest || !source) {
+ MessageBox(NULL,"TStrCat - NULL ptr for dest or source string!","Error : WmStress",MB_ICONEXCLAMATION);
+ return NULL;
+ }
+
+ start_dest = dest;
+ start_source = source;
+
+ while (*dest++!='\0' && i++<=MAX_TITLE_LENGTH)
+ ;
+
+ TStrCpy(dest,source);
+
+ source = start_source;
+ dest = start_dest;
+
+ return( start_dest );
+}
+
+/*************************** Private Function ******************************\
+*
+* TStrCmp
+*
+* Compares two NULL terminated strings ( returns TRUE if equal )
+*
+\***************************************************************************/
+
+BOOL TStrCmp(LPSTR s, LPSTR t)
+{
+ // Valid pointer?
+
+ if ( !s && !t ) return TRUE; // If either is NULL then they should
+ if ( (!s&&t)||(s&&!t) ) // both be NULL. Otherwise error.
+ return FALSE;
+
+ for (; *s == *t; s++, t++) // Compare strings
+ if (*s=='\0')
+ return TRUE;
+
+ if ((*s-*t)== 0) return TRUE;
+ else return FALSE;
+}
+
+/******************************************************************\
+* TStrCpy
+* 11/20/88
+*
+* Copies a string from source to destination
+\******************************************************************/
+
+LPSTR TStrCpy( LPSTR dest, LPSTR source)
+{
+LPSTR start_source;
+LPSTR start_dest;
+INT i;
+
+ /* If we have a NULL pointer set destination to NULL and
+ continue */
+
+ if(!source) {
+ dest=NULL;
+ return NULL;
+ }
+
+ if (!dest) {
+ MessageBox(NULL,"TStrCpy - NULL ptr for dest!","Error:WmStress",MB_ICONEXCLAMATION);
+ return NULL;
+ }
+
+ start_dest = dest;
+ start_source = source;
+
+ i=0;
+ while (*dest++ = *source++){
+ i++;
+ }
+
+ source = start_source;
+ dest = start_dest;
+
+ return( start_dest );
+}
+
+/***************************************************************************\
+*
+* FixForStressPercentage - This is a fix for the command line -5%. The
+* origional get_cmd_args() did not handle this
+* case. This routine handles string modifications
+* to the command line parse will be correct.
+*
+\***************************************************************************/
+
+BOOL FixForStressPercentage(HWND hwnd, LPSTR lpszStart )
+{
+CHAR ac[6];
+INT i;
+LPSTR lpsz,lpszdash;
+BOOL bLastTime;
+
+ lpsz =lpszStart;
+ lpszdash =NULL;
+
+ ac[0]='x';
+
+ while(*lpsz!='\0') {
+
+ if( *lpsz=='-') lpszdash=lpsz;
+
+ if( *lpsz=='%') {
+
+ if(lpszdash==NULL) return FALSE;
+ else lpsz=(LPSTR)(lpszdash+1);
+
+ // Basically what we do hear is replace the '%' by an 'x'
+ // and shift characters...(-60% becomes -x60).
+
+ i=0;
+ bLastTime=FALSE;
+
+ while(!bLastTime) {
+ ac[i+1]=*lpsz;
+ if(*lpsz=='%') bLastTime=TRUE;
+ *lpsz=ac[i];
+ lpsz++;
+ i++;
+ }
+
+ } // if
+
+ lpsz++;
+
+ } // while
+
+ return TRUE;
+ hwnd;
+
+} // FixForStressPercentage
+
+/***************************************************************************\
+*
+* FixForNetDdeStartup - This is a fix for the command line "Test". The
+* origional get_cmd_args() did not handle this
+* case. This routine modifies the string from
+* "Test" to "-s".
+*
+* The reason for this change is to make ddestrs.exe
+* netdde aware for the startup situation. When
+* netdde starts up the application is passed the topic
+* name (in this case Test) to the application on the
+* command line.
+*
+* NOTE!!! The below code relies on TOPIC="Test". If this has changed then
+* update FixForNetDdeStartup() and IsTopicNameFromNetDde().
+*
+\***************************************************************************/
+
+BOOL FixForNetDdeStartup( HWND hwnd, LPSTR lpszStart )
+{
+INT i;
+LPSTR lpsz;
+
+ lpsz =lpszStart;
+
+ i=1;
+ while(*lpsz!='\0') {
+
+ // Important. I am relying on lpsz being the same
+ // exiting IsTopicNameFromNetDde as it was going in!!!
+
+ if(IsTopicNameFromNetDde(lpsz,TOPIC)) {
+
+ // We have one last check before we make the change. lpsz-2
+ // must not be '-' or '/' and lpsz must not be 'n' or 'N'.
+
+ // Are we at the 3rd char or later? We can't make this
+ // final check unless we have previous character to see.
+
+ if(i>=3) {
+ if( *(lpsz-1)!='n' &&
+ *(lpsz-1)!='N' &&
+ *(lpsz-2)!='-' &&
+ *(lpsz-2)!='/' )
+ {
+ *lpsz='-';
+ *(lpsz+1)='s'; // change "Test" to "-s "
+ *(lpsz+2)=' ';
+ *(lpsz+3)=' ';
+ } // if check for -,n,N,/
+
+ } // if i>=3
+ else {
+ *lpsz='-';
+ *(lpsz+1)='s'; // change "Test" to "-s "
+ *(lpsz+2)=' ';
+ *(lpsz+3)=' ';
+ }
+
+ } // IsTopicName...
+
+ lpsz++;
+ i++; // We use this to keep charater position.
+
+ } // while
+
+ return TRUE;
+ hwnd;
+
+} // FixForNetDdeStartup
+
+/***************************************************************************\
+*
+* IsTopicNameFromNetDde
+*
+\***************************************************************************/
+
+BOOL IsTopicNameFromNetDde(LPSTR lpsz, LPSTR lpszTopic )
+{
+LPSTR lpstr;
+
+ // Check to see that string is >=4 characters not including NULL
+ // terminator.
+
+ lpstr=lpsz;
+
+ if(TStrLen(lpstr)<TStrLen(lpszTopic)) return FALSE;
+
+
+ // Is our topic string present.
+
+ if(*lpsz!='T' && *lpsz!='t') {
+ return FALSE;
+ }
+
+ if(*(lpsz+1)!='e' && *(lpsz+1)!='E') {
+ return FALSE;
+ }
+
+ if(*(lpsz+2)!='s' && *(lpsz+2)!='S') {
+ return FALSE;
+ }
+
+ if(*(lpsz+3)!='t' && *(lpsz+3)!='T') {
+ return FALSE;
+ }
+
+ if(*(lpsz+4)!=' ' && *(lpsz+4)!='\0') {
+ return FALSE;
+ }
+
+ return TRUE;
+
+} // IsTopicNameFromNetDde
+
+/************************** Private Function ****************************\
+*
+* IsTimeExpired - This routine is called periodically to check if its
+* time to quit.
+*
+\**************************************************************************/
+
+BOOL IsTimeExpired( HWND hwnd ) {
+LONG lrtime, lrtPMin, lrtPHour, lrt, l, ll;
+SYSTEMTIME t;
+LPSYSTEMTIME lptime=&t;
+LONG lflags=0L;
+
+ lflags=GetWindowLong(hwnd,OFFSET_FLAGS);
+
+ if(!(lflags&FLAG_STOP)) {
+ // This is how long we should run. In minutes
+
+ lrtime =GetWindowLong(hwnd,OFFSET_RUNTIME);
+
+ // This is how long we have run. In minutes.
+
+ lrt =GetWindowLong(hwnd,OFFSET_TIME_ELAPSED);
+ l=lrt;
+
+ // Time at last check.
+
+ lrtPMin =GetWindowLong(hwnd,OFFSET_LAST_MIN);
+ lrtPHour=GetWindowLong(hwnd,OFFSET_LAST_HOUR);
+
+ SysTime(lptime);
+
+ if(lrtPHour!=(LONG)(lptime->wHour)) {
+
+ // Calc update minutes for the wrap case.
+
+ lrt=(((_1HOUR-lrtPMin)+lptime->wMinute)+lrt);
+
+ // We need to check for multiple hours since last
+ // update.
+
+ if(lrtPHour>lptime->wHour) {
+
+ // In case clock does not rap at 12:00.
+
+ if(lptime->wHour>12) ll=lptime->wHour-12;
+ else ll=lptime->wHour;
+
+ l=(12-lrtPHour)+ll;
+ }
+ else l=lptime->wHour-lrtPHour;
+
+ if(l>1) {
+ lrt=lrt+((l-1)*_1HOUR);
+ }
+
+ }
+
+ else lrt=((lptime->wMinute-lrtPMin)+lrt);
+
+ SetWindowLong(hwnd,OFFSET_LAST_MIN,(LONG)lptime->wMinute);
+ SetWindowLong(hwnd,OFFSET_LAST_HOUR,(LONG)lptime->wHour);
+ SetWindowLong(hwnd,OFFSET_TIME_ELAPSED,lrt);
+
+ if(lptime->wMinute!=LOWORD(lrtPMin))
+ UpdateCount(hwnd,OFFSET_TIME_ELAPSED,PNT);
+
+ // if elapsed time > runtime time has expired.
+
+ if(lrt>=lrtime)
+ return TRUE;
+ else return FALSE;
+ }
+
+ // If we are already shutting down no need to trigger other WM_CLOSE
+ // messages.
+
+ else return FALSE;
+
+}
+
+/*---------------------------------------------------------------------------*\
+| ASCII TO INTEGER
+| This routine converts an ascii string to a decimal integer.
+|
+| created: 12-Oct-90
+| history: 12-Oct-90 <chriswil> created.
+|
+\*---------------------------------------------------------------------------*/
+int APIENTRY latoi(LPSTR lpString)
+{
+ int nInt,nSign;
+
+
+ if(*lpString == '-')
+ {
+ nSign = -1;
+ lpString++;
+ }
+ else
+ {
+ if(*lpString == '+')
+ lpString++;
+ nSign = 1;
+ }
+
+ nInt = 0;
+ while(*lpString)
+ nInt = (nInt*10) + (*lpString++ - 48);
+
+ return(nInt * nSign);
+}
+
+/*****************************************************************************\
+| INTEGER TO ASCI
+| This routine converts an decimal integer to an ascii string.
+|
+| created: 29-Jul-91
+| history: 29-Jul-91 <johnsp> created.
+|
+\*****************************************************************************/
+LPSTR FAR PASCAL itola(INT i, LPSTR lpsz)
+{
+LPSTR lpsz_start;
+INT irange=1;
+INT id=0;
+
+ lpsz_start=lpsz; // Keep track of the beginning of the
+ // string.
+ while (id=DIV(i,irange)>0)
+ irange=irange*10;
+
+ irange=DIV(irange,10);
+
+ if(i==0) { // If i==0 set string and we
+ *lpsz='0'; // will skip loop
+ lpsz++;
+ }
+
+ while (irange>0) {
+
+ id=DIV(i,irange); // Calculate character
+ *lpsz=(CHAR)(id+48);
+
+ lpsz++;
+ i=i-(irange*id); // Adjust values for next time
+ irange=DIV(irange,10); // through the loop.
+
+ }
+
+ *lpsz='\0'; // Null terminate the string
+
+ return lpsz_start;
+
+}
diff --git a/private/mvdm/wow16/ddeml/tests/ddestrs/ddesorg.ico b/private/mvdm/wow16/ddeml/tests/ddestrs/ddesorg.ico
new file mode 100644
index 000000000..65c6a7180
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/ddestrs/ddesorg.ico
Binary files differ
diff --git a/private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.c b/private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.c
new file mode 100644
index 000000000..e05745cb4
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.c
@@ -0,0 +1,1856 @@
+#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=&ll;
+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;
+
+}
+
+
diff --git a/private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.def b/private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.def
new file mode 100644
index 000000000..775c1543d
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.def
@@ -0,0 +1,17 @@
+NAME DDESTRS
+
+DESCRIPTION 'Microsoft Windows DDE stress'
+EXETYPE WINDOWS
+STUB 'WINSTUB.EXE'
+
+CODE PRELOAD FIXED
+DATA PRELOAD MOVEABLE MULTIPLE
+
+HEAPSIZE 4096
+STACKSIZE 4096
+
+EXPORTS
+ MAINWNDPROC @1
+ DISPWNDPROC @2
+ WRAPPERCALLBACK @3
+
diff --git a/private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.h b/private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.h
new file mode 100644
index 000000000..192a2c3a9
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.h
@@ -0,0 +1,287 @@
+#ifdef WIN16
+
+typedef struct _SYSTEMTIME {
+ WORD wYear;
+ WORD wMonth;
+ WORD wDayOfWeek;
+ WORD wDay;
+ WORD wHour;
+ WORD wMinute;
+ WORD wSecond;
+ WORD wMilliseconds;
+} SYSTEMTIME, *PSYSTEMTIME, *LPSYSTEMTIME;
+
+#define GETCURRENTTHREADID() 1
+
+#else
+
+#define GETCURRENTTHREADID() GetCurrentThreadId()
+
+#endif
+
+#define WHITE RGB(255,255,255)
+#define GREEN RGB(0,128,128)
+#define GREY RGB(192,192,192)
+#define TOPIC "Test"
+
+extern HANDLE hExtraMem;
+
+#ifdef WIN32
+#define PNT_INTERVAL 60000
+#else
+#define PNT_INTERVAL 30000
+#endif
+
+#define _5SEC 5000 // milliseconds
+#define _1MIN 1
+#define _1HOUR 60
+#define _1DAY 1440
+#define _1WEEKEND 4320
+#define _1WEEK 10080
+#define SERVER 0
+#define CLIENT 1
+
+#ifdef WIN16
+#define NUM_FORMATS 5
+#else
+#define NUM_FORMATS 6
+#endif
+
+// The below offsets are used with Set/GetThreadLong() "THREAD"
+// Offset defines cannot be interchanged between window
+// and thread use because of collisions.
+
+#define OFFSET_IDINST 0
+#define OFFSET_HCONVLIST 4
+#define OFFSET_CSERVERCONVS 8
+#define OFFSET_HSERVERCONVS 12
+#define OFFSET_HAPPOWNED 16
+#define OFFSET_CCLIENTCONVS 20
+#define OFFSET_HWNDDISPLAY 24
+#define OFFSET_CLIENTTIMER 28
+#define OFFSET_SERVERTIMER 32
+#define DELAY_METRIC 2
+
+#define EXTRA_THREAD_MEM OFFSET_SERVERTIMER+4
+#define S2L(s) (LONG)(MAKELONG((WORD)(s),0))
+
+// The below offsets are used with Set/GetWindowLong() "WINDOW"
+
+#define OFFSET_FLAGS 0
+#define OFFSET_RUNTIME 4
+#define OFFSET_STARTTIME_SEC 8
+#define OFFSET_STARTTIME_MIN 12
+#define OFFSET_STARTTIME_HOUR 16
+#define OFFSET_STARTTIME_DAY 20
+#define OFFSET_LAST_MIN 24
+#define OFFSET_LAST_HOUR 28
+#define OFFSET_TIME_ELAPSED 32
+#define OFFSET_DELAY 36
+#define OFFSET_STRESS 40
+#define OFFSET_SERVER_CONNECT 44
+#define OFFSET_CLIENT_CONNECT 48
+#define OFFSET_CLIENT 52
+#define OFFSET_SERVER 56
+
+#define OFFSET_THRDMAIN 60 // <== ***
+#define OFFSET_THRD2 64 // <== *** Ordering here is relied
+#define OFFSET_THRD3 68 // <== *** upon in the test. Keep
+#define OFFSET_THRD4 72 // <== *** This group of values
+#define OFFSET_THRD5 76 // <== *** in sequential order.
+#define OFFSET_THRDMID 80 // <== ***
+#define OFFSET_THRD2ID 84 // <== ***
+#define OFFSET_THRD3ID 88 // <== ***
+#define OFFSET_THRD4ID 92 // <== ***
+#define OFFSET_THRD5ID 96 // <== ***
+#define OFFSET_THRD2EVENT 100 // <== ***
+#define OFFSET_THRD3EVENT 104 // <== ***
+#define OFFSET_THRD4EVENT 108 // <== ***
+#define OFFSET_THRD5EVENT 112 // <== ***
+
+#define OFFSET_CRITICALSECT 116
+#define OFFSET_THRDCOUNT 120
+#define OFFSET_EXTRAMEM 124
+#define OFFSET_DISPWNDHEIGHT 128
+#define OFFSET_BASE_DELAY 132
+#define OFFSET_MEM_ALLOCATED 136
+
+#define WND OFFSET_MEM_ALLOCATED+4
+
+#define ID_OFFSET 20
+#define INC 1
+#define DEC 0
+#define STP 2
+#define PNT 3
+#define ALL -1
+
+#define ON 1
+#define OFF 0
+
+#define AT_SWITCH 1
+#define AT_FILE 2
+#define AT_STRESS 3
+#define AT_DELAY 4
+#define AT_TIME 5
+#define AT_WND 6
+#define AT_MSG 7
+#define AT_FORMAT 8
+#define AT_THRD 9
+
+#define FLAG_BACKGROUND 0x00000001
+#define FLAG_AUTO 0x00000002
+#define FLAG_TIME 0x00000004
+#define FLAG_STOP 0x00000008
+#define FLAG_LOG 0x00000010
+#define FLAG_USRWNDCOUNT 0x00000020
+#define FLAG_USRMSGCOUNT 0x00000040
+#define FLAG_USRDELAY 0x00000080
+#define FLAG_DEBUG 0x00000100
+#define FLAG_CHARINFO 0x00000200
+#define FLAG_DELAYON 0x00000400
+#define FLAG_TEST_MSG_ON 0x00000800
+#define FLAG_MSGDELAYON 0x00001000
+#define FLAG_APPOWNED 0x00002000
+#define FLAG_MULTTHREAD 0x00004000
+
+#define FLAG_THRD2 0x00008000
+#define FLAG_THRD3 0x00010000
+#define FLAG_THRD4 0x00020000
+#define FLAG_THRD5 0x00040000
+
+#define FLAG_NET 0x00080000
+#define FLAG_SYNCPAINT 0x00100000
+#define FLAG_USRTHRDCOUNT 0x00200000
+#define FLAG_PAUSE_BUTTON 0X00400000
+#define FLAG_PAUSE 0X00800000
+
+#define THREADLIMIT 5
+
+#define STD_EXIT 1
+#define ABNORMAL_EXIT 0
+
+#define FLAGON(a,b) (LONG)(a|b)
+#define FLAGOFF(a,b) (LONG)(a&(~b))
+
+//#define MAX_SERVER_HCONVS 1000
+#define MAX_SERVER_HCONVS 500
+
+#define IDR_ICON 1
+#define IDR_MENU 2
+#define IDM_DIE 100
+
+#define DIGITS_IN_TENMILL 8
+#define BLANK_SPACE 3
+#define LONGEST_LINE 15
+
+#define NUM_COLUMNS (LONGEST_LINE+BLANK_SPACE+DIGITS_IN_TENMILL)
+#define NUM_ROWS 16
+#define MAX_TITLE_LENGTH 100
+
+#define TXT 0
+#define DIB 1
+#define BITMAP 2
+#define ENHMETA 3
+#define METAPICT 4
+#define PALETTE 5
+
+#define EXIT_THREAD WM_USER+6
+#define START_DISCONNECT WM_USER+7
+
+#include "globals.h"
+
+/*
+ * Prototypes
+ */
+
+/*
+ * ddestrs.c
+ */
+
+LONG FAR PASCAL MainWndProc(HWND hwnd, UINT message, WPARAM wParam, LONG lParam);
+
+VOID InitArgsError(HWND,unsigned);
+VOID SysTime(LPSYSTEMTIME);
+BOOL ParseCommandLine(HWND,LPSTR);
+int SetupArgv( char **, char *, LPSTR);
+BOOL PASCAL get_cmd_arg(HWND,LPSTR);
+BOOL IsTimeExpired(HWND);
+
+INT DIV(INT,INT);
+
+BOOL TStrCmp(LPSTR,LPSTR);
+LPSTR TStrCpy(LPSTR,LPSTR);
+LPSTR TStrCat(LPSTR,LPSTR);
+INT TStrLen(LPSTR);
+
+LPSTR FAR PASCAL itola(int,LPSTR);
+int APIENTRY latoi(LPSTR);
+
+BOOL DOut(HWND,LPSTR,LPSTR,INT);
+BOOL EOut(LPSTR);
+
+
+#ifdef WIN32
+BOOL ThreadShutdown(VOID);
+BOOL ThreadDisconnect(VOID);
+#endif
+
+#define DDEMLERROR(a) EOut(a)
+#define LOGDDEMLERROR(a) EOut(a)
+
+
+/*
+ * client.c
+ */
+
+void CALLBACK TimerFunc(HWND,UINT,UINT,DWORD);
+VOID PaintClient(HWND hwnd, PAINTSTRUCT *pps);
+VOID ReconnectList(VOID);
+BOOL InitClient(VOID);
+VOID CloseClient(VOID);
+
+/*
+ * server.c
+ */
+
+HDDEDATA RenderHelp_Text(HDDEDATA hData);
+BOOL PokeTestItem_Text(HDDEDATA hData);
+HDDEDATA RenderTestItem_Text(HDDEDATA hData);
+BOOL PokeTestItem_DIB(HDDEDATA hData);
+HDDEDATA RenderTestItem_DIB(HDDEDATA hData);
+BOOL PokeTestItem_BITMAP(HDDEDATA hData);
+HDDEDATA RenderTestItem_BITMAP(HDDEDATA hData);
+BOOL PokeTestItem_METAPICT(HDDEDATA hData);
+HDDEDATA RenderTestItem_METAPICT(HDDEDATA hData);
+BOOL PokeTestItem_ENHMETA(HDDEDATA hData);
+HDDEDATA RenderTestItem_ENHMETA(HDDEDATA hData);
+BOOL PokeTestItem_PALETTE(HDDEDATA hData);
+HDDEDATA RenderTestItem_PALETTE(HDDEDATA hData);
+HINSTANCE GetHINSTANCE(HWND);
+
+BOOL Execute(HDDEDATA hData);
+VOID PaintServer(HWND hwnd, PAINTSTRUCT *pps);
+HDDEDATA FAR PASCAL CustomCallback(UINT wType, UINT wFmt, HCONV hConv, HSZ hsz1,
+ HSZ hsz2, HDDEDATA hData, DWORD dwData1, DWORD dwData2);
+
+#ifdef WIN32
+VOID ThreadWait(HWND);
+DWORD SecondaryThreadMain(DWORD);
+BOOL ThreadInit(HWND);
+#endif
+
+LONG SetFlag(HWND,LONG,INT);
+LONG SetCount(HWND,INT,LONG,INT);
+LPSTR GetMem(INT, LPHANDLE);
+BOOL FreeMem(HANDLE);
+BOOL FreeMemHandle(HANDLE);
+HANDLE GetMemHandle(INT);
+LONG SetThreadLong(DWORD,INT,LONG);
+LONG GetThreadLong(DWORD,INT);
+BOOL FreeThreadExtraMem(void);
+BOOL CreateThreadExtraMem(INT,INT);
+BOOL InitThreadInfo(DWORD);
+BOOL FreeThreadInfo(DWORD);
+INT IDtoTHREADNUM(DWORD);
+HWND CreateDisplayWindow(HWND,INT);
+LONG GetCurrentCount(HWND,INT);
+
diff --git a/private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.ico b/private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.ico
new file mode 100644
index 000000000..035bcc11b
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.ico
Binary files differ
diff --git a/private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.rc b/private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.rc
new file mode 100644
index 000000000..b5090896a
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.rc
@@ -0,0 +1,13 @@
+#include <windows.h>
+#include "ddestrs.h"
+
+IDR_ICON ICON ddestrs.ico
+
+
+IDR_MENU MENU
+BEGIN
+ POPUP "&Options"
+ BEGIN
+ MENUITEM "&Die!", IDM_DIE
+ END
+END
diff --git a/private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.txt b/private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.txt
new file mode 100644
index 000000000..d87d32c93
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/ddestrs/ddestrs.txt
@@ -0,0 +1,110 @@
+The document breifly describes DdeStrs.exe.
+
+DdeStrs is intended to exercise and stress Dde/Ddeml.
+
+Some areas exercised in the test are ...
+
+ o Async/fAckRequest advise loops
+ o Async executes
+ o CF_TEXT, CF_DIB, CF_BITMAP, CF_METAFILEPICT, CF_PALETTE,
+ and CF_ENHMETAFILE (w32 only) formats.
+ o DdeConnectList/DdeDisconnectList
+ o AppOwned handles [when -a option used]
+ o Variable client/server connects (number of instances running
+ of ddestrs.exe)
+ o Cross process/In process and multithread communication.
+ o System Timers
+
+
+The command line options are ...
+
+DdeStrs [-#%,-e#,-t#,-d,-a,-s,-c,-f#,-nNAME,-i#,-p,-?]
+
+ where -#% allow the user to specify the intensity of
+ the run (# = [1...100]) and can be read as stress
+ percentage. 1 being low stress 100 being high stress.
+
+ where -e# allows override of the delay set by the stress
+ level. -e0 is usefull if the stress test is the only one
+ running and it is desirable for the test to cover ground
+ (number of windows, classes, and messages that are
+ exercised). # is in milliseconds.
+
+ where -t# specifies the number of minutes for the test to run. At
+ the end of # minutes the test will shutdown. Default is 4320 min
+ (About a weekend). Test can also be exited manually at any
+ point.
+
+ where -d selects debug mode. This mode of operation displays
+ additional test information and outputs failures to
+ the debug terminal. This mode is intended for debugging
+ DdeStrs failures and not for use in public stress runs.
+
+ where -a specifies to use AppOwned handle for data communications.
+
+ where -s specifies that this instance is to run as server only
+ [default is -s -c].
+
+ where -c specifies that this instance is to run as client only.
+ [default is -s -c].
+
+ where -f# allow specific formats to be used. Default is all
+ formats. If any specific formats are specified then only
+ to formats will be used in the communication.
+
+ [Ex - ddestrs -f1 -f2] will only use formats 1 and 2.
+
+ Formats 1 CF_TEXT
+ 2 CF_DIB
+ 3 CF_BITMAP
+ 4 CF_ENHMETAFILE (w32 only)
+ 5 CF_METAFILEPICT
+ 6 CF_PALETTE
+
+ where -nNAME specifies the computer name to connect to. This
+ is used for netdde and only needs to be specified on client
+ applications. NAME=servername, Example '-njohnsp1' for
+ computer \\johnsp1. Use Ddeshare.exe (w31 resources kit or
+ Nt sdk) to setup the dde share enabling netdde to work. DdeStrs
+ Service Name=DdeStrs, Topic=Test, and permissions must be
+ change or greater (ddestrs.exe uses executes).
+
+ where -i# specifies the number of threads to execute. # can
+ be in the range [1..5]. This option is only available
+ for Win Nt.
+
+ where -p specifies pause before data update. With this specified the user can
+ manually start executes and advise updates. With this connections are established, but
+ no data is passed until manually started. DdeStrs adds a 'pause' button to allow stress
+ to be started and stopped. Default is NO -p.
+
+ where -? brings up a brief help list of DdeStrs Options.
+
+Test Usage ...
+
+ Ddestrs will communicate with multiple copies of itself. Each
+ new instance of ddestrs started will cause other instances to
+ connect to all running copies available for conversation. This
+ allows the stress level to be tailored both by the -#% and
+ by the number of copies of the test running.
+
+Focus Test Api ...
+
+DdeQueryNextServer
+DdeClientTransaction
+DdeDisconnectList
+DdeConnectList
+DdeAccessData
+DdeAddData
+DdePostAdvise
+DdeDisconnect
+DdeUnaccessData
+DdeInitialize
+DdeNameService
+DdeCreateStringHandle
+DdeUninitialize
+DdeFreeStringHandle
+DdeCmpStringHandles
+DdeQueryConvInfo
+DdeCreateDataHandle
+DdeFreeDataHandle
diff --git a/private/mvdm/wow16/ddeml/tests/ddestrs/globals.c b/private/mvdm/wow16/ddeml/tests/ddestrs/globals.c
new file mode 100644
index 000000000..8dc7c2b3e
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/ddestrs/globals.c
@@ -0,0 +1,106 @@
+
+#include <windows.h>
+#include <port1632.h>
+#include <ddeml.h>
+#include "wrapper.h"
+#include "ddestrs.h"
+
+/* Truley global variables */
+
+CHAR szClass[] = "DdeStrs";
+int cyText = 0;
+int cxText = 0;
+BOOL fClient = FALSE;
+BOOL fServer = FALSE;
+HINSTANCE hInst;
+
+HWND hwndMain;
+CHAR szExecDie[] = "Die";
+CHAR szExecDisconnect[] = "Disconnect";
+CHAR szExecRefresh[] = "Refresh";
+
+// This array contains storage for each supported
+// format (CF_TEXT,CF_BITMAP,CF_DIB,..CF_ENHMETAFILE)
+
+INT iAvailFormats[] = { 0, 0, 0, 0, 0, 0 };
+
+/*
+ * Service tables - read bottom up
+ */
+DDEFORMATTBL TestItemFormats[] = {
+ {
+ "TEXT",
+ CF_TEXT,
+ 0,
+ PokeTestItem_Text,
+ RenderTestItem_Text
+ },
+ {
+ "DIB",
+ CF_DIB,
+ 0,
+ PokeTestItem_DIB,
+ RenderTestItem_DIB
+ },
+ {
+ "BITMAP",
+ CF_BITMAP,
+ 0,
+ PokeTestItem_BITMAP,
+ RenderTestItem_BITMAP
+ },
+#ifdef WIN32
+ {
+ "ENHMETAFILE",
+ CF_ENHMETAFILE,
+ 0,
+ PokeTestItem_ENHMETA,
+ RenderTestItem_ENHMETA
+ },
+#endif
+ {
+ "METAFILEPICT",
+ CF_METAFILEPICT,
+ 0,
+ PokeTestItem_METAPICT,
+ RenderTestItem_METAPICT
+ },
+ {
+ "PALETTE",
+ CF_PALETTE,
+ 0,
+ PokeTestItem_PALETTE,
+ RenderTestItem_PALETTE
+ }
+};
+
+DDEITEMTBL Items[] = {
+ {
+ "TestItem",
+ 0,
+ sizeof(TestItemFormats) / sizeof(DDEFORMATTBL),
+ 0,
+ TestItemFormats
+ }
+};
+
+DDETOPICTBL Topics[] = {
+ {
+ TOPIC,
+ 0,
+ sizeof(Items) / sizeof(DDEITEMTBL),
+ 0,
+ Items,
+ Execute
+ }
+};
+
+DDESERVICETBL ServiceInfoTable[] = {
+ {
+ "DdeStrs",
+ 0,
+ sizeof(Topics) / sizeof(DDETOPICTBL),
+ 0,
+ Topics
+ }
+};
diff --git a/private/mvdm/wow16/ddeml/tests/ddestrs/globals.h b/private/mvdm/wow16/ddeml/tests/ddestrs/globals.h
new file mode 100644
index 000000000..b1ccda8ee
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/ddestrs/globals.h
@@ -0,0 +1,19 @@
+
+extern CHAR szClass[];
+extern int cyText;
+extern int cxText;
+extern BOOL fClient;
+extern BOOL fServer;
+extern HINSTANCE hInst;
+extern HCONV pServerhConvs[MAX_SERVER_HCONVS];
+extern HWND hwndMain;
+extern CHAR szExecDie[];
+extern CHAR szExecDisconnect[];
+extern CHAR szExecRefresh[];
+extern INT iAvailFormats[];
+
+DDEFORMATTBL TestItemFormats[];
+DDEITEMTBL Items[];
+DDETOPICTBL Topics[];
+DDESERVICETBL ServiceInfoTable[];
+
diff --git a/private/mvdm/wow16/ddeml/tests/ddestrs/makefile b/private/mvdm/wow16/ddeml/tests/ddestrs/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/ddestrs/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/mvdm/wow16/ddeml/tests/ddestrs/makefile.dos b/private/mvdm/wow16/ddeml/tests/ddestrs/makefile.dos
new file mode 100644
index 000000000..c7c1599a1
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/ddestrs/makefile.dos
@@ -0,0 +1,50 @@
+#
+# Test makefile
+
+!ifdef WIN31
+EXEFLAGS=-AM -Gsw -Od -Ziep -W3 -DWIN16 -DWIN31 -DUSECOMM -DWIN
+!else
+EXEFLAGS=-AS -FPi -Gcw -Os -Ziepd -W3 -DWIN16 -DWIN
+!endif
+
+TEST =ddestrs
+RCFILE =ddestrs
+S1 =cmdln
+S2 =client
+S3 =$(TEST)
+S4 =globals
+S5 =server
+S6 =wrapper
+OBJ =$(S1).obj $(S2).obj $(S3).obj $(S4).obj $(S5).obj $(S6).obj
+
+#
+# Stress Test
+#
+
+all: $(TEST).exe
+
+$(RCFILE).res: $(RCFILE).rc
+ rc -r $(RCFILE).rc
+
+$(S1).obj: $(S1).c $(S3).h $(S6).h
+ cl -c $(EXEFLAGS) $(S1).c
+
+$(S2).obj: $(S2).c $(S3).h $(S6).h
+ cl -c $(EXEFLAGS) $(S2).c
+
+$(S3).obj: $(S3).c $(S3).h $(S6).h
+ cl -c $(EXEFLAGS) $(S3).c
+
+$(S4).obj: $(S4).c $(S3).h $(S6).h
+ cl -c $(EXEFLAGS) $(S4).c
+
+$(S5).obj: $(S5).c $(S3).h $(S6).h
+ cl -c $(EXEFLAGS) $(S5).c
+
+$(S6).obj: $(S6).c $(S3).h $(S6).h
+ cl -c $(EXEFLAGS) $(S6).c
+
+$(TEST).exe: $(OBJ) $(TEST).def $(RCFILE).res
+ link /map/li/co $(OBJ)/AL:16,$(TEST).exe,, /NOE /NOD libw ddeml mlibcew,$(TEST).def
+ mapsym $(TEST)
+ rc $(RCFILE).res $(TEST).exe
diff --git a/private/mvdm/wow16/ddeml/tests/ddestrs/mk.cmd b/private/mvdm/wow16/ddeml/tests/ddestrs/mk.cmd
new file mode 100644
index 000000000..7fbb62b49
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/ddestrs/mk.cmd
@@ -0,0 +1 @@
+build -cl ddestrs
diff --git a/private/mvdm/wow16/ddeml/tests/ddestrs/mk4dos.cmd b/private/mvdm/wow16/ddeml/tests/ddestrs/mk4dos.cmd
new file mode 100644
index 000000000..1cc3f8bff
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/ddestrs/mk4dos.cmd
@@ -0,0 +1,13 @@
+@echo off
+if "%1"=="" goto bld
+del *.dll
+del *.sym
+del *.map
+del *.obj
+del *.bak
+del *.res
+del *.lnk
+goto done
+:bld
+nmake -f makefile.dos
+:done
diff --git a/private/mvdm/wow16/ddeml/tests/ddestrs/runddes.bat b/private/mvdm/wow16/ddeml/tests/ddestrs/runddes.bat
new file mode 100644
index 000000000..d68805551
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/ddestrs/runddes.bat
@@ -0,0 +1,12 @@
+start ddestrs.exe -10%% -e35000
+sleep 30
+
+ddestrs.exe -c -e13000 -t10
+sleep 10
+
+:loop
+start ddestrs.exe -t3 -s -a
+sleep 15
+ddestrs.exe -c -e13000 -t10
+sleep 20
+goto loop
diff --git a/private/mvdm/wow16/ddeml/tests/ddestrs/server.c b/private/mvdm/wow16/ddeml/tests/ddestrs/server.c
new file mode 100644
index 000000000..56f1d2280
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/ddestrs/server.c
@@ -0,0 +1,1372 @@
+
+#include <windows.h>
+#include <port1632.h>
+#include <ddeml.h>
+#include <string.h>
+#include "wrapper.h"
+#include "ddestrs.h"
+
+extern BOOL UpdateCount(HWND,INT,INT);
+BOOL Balance(INT);
+
+/*
+ * Service routines
+ */
+
+/*************************** Private Function ******************************\
+
+GetHINSTANCE
+
+\***************************************************************************/
+
+HINSTANCE GetHINSTANCE( HWND hwnd ) {
+HINSTANCE hInstance;
+
+#ifdef WIN32
+ hInstance=(HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE);
+#else
+ hInstance=(HINSTANCE)GetWindowWord(hwnd,GWW_HINSTANCE);
+#endif
+
+ return hInstance;
+
+}
+
+//*****************************************************************************
+//************************** DispWndProc **************************
+//*****************************************************************************
+
+LONG FAR PASCAL DispWndProc( HWND hwnd , UINT msg, WPARAM wp, LONG lp) {
+
+ return DefWindowProc(hwnd,msg,wp,lp);
+
+}
+
+/*************************** Private Function ******************************\
+*
+* CreateDisplayWindow
+*
+\***************************************************************************/
+
+HWND CreateDisplayWindow( HWND hwndParent, int nPosIndex ) {
+WNDCLASS wc,wcc;
+LPWNDCLASS lpWndClass=&wc;
+HWND hwnd;
+RECT r;
+int stpy,stpx,cy;
+char sz[100];
+LPSTR lpstr=&sz[0];
+
+#ifdef WIN32
+LPCTSTR lpsz;
+#else
+LPSTR lpsz;
+#endif
+
+char szname[100];
+
+ strcpy(&szname[0],"Display Window");
+
+ wc.style = 0;
+ wc.lpfnWndProc = DispWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = GetHINSTANCE(hwndParent);
+ wc.hIcon = LoadIcon(NULL,IDI_EXCLAMATION );
+ wc.hCursor = LoadCursor(NULL,IDC_ARROW );
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = "Display Window";
+ wc.hbrBackground = CreateSolidBrush(RGB(0,255,255));
+
+ lpsz=(LPSTR)wc.lpszClassName;
+
+ if(!GetClassInfo(wc.hInstance,lpsz,&wcc)) {
+ RegisterClass(lpWndClass);
+ }
+
+ GetClientRect(hwndParent,&r);
+
+ stpx =r.right-r.left;
+ stpy =((r.bottom-r.top)/3);
+
+ switch(nPosIndex) {
+ case 1: cy=r.bottom-(3*cyText);
+ break;
+ case 2: cy=r.bottom-(6*cyText);
+ break;
+ case 3: cy=r.bottom-(9*cyText);
+ break;
+ case 4: cy=r.bottom-(12*cyText);
+ break;
+ case 5: cy=r.bottom-(15*cyText);
+ break;
+ default: cy=r.bottom-(18*cyText);
+ break;
+ }
+
+ if (!IsWindow(hwndParent)) DOut((HWND)NULL,"DdeStrs.exe -- ERR:Bad parent hwnd=%u!\r\n",0,(LONG)hwndParent);
+
+ hwnd = CreateWindowEx(WS_EX_DLGMODALFRAME,
+ "Display Window",
+ &szname[0],
+ WS_CHILD|WS_VISIBLE|WS_CAPTION|WS_DISABLED,
+ 0,
+ cy,
+ stpx,
+ 3*cyText,
+ hwndParent,
+ NULL,
+ lpWndClass->hInstance,
+ NULL );
+
+ if ( !IsWindow(hwnd) )
+ {
+ DDEMLERROR("DdeStrs.Exe -- ERR:Display window not created\r\n");
+ UnregisterClass("Display Window",wc.hInstance);
+ }
+
+ return hwnd;
+
+}
+
+BOOL PokeTestItem_Text(
+HDDEDATA hData)
+{
+LPBYTE lpData;
+HDC hdc;
+HBRUSH hBrush;
+PAINTSTRUCT ps;
+RECT rc;
+DWORD cbData;
+HWND hwndDisplay;
+
+ Balance(OFFSET_CLIENT);
+
+ hwndDisplay=(HWND)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HWNDDISPLAY);
+ SetWindowText(hwndDisplay,"Client - CF_TEXT");
+
+ lpData = (LPBYTE) DdeAccessData( hData, &cbData );
+
+ hdc = GetDC(hwndDisplay);
+ if(!hdc) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:NULL hdc ret from GetDC (client:CF_TEXT)!\r\n");
+ DdeUnaccessData(hData); //JOHNSP:CHANGE
+ return 0;
+ }
+
+ hBrush=CreateSolidBrush(WHITE);
+ if(!hBrush) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:NULL hBrush ret from CreateSolidBrush (client:CF_TEXT)!\r\n");
+ DdeUnaccessData(hData); //JOHNSP:CHANGE
+ EndPaint(hwndDisplay,&ps);
+ return 0;
+ }
+
+ GetClientRect(hwndDisplay,&rc);
+
+ FillRect(hdc,&rc,hBrush);
+ DeleteObject(hBrush);
+
+ DrawText(hdc, lpData, -1, &rc, DT_LEFT|DT_TOP);
+ ReleaseDC(hwndDisplay,hdc);
+
+ DdeUnaccessData(hData); //JOHNSP:CHANGE
+
+ return(TRUE);
+
+}
+
+BOOL PokeTestItem_DIB(
+HDDEDATA hData)
+{
+HWND hwnd;
+HDC hdc;
+RECT r;
+INT width,height;
+LPBITMAPINFO lpbitinfo;
+LPBYTE lpbits;
+HANDLE hmem;
+LPBYTE lpData;
+DWORD cbData;
+LPBYTE lp;
+int iexRGB;
+
+ Balance(OFFSET_CLIENT);
+
+ lpData = (LPBYTE) DdeAccessData( hData, &cbData );
+
+ hwnd=(HWND)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HWNDDISPLAY);
+ SetWindowText(hwnd,"Client - CF_DIB");
+
+ hdc = GetDC(hwnd);
+ if(!hdc) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:NULL hdc (client)\r\n");
+ DdeUnaccessData(hData); //JOHNSP:CHANGE
+ return 0;
+ }
+
+ GetClientRect(hwnd,&r);
+ width=r.right-r.left;
+ height=r.bottom-r.top;
+
+#ifdef WIN32
+ memcpy(&hmem,lpData,sizeof(HANDLE));
+#else
+ _fmemcpy(&hmem,lpData,sizeof(HANDLE));
+#endif
+
+ if(!hmem) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:hmem recieved from server=NULL (client)\r\n");
+ DdeUnaccessData(hData); //JOHNSP:CHANGE
+ ReleaseDC(hwnd,hdc);
+ return 0;
+ }
+
+ lp =(LPBYTE)GlobalLock(hmem);
+ lpbitinfo=(LPBITMAPINFO)lp;
+
+ // iexRGB is ((2^n)-1) where n=biBitCount and we are computing the
+ // number of RGBQUAD structures. Remember that part of the
+ // BITMAPINFO structure contains 1 RGBQUAD already.
+
+ iexRGB =((0x0001<<lpbitinfo->bmiHeader.biBitCount)-1)*sizeof(RGBQUAD);
+ lpbits=lp+(sizeof(BITMAPINFO)+iexRGB);
+
+ SetDIBitsToDevice(hdc,
+ 0,
+ 0,
+ (UINT)lpbitinfo->bmiHeader.biWidth,
+ (UINT)lpbitinfo->bmiHeader.biHeight,
+ 0,
+ 0,
+ 0,
+ (UINT)(lpbitinfo->bmiHeader.biHeight),
+ lpbits,
+ lpbitinfo,
+ DIB_RGB_COLORS);
+
+ ReleaseDC(hwnd,hdc);
+
+ DdeUnaccessData(hData); //JOHNSP:CHANGE
+
+ return(TRUE);
+}
+
+BOOL PokeTestItem_BITMAP(
+HDDEDATA hData)
+{
+HWND hwnd;
+HDC hdc,hdcMem;
+RECT r;
+INT width,height;
+HBITMAP hbmap;
+HANDLE hobj;
+LPBYTE lpData;
+DWORD cbData;
+
+ Balance(OFFSET_CLIENT);
+
+ hwnd=(HWND)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HWNDDISPLAY);
+ SetWindowText(hwnd,"Client - CF_BITMAP");
+
+ lpData = (LPBYTE) DdeAccessData( hData, &cbData );
+
+#ifdef WIN32
+ memcpy(&hbmap,lpData,sizeof(HBITMAP));
+#else
+ _fmemcpy(&hbmap,lpData,sizeof(HBITMAP));
+#endif
+
+ hdc = GetDC(hwnd);
+ hdcMem = CreateCompatibleDC(hdc);
+
+ if(!hdc||!hdcMem) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:NULL hdc (client)\r\n");
+ DdeUnaccessData(hData); //JOHNSP:CHANGE
+ if(hdc) ReleaseDC(hwndMain,hdc);
+ if(hdcMem) DeleteDC(hdcMem);
+ return 0;
+ }
+
+ if(!hbmap) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:NULL hbmap (client)\r\n");
+ DdeUnaccessData(hData); //JOHNSP:CHANGE
+ DeleteDC(hdcMem);
+ ReleaseDC(hwndMain,hdc);
+ return 0;
+ }
+
+ GetClientRect(hwnd,&r);
+ width=r.right-r.left;
+ height=r.bottom-r.top;
+
+ hobj=SelectObject(hdcMem,hbmap);
+ if(!hobj) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:SelectObject failed (client)\r\n");
+ DdeUnaccessData(hData); //JOHNSP:CHANGE
+ DeleteDC(hdcMem);
+ ReleaseDC(hwndMain,hdc);
+ return 0;
+ }
+
+ if(!BitBlt(hdc,0,0,width,height,hdcMem,0,0,SRCCOPY))
+ DDEMLERROR("DdeStrs.Exe -- ERR:BitBlt failed (client)\r\n");
+
+ hobj=SelectObject(hdcMem,hobj);
+ DeleteDC(hdcMem);
+ ReleaseDC(hwnd,hdc);
+
+ DdeUnaccessData(hData); //JOHNSP:CHANGE
+
+ return(TRUE);
+
+}
+
+#ifdef WIN32
+BOOL PokeTestItem_ENHMETA(
+HDDEDATA hData)
+{
+LPBYTE lpData;
+HWND hwnd;
+HDC hdc;
+HANDLE hemf;
+DWORD cbData;
+RECT r;
+
+ Balance(OFFSET_CLIENT);
+
+ hwnd=(HWND)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HWNDDISPLAY);
+ SetWindowText(hwnd,"Client - CF_ENHMETAFILE");
+
+ lpData = (LPBYTE) DdeAccessData( hData, &cbData );
+
+ hdc = GetDC(hwnd);
+ if(!hdc) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:NULL hdc (client)\r\n");
+ DdeUnaccessData(hData); //JOHNSP:CHANGE
+ return 0;
+ }
+
+#ifdef WIN32
+ memcpy(&hemf,lpData,sizeof(HANDLE));
+#else
+ _fmemcpy(&hemf,lpData,sizeof(HANDLE));
+#endif
+
+ GetClientRect(hwnd,&r);
+ if(!PlayEnhMetaFile(hdc,hemf,&r))
+ DDEMLERROR("DdeStrs.Exe -- ERR:PlayMetaFile failed (client)\r\n");
+
+ ReleaseDC(hwnd,hdc);
+
+ DdeUnaccessData(hData); //JOHNSP:CHANGE
+
+ return(TRUE);
+
+}
+#endif
+
+BOOL PokeTestItem_METAPICT(
+HDDEDATA hData)
+{
+LPBYTE lpData;
+HWND hwnd;
+HDC hdc;
+HANDLE hmf;
+LPMETAFILEPICT lpMfp;
+HANDLE hmem;
+DWORD cbData;
+
+ Balance(OFFSET_CLIENT);
+
+ hwnd=(HWND)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HWNDDISPLAY);
+ SetWindowText(hwnd,"Client - CF_METAFILEPICT");
+
+ lpData = (LPBYTE) DdeAccessData( hData, &cbData );
+
+ hdc = GetDC(hwnd);
+ if(!hdc) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:NULL hdc (client)\r\n");
+ DdeUnaccessData(hData); //JOHNSP:CHANGE
+ return 0;
+ }
+
+#ifdef WIN32
+ memcpy(&hmem,lpData,sizeof(HANDLE));
+#else
+ _fmemcpy(&hmem,lpData,sizeof(HANDLE));
+#endif
+
+ lpMfp=(LPMETAFILEPICT)GlobalLock(hmem);
+ hmf=lpMfp->hMF;
+
+ if(!PlayMetaFile(hdc,hmf))
+ DDEMLERROR("DdeStrs.Exe -- ERR:PlayMetaFile failed (client)\r\n");
+
+ ReleaseDC(hwnd,hdc);
+
+ DdeUnaccessData(hData); //JOHNSP:CHANGE
+
+ return(TRUE);
+
+}
+
+BOOL PokeTestItem_PALETTE(
+HDDEDATA hData)
+{
+LPBYTE lpData;
+HWND hwnd;
+HPALETTE hpal;
+HDC hdc;
+RECT r;
+HANDLE hobj;
+HANDLE hbrush;
+DWORD cbData;
+
+ Balance(OFFSET_CLIENT);
+
+ hwnd=(HWND)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HWNDDISPLAY);
+ SetWindowText(hwnd,"Client - CF_PALETTE");
+
+ lpData = (LPBYTE) DdeAccessData( hData, &cbData );
+
+ GetClientRect(hwnd,&r);
+
+ hdc=GetDC(hwnd);
+
+ if(!hdc) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:NULL hdc (client)\r\n");
+ DdeUnaccessData(hData); //JOHNSP:CHANGE
+ return 0;
+ }
+
+#ifdef WIN32
+ memcpy(&hpal,lpData,sizeof(HPALETTE));
+#else
+ _fmemcpy(&hpal,lpData,sizeof(HPALETTE));
+#endif
+
+ hobj=(HPALETTE)SelectPalette(hdc,hpal,FALSE);
+
+ if(!hobj) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:NULL hobj:SelectPalette failed (client)\r\n");
+ DdeUnaccessData(hData); //JOHNSP:CHANGE
+ ReleaseDC(hwnd,hdc);
+ return 0;
+ }
+
+ RealizePalette(hdc);
+
+ hbrush=CreateSolidBrush(PALETTEINDEX(0));
+ if(!hbrush) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:NULL hbrush ret from CreatSolidBrush (client)\r\n");
+ DdeUnaccessData(hData); //JOHNSP:CHANGE
+ SelectPalette(hdc,(HPALETTE)hobj,FALSE);
+ ReleaseDC(hwnd,hdc);
+ return 0;
+ }
+
+ FillRect(hdc,&r,hbrush);
+ DeleteObject(hbrush);
+
+ SelectPalette(hdc,(HPALETTE)hobj,FALSE);
+ ReleaseDC(hwnd,hdc);
+
+ DdeUnaccessData(hData); //JOHNSP:CHANGE
+
+ return(TRUE);
+
+}
+
+HDDEDATA RenderTestItem_Text(
+HDDEDATA hData)
+{
+HDC hdc;
+HBRUSH hBrush;
+PAINTSTRUCT ps;
+RECT rc;
+HDDEDATA hddedata;
+LONG l;
+HDDEDATA FAR *hAppOwned;
+HANDLE hmem;
+HWND hwndDisplay;
+
+ Balance(OFFSET_SERVER);
+
+ hwndDisplay=(HWND)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HWNDDISPLAY);
+ SetWindowText(hwndDisplay,"Server - CF_TEXT");
+
+ // if we are running app owned then we just reuse our
+ // last handle.
+
+ hmem=(HANDLE)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HAPPOWNED);
+ hAppOwned=(HDDEDATA FAR *)GlobalLock(hmem);
+
+ if(hAppOwned[TXT]!=0L) {
+ hddedata=hAppOwned[TXT];
+ GlobalUnlock(hmem);
+ return hddedata;
+ }
+
+ hdc=GetDC(hwndDisplay);
+ if(!hdc) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:NULL hdc ret from GetDC! (server)\r\n");
+ GlobalUnlock(hmem);
+ return 0;
+ }
+
+ hBrush=CreateSolidBrush(WHITE);
+ if(!hBrush) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:NULL hBrush ret from CreateSolidBrush! (server)\r\n");
+ EndPaint(hwndDisplay,&ps);
+ GlobalUnlock(hmem);
+ return 0;
+ }
+
+ GetClientRect(hwndDisplay,&rc);
+ FillRect(hdc,&rc,hBrush);
+ DeleteObject(hBrush);
+
+ DrawText(hdc, "Data:CF_TEXT format", -1, &rc, DT_LEFT|DT_TOP);
+ ReleaseDC(hwndDisplay,hdc);
+
+ hddedata=DdeAddData(hData, "Data:CF_TEXT format", 20, 0);
+
+ l=GetWindowLong(hwndMain,OFFSET_FLAGS);
+ if(l&FLAG_APPOWNED) {
+ hAppOwned[TXT]=hddedata;
+ }
+
+ GlobalUnlock(hmem);
+
+ return hddedata;
+}
+
+HDDEDATA RenderTestItem_DIB(
+HDDEDATA hData)
+{
+HWND hwnd;
+LONG length;
+HDC hdc,hdcMem;
+RECT r;
+INT width,height,dibhdr;
+HBITMAP hbmap;
+HANDLE hobj;
+LPBITMAPINFO lpbitinfo;
+LPBITMAPINFOHEADER lpbithdr;
+LPBYTE lpbits;
+LPBYTE lpdata;
+HDDEDATA hddedata;
+INT ip,ibpp;
+CHAR sz[100];
+LONG l;
+HDDEDATA FAR *hAppOwned;
+HANDLE hmem,hm;
+
+ Balance(OFFSET_SERVER);
+
+ hwnd=(HWND)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HWNDDISPLAY);
+ SetWindowText(hwnd,"Server - CF_DIB");
+
+ // if we are running app owned then we just reuse our
+ // last handle.
+
+ hmem=(HANDLE)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HAPPOWNED);
+ hAppOwned=(HDDEDATA FAR *)GlobalLock(hmem);
+
+ if(hAppOwned[DIB]!=0L) {
+ hddedata=hAppOwned[DIB];
+ GlobalUnlock(hmem);
+ return hddedata;
+ }
+
+ length = sizeof(HBITMAP);
+
+ hdc=GetDC(hwnd);
+ if(!hdc) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:NULL hdc (server)\r\n");
+ GlobalUnlock(hmem);
+ return 0;
+ }
+
+ ibpp=GetDeviceCaps(hdc,BITSPIXEL);
+ ip=GetDeviceCaps(hdc,PLANES);
+
+ hdcMem=CreateCompatibleDC(hdc);
+
+ if(!hdcMem) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:NULL hdc (server)\r\n");
+ ReleaseDC(hwnd,hdc);
+ GlobalUnlock(hmem);
+ return 0;
+ }
+
+ GetClientRect(hwnd,&r);
+ width=r.right-r.left;
+ height=r.bottom-r.top;
+
+ hbmap=CreateCompatibleBitmap(hdcMem,width,height);
+ if(!hbmap) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:NULL hbmap-CreateCompatibleBitmap failed (server)\r\n");
+ DeleteDC(hdcMem);
+ ReleaseDC(hwnd,hdc);
+ GlobalUnlock(hmem);
+ return 0;
+ }
+
+ hobj=SelectObject(hdcMem,hbmap);
+ if(!hobj) {
+ DDEMLERROR("DdeStrs.Exe -- ERR (Server), SelectObject failed\r\n");
+ DeleteObject(hbmap);
+ DeleteDC(hdcMem);
+ ReleaseDC(hwnd,hdc);
+ GlobalUnlock(hmem);
+ return 0;
+ }
+
+ if(!PatBlt(hdcMem,r.left,r.top,width,height,WHITENESS))
+ DDEMLERROR("DdeStrs.Exe -- ERR (Server), PatBlt failed\r\n");
+
+ // Deselect object (must be done according to docs)
+
+ hobj=SelectObject(hdcMem,hobj);
+ if(!hobj) DDEMLERROR("DdeStrs.Exe -- ERR (Server), SelectObject [call 2] failed\r\n");
+
+
+ // Set up for a monochrome bitmap.
+
+ dibhdr =sizeof(BITMAPINFO)+(sizeof(RGBQUAD));
+
+
+ // dib header plus area for raw bits
+
+ length =dibhdr+(((width*ibpp)+31)/32)*ip*height*4;
+
+ // Allocate memory for the DIB
+
+ hm=GlobalAlloc(GMEM_ZEROINIT|GMEM_DDESHARE,length);
+ if(!hm) {
+ DDEMLERROR("DdeStrs.Exe - RenderTestItem_DIB\r\n");
+ wsprintf(sz, "DdeStrs.Exe - GobalAlloc failed, allocation size = %d\r\n", length );
+ DDEMLERROR(&sz[0]);
+
+ DeleteObject(hbmap);
+ DeleteDC(hdcMem);
+ ReleaseDC(hwnd,hdc);
+ GlobalUnlock(hmem);
+ return 0;
+ }
+
+ lpdata=(LPBYTE)GlobalLock(hm);
+
+ lpbitinfo=(LPBITMAPINFO)lpdata;
+ lpbithdr=&(lpbitinfo->bmiHeader);
+
+ lpbits=lpdata+dibhdr;
+
+ lpbitinfo->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
+ lpbitinfo->bmiHeader.biWidth=width;
+ lpbitinfo->bmiHeader.biHeight=height;
+ lpbitinfo->bmiHeader.biPlanes=1;
+ lpbitinfo->bmiHeader.biBitCount=1;
+
+ // I allocated zero init memory so the other values should
+ // be 0 and will use the default.
+
+ if(!GetDIBits(hdcMem,
+ hbmap,
+ 0,
+ height,
+ lpbits,
+ lpbitinfo,
+ DIB_RGB_COLORS))
+ {
+ DDEMLERROR("DdeStrs.Exe -- ERR (Server), GetDIBits failed\r\n");
+ }
+
+ SetDIBitsToDevice(hdc,
+ 0,
+ 0,
+ (UINT)lpbitinfo->bmiHeader.biWidth,
+ (UINT)lpbitinfo->bmiHeader.biHeight,
+ 0,
+ 0,
+ 0,
+ (UINT)(lpbitinfo->bmiHeader.biHeight),
+ lpbits,
+ lpbitinfo,
+ DIB_RGB_COLORS);
+
+ hddedata=DdeAddData(hData, &hm, sizeof(HANDLE), 0);
+
+ GlobalUnlock(hm);
+
+ DeleteObject(hbmap);
+
+ DeleteDC(hdcMem);
+ ReleaseDC(hwnd,hdc);
+
+ l=GetWindowLong(hwndMain,OFFSET_FLAGS);
+ if(l&FLAG_APPOWNED) {
+ hAppOwned[DIB]=hddedata;
+ }
+
+ GlobalUnlock(hmem);
+
+ return hddedata;
+}
+
+HDDEDATA RenderTestItem_BITMAP(
+HDDEDATA hData)
+{
+HWND hwnd;
+LONG length;
+HDC hdc,hdcMem;
+RECT r;
+INT width,height;
+HBITMAP hbmap;
+HANDLE hobj;
+HDDEDATA hddedata;
+DWORD d;
+LPBYTE lpdata=(LPBYTE)&d;
+LONG l;
+HDDEDATA FAR *hAppOwned;
+HANDLE hmem;
+
+ Balance(OFFSET_SERVER);
+
+ hwnd=(HWND)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HWNDDISPLAY);
+ SetWindowText(hwnd,"Server - CF_BITMAP");
+
+ // if we are running app owned then we just reuse our
+ // last handle.
+
+ hmem=(HANDLE)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HAPPOWNED);
+ hAppOwned=(HDDEDATA FAR *)GlobalLock(hmem);
+
+ if(hAppOwned[BITMAP]!=0L) {
+ hddedata=hAppOwned[BITMAP];
+ GlobalUnlock(hmem);
+ return hddedata;
+ }
+
+ length = sizeof(HBITMAP);
+
+ hdc=GetDC(hwnd);
+ hdcMem=CreateCompatibleDC(hdc);
+
+ if(!hdc) {
+ DDEMLERROR("DdeStrs.Exe -- ERR (Server), NULL hdc\r\n");
+ GlobalUnlock(hmem);
+ return 0;
+ }
+
+ if(!hdcMem) {
+ DDEMLERROR("DdeStrs.Exe -- ERR (Server), NULL hdc\r\n");
+ ReleaseDC(hwnd,hdc);
+ GlobalUnlock(hmem);
+ return 0;
+ }
+
+ GetClientRect(hwnd,&r);
+ width=r.right-r.left;
+ height=r.bottom-r.top;
+
+ hbmap=CreateCompatibleBitmap(hdcMem,width,height);
+ if(!hbmap) {
+ DDEMLERROR("DdeStrs.Exe -- ERR (Server), NULL hbmap\r\n");
+ DeleteDC(hdcMem);
+ ReleaseDC(hwnd,hdc);
+ GlobalUnlock(hmem);
+ return 0;
+ }
+
+ hobj=SelectObject(hdcMem,hbmap);
+
+ if(!hobj) {
+ DDEMLERROR("DdeStrs.Exe -- ERR (Server), SelectObject failed\r\n");
+ DeleteObject(hbmap);
+ DeleteDC(hdcMem);
+ ReleaseDC(hwnd,hdc);
+ GlobalUnlock(hmem);
+ return 0;
+ }
+
+ if(!PatBlt(hdcMem,r.left,r.top,width,height,WHITENESS))
+ DDEMLERROR("DdeStrs.Exe -- ERR (Server), PatBlt failed\r\n");
+
+ if(!BitBlt(hdc,0,0,width,height,hdcMem,0,0,SRCCOPY))
+ DDEMLERROR("DdeStrs.Exe -- ERR (Server), BitBlt failed\r\n");
+
+#ifdef WIN32
+ memcpy(lpdata,&hbmap,(INT)length);
+#else
+ _fmemcpy(lpdata,&hbmap,(INT)length);
+#endif
+
+ hddedata=DdeAddData(hData, lpdata, length, 0);
+
+ // Object will be deleted by client! Not server.
+
+ SelectObject(hdcMem,hobj);
+ DeleteDC(hdcMem);
+ ReleaseDC(hwnd,hdc);
+
+ l=GetWindowLong(hwndMain,OFFSET_FLAGS);
+ if(l&FLAG_APPOWNED) {
+ hAppOwned[BITMAP]=hddedata;
+ }
+
+ GlobalUnlock(hmem);
+
+ return hddedata;
+}
+
+#ifdef WIN32
+HDDEDATA RenderTestItem_ENHMETA(
+HDDEDATA hData)
+{
+HWND hwnd;
+HDDEDATA hddedata;
+HDC hdc,hdcMem;
+INT width,height,length;
+RECT r;
+HANDLE hemf;
+DWORD d;
+LPBYTE lpdata=(LPBYTE)&d;
+LONG l;
+HDDEDATA FAR *hAppOwned;
+HANDLE hmem;
+
+#ifdef WIN32
+XFORM xp;
+LPXFORM lpxform=&xp;
+#endif
+
+ Balance(OFFSET_SERVER);
+
+ hwnd=GetThreadLong(GETCURRENTTHREADID(),OFFSET_HWNDDISPLAY);
+ SetWindowText(hwnd,"Server - CF_ENHMETAFILE");
+
+ // if we are running app owned then we just reuse our
+ // last handle.
+
+ hmem=(HANDLE)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HAPPOWNED);
+ hAppOwned=GlobalLock(hmem);
+
+ if(hAppOwned[ENHMETA]!=0L) {
+ hddedata=hAppOwned[ENHMETA];
+ GlobalUnlock(hmem);
+ return hddedata;
+ }
+
+ hdc=GetDC(hwnd); //JOHNSP:CHANGE - below few lines
+
+ if(!hdc) {
+ DDEMLERROR("DdeStrs.Exe -- ERR (Server), NULL hdc\r\n");
+ GlobalUnlock(hmem);
+ return 0;
+ }
+
+ hdcMem=CreateEnhMetaFile(hdc,NULL,NULL,NULL);
+
+ if(!hdcMem) {
+ DDEMLERROR("DdeStrs.Exe -- ERR (Server), NULL hdc\r\n");
+ ReleaseDC(hwnd,hdc);
+ GlobalUnlock(hmem);
+ return 0;
+ }
+
+ length=sizeof(HANDLE);
+
+ GetClientRect(hwnd,&r);
+ width=r.right-r.left;
+ height=r.bottom-r.top;
+
+ if(!PatBlt(hdcMem,r.left,r.top,width,height,WHITENESS))
+ DDEMLERROR("DdeStrs.Exe -- ERR:PatBlt failed (server)\r\n");
+
+ hemf=CloseEnhMetaFile(hdcMem);
+ if(!hemf) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:CloseEnhMetaFile failed (server)\r\n");
+ ReleaseDC(hwnd,hdc);
+ GlobalUnlock(hmem);
+ return 0;
+ }
+
+#ifdef WIN32
+ memcpy(lpdata,&hemf,length);
+#else
+ _fmemcpy(lpdata,&hemf,length);
+#endif
+
+ if(!PlayEnhMetaFile(hdc,hemf,&r))
+ DDEMLERROR("DdeStrs.Exe -- ERR:PlayEnhMetaFile failed (server)\r\n");
+
+ hddedata=DdeAddData(hData, lpdata, length, 0);
+
+ ReleaseDC(hwnd,hdc);
+
+ l=GetWindowLong(hwndMain,OFFSET_FLAGS);
+ if(l&FLAG_APPOWNED) {
+ hAppOwned[ENHMETA]=hddedata;
+ }
+
+ GlobalUnlock(hmem);
+
+ return hddedata;
+
+}
+#endif
+
+HDDEDATA RenderTestItem_METAPICT(
+HDDEDATA hData)
+{
+HWND hwnd;
+HDDEDATA hddedata;
+HDC hdc,hdcMem;
+INT width,height,length;
+RECT r;
+HANDLE hmf;
+LPMETAFILEPICT lpMfp;
+DWORD d;
+LPBYTE lpdata=(LPBYTE)&d;
+CHAR sz[100];
+LONG l;
+HDDEDATA FAR *hAppOwned;
+HANDLE hmem,hm;
+
+ Balance(OFFSET_SERVER);
+
+ hwnd=(HWND)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HWNDDISPLAY);
+ SetWindowText(hwnd,"Server - CF_METAFILEPICT");
+
+ // if we are running app owned then we just reuse our
+ // last handle.
+
+ hmem=(HANDLE)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HAPPOWNED);
+ hAppOwned=(HDDEDATA FAR *)GlobalLock(hmem);
+
+ if(hAppOwned[METAPICT]!=0L) {
+ hddedata=hAppOwned[METAPICT];
+ GlobalUnlock(hmem);
+ return hddedata;
+ }
+
+ hdcMem=CreateMetaFile(NULL);
+ if(!hdcMem) {
+ DDEMLERROR("DdeStrs.Exe -- ERR: NULL hdc ret from CreateMetaFile, (Server)\r\n");
+ GlobalUnlock(hmem);
+ return 0;
+ }
+
+ length=sizeof(HANDLE);
+
+ GetClientRect(hwnd,&r);
+ width=r.right-r.left;
+ height=r.bottom-r.top;
+
+ if(!PatBlt(hdcMem,r.left,r.top,width,height,WHITENESS))
+ DDEMLERROR("DdeStrs.Exe -- ERR:PatBlt failed (server)\r\n");
+
+ hmf=CloseMetaFile(hdcMem);
+ if(!hmf) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:NULL hmf ret CloseMetaFile! (Server)\r\n");
+ GlobalUnlock(hmem);
+ return 0;
+ }
+
+ hm=GlobalAlloc(GMEM_ZEROINIT|GMEM_DDESHARE,sizeof(METAFILEPICT));
+ if(!hm) {
+ DDEMLERROR("DdeStrs.Exe - RenderTestItem_METAPICT\r\n");
+ wsprintf(sz, "DdeStrs.Exe - GlobalAlloc failed, allocation size = %d\r\n", sizeof(METAFILEPICT) );
+ DDEMLERROR(&sz[0]);
+ DeleteMetaFile(hmf); //JOHNSP:CHANGE
+ GlobalUnlock(hmem);
+ return 0;
+ }
+
+ lpMfp=(LPMETAFILEPICT)GlobalLock(hm);
+
+ lpMfp->mm = MM_TEXT;
+ lpMfp->xExt = width;
+ lpMfp->yExt = height;
+ lpMfp->hMF = hmf;
+
+ GlobalUnlock(hm);
+
+#ifdef WIN32
+ memcpy(lpdata,&hm,length);
+#else
+ _fmemcpy(lpdata,&hm,length);
+#endif
+
+ hdc=GetDC(hwnd);
+ if(!hdc) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:NULL hdc ret from GetDC, (Server)\r\n");
+ GlobalFree(hm); //JOHNSP:CHANGE
+ DeleteMetaFile(hmf); //JOHNSP:CHANGE
+ GlobalUnlock(hmem);
+ return 0;
+ }
+ else {
+ hddedata=DdeAddData(hData, lpdata, length, 0); //JOHNSP:CHANGE
+ PlayMetaFile(hdc,hmf);
+ ReleaseDC(hwnd,hdc);
+ }
+
+ l=GetWindowLong(hwndMain,OFFSET_FLAGS);
+ if(l&FLAG_APPOWNED) {
+ hAppOwned[METAPICT]=hddedata;
+ }
+
+ GlobalUnlock(hmem);
+
+ return hddedata;
+
+}
+
+HDDEDATA RenderTestItem_PALETTE(
+HDDEDATA hData)
+{
+HWND hwnd;
+HPALETTE hpal;
+LPLOGPALETTE lppal;
+HDDEDATA hddedata;
+INT length;
+DWORD d;
+LPBYTE lpdata=(LPBYTE)&d;
+CHAR sz[100];
+LONG l;
+HDDEDATA FAR *hAppOwned;
+HANDLE hmem,hm;
+
+HDC hdc;
+HANDLE hobj;
+HANDLE hbrush;
+RECT r;
+
+
+ Balance(OFFSET_SERVER);
+
+ hwnd=(HWND)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HWNDDISPLAY);
+ SetWindowText(hwnd,"Server - CF_PALETTE");
+
+ // if we are running app owned then we just reuse our
+ // last handle.
+
+ hmem=(HANDLE)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HAPPOWNED);
+ hAppOwned=(HDDEDATA FAR *)GlobalLock(hmem);
+
+ if(hAppOwned[PALETTE]!=0L) {
+ hddedata=hAppOwned[PALETTE];
+ GlobalUnlock(hmem);
+ return hddedata;
+ }
+
+ length=sizeof(LOGPALETTE)+sizeof(PALETTEENTRY);
+
+ lppal=(LPLOGPALETTE)GetMem(length,&hm);
+
+ if(!hm) {
+ DDEMLERROR("DdeStrs.Exe - RenderTestItem_PALETTE\r\n");
+ wsprintf(sz, "DdeStrs.Exe - GlobalAlloc failed, allocation size = %d\r\n", length );
+ DDEMLERROR(&sz[0]);
+ GlobalUnlock(hmem);
+ return 0;
+ }
+
+ lppal->palNumEntries=1;
+ lppal->palVersion=0x0300;
+
+ lppal->palPalEntry[0].peRed =(BYTE)255;
+ lppal->palPalEntry[0].peGreen=(BYTE)255;
+ lppal->palPalEntry[0].peBlue =(BYTE)255;
+ lppal->palPalEntry[0].peFlags=(BYTE)0;
+
+ hpal=CreatePalette(lppal);
+ if(!hpal) {
+ DDEMLERROR("DdeStrs.Exe - NULL hpal ret CreatePalette! (server)\r\n");
+ FreeMem(hm);
+ GlobalUnlock(hmem);
+ return 0;
+ }
+
+ FreeMem(hm);
+
+#ifdef WIN32
+ memcpy(lpdata,&hpal,sizeof(HANDLE));
+#else
+ _fmemcpy(lpdata,&hpal,sizeof(HANDLE));
+#endif
+
+ hddedata=DdeAddData(hData, lpdata, sizeof(HPALETTE), 0);
+
+ // Show that palette works.
+
+ // NOTE: From here down if we get a failure we don't abort but
+ // return hddedata to pass to the client. More basically if
+ // an error is encountered below it only affects the display
+ // on the server side!
+
+ GetClientRect(hwnd,&r);
+
+ hdc=GetDC(hwnd);
+
+ if(!hdc) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:Null hdc (client)\r\n");
+ return hddedata;
+ }
+
+ hobj=(HPALETTE)SelectPalette(hdc,hpal,FALSE);
+
+ if(!hobj) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:Null hobj:SelectPalette failed (client)\r\n");
+ ReleaseDC(hwnd,hdc);
+ return hddedata;
+ }
+
+ RealizePalette(hdc);
+
+ hbrush=CreateSolidBrush(PALETTEINDEX(0));
+ if(!hbrush) {
+ DDEMLERROR("DdeStrs.Exe -- ERR:Null hbrush ret from CreatSolidBrush (client)\r\n");
+ SelectPalette(hdc,(HPALETTE)hobj,FALSE);
+ ReleaseDC(hwnd,hdc);
+ return hddedata;
+ }
+
+ FillRect(hdc,&r,hbrush);
+ DeleteObject(hbrush);
+
+ SelectPalette(hdc,(HPALETTE)hobj,FALSE);
+ ReleaseDC(hwnd,hdc);
+
+ // if we are running appowned, save first created handle
+ // away for futher use.
+
+ l=GetWindowLong(hwndMain,OFFSET_FLAGS);
+ if(l&FLAG_APPOWNED) {
+ hAppOwned[PALETTE]=hddedata;
+ }
+
+ GlobalUnlock(hmem);
+
+ return hddedata;
+
+}
+
+BOOL Execute(
+HDDEDATA hData)
+{
+ LPSTR psz,psz2;
+ BOOL fRet = FALSE;
+ LONG cServerhConvs;
+ int i;
+ HANDLE hmem;
+ HCONV FAR *pServerhConvs;
+
+ psz = DdeAccessData(hData, NULL);
+
+#ifdef WIN16
+ if (!_fstricmp(psz, szExecDie)) {
+#else
+ if (!stricmp(psz, szExecDie)) {
+#endif
+ psz2=(LPSTR)-1;
+ *psz; // GP Fault!
+ fRet = TRUE;
+
+#ifdef WIN16
+ } else if (!_fstricmp(psz, szExecRefresh)) {
+#else
+ } else if (!stricmp(psz, szExecRefresh)) {
+#endif
+
+ if (!DdePostAdvise(GetThreadLong(GETCURRENTTHREADID(),OFFSET_IDINST), 0, 0)) {
+ DDEMLERROR("DdeStrs.Exe -- ERR DdePostAdvise failed\r\n");
+ }
+ fRet = TRUE;
+
+#ifdef WIN16
+ } else if (!_fstricmp(psz, szExecDisconnect)) {
+#else
+ } else if (!stricmp(psz, szExecDisconnect)) {
+#endif
+
+ cServerhConvs=(INT)GetThreadLong(GETCURRENTTHREADID(),OFFSET_CSERVERCONVS);
+ hmem=(HANDLE)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HSERVERCONVS);
+ pServerhConvs=(HCONV FAR *)GlobalLock(hmem);
+
+ for (i = 0; i < cServerhConvs; i++) {
+ if (!DdeDisconnect(pServerhConvs[i])) {
+ DDEMLERROR("DdeStrs.Exe -- ERR DdeDisconnect failed\r\n");
+ }
+ }
+
+ GlobalUnlock(hmem);
+
+ SetThreadLong(GETCURRENTTHREADID(),OFFSET_CSERVERCONVS,0L);
+ UpdateCount(hwndMain,OFFSET_SERVER_CONNECT,PNT);
+ fRet = TRUE;
+ }
+ DdeUnaccessData(hData);
+ return(fRet);
+}
+
+VOID PaintServer(
+HWND hwnd,
+PAINTSTRUCT *pps)
+{
+ RECT rc;
+ static CHAR szT[40];
+
+ GetClientRect(hwnd, &rc);
+
+ if (fServer) {
+ rc.left += (rc.right - rc.left) >> 1; // server info is on right half
+ }
+ rc.bottom = rc.top + cyText;
+
+ wsprintf(szT, "%d server connections", GetThreadLong(GETCURRENTTHREADID(),OFFSET_CSERVERCONVS));
+ DrawText(pps->hdc, szT, -1, &rc, DT_RIGHT);
+ OffsetRect(&rc, 0, cyText);
+
+ wsprintf(szT, "%d server count", GetWindowLong(hwnd,OFFSET_SERVER));
+ DrawText(pps->hdc, szT, -1, &rc, DT_RIGHT);
+ OffsetRect(&rc, 0, cyText);
+
+}
+
+
+HDDEDATA FAR PASCAL CustomCallback(
+UINT wType,
+UINT wFmt,
+HCONV hConv,
+HSZ hsz1,
+HSZ hsz2,
+HDDEDATA hData,
+DWORD dwData1,
+DWORD dwData2)
+{
+ LONG cServerhConvs,cClienthConvs;
+ int i;
+ HANDLE hmem;
+ HCONV FAR *pServerhConvs;
+ HCONV hC;
+ HCONVLIST hConvList=0;
+ DWORD dwid;
+ LONG lflags;
+
+
+ dwid=GETCURRENTTHREADID();
+ cServerhConvs=(INT)GetThreadLong(dwid,OFFSET_CSERVERCONVS);
+
+ switch (wType) {
+ case XTYP_CONNECT_CONFIRM:
+
+ hmem=(HANDLE)GetThreadLong(dwid,OFFSET_HSERVERCONVS);
+ pServerhConvs=(HCONV FAR *)GlobalLock(hmem);
+
+ pServerhConvs[cServerhConvs] = hConv;
+ cServerhConvs++;
+ SetThreadLong(dwid,OFFSET_CSERVERCONVS,cServerhConvs);
+ UpdateCount(hwndMain,OFFSET_SERVER_CONNECT,PNT);
+ if (cServerhConvs >= MAX_SERVER_HCONVS) {
+ LOGDDEMLERROR("DdeStrs.Exe -- ERR-Number of connections > MAX\r\n");
+ cServerhConvs--;
+ SetThreadLong(dwid,OFFSET_CSERVERCONVS,cServerhConvs);
+ UpdateCount(hwndMain,OFFSET_SERVER_CONNECT,PNT);
+ }
+ GlobalUnlock(hmem);
+ break;
+
+ case XTYP_DISCONNECT:
+
+ if(fServer)
+ {
+
+ hmem=(HANDLE)GetThreadLong(dwid,OFFSET_HSERVERCONVS);
+ pServerhConvs=(HCONV FAR *)GlobalLock(hmem);
+
+ for (i = 0; i < cServerhConvs; i++)
+ {
+
+ if (pServerhConvs[i] == hConv)
+ {
+ cServerhConvs--;
+ SetThreadLong(dwid,OFFSET_CSERVERCONVS,cServerhConvs);
+ UpdateCount(hwndMain,OFFSET_SERVER_CONNECT,PNT);
+
+ for (; i < cServerhConvs; i++)
+ {
+ pServerhConvs[i] = pServerhConvs[i+1];
+ } // for
+
+ break;
+
+ } // if pServerhConvs
+
+ } // for i
+
+ GlobalUnlock(hmem);
+
+ } // fServer
+
+ // If the server is shutting down the conversation then we need
+ // to change our client connection count. Remember that the
+ // current conversation is valid until we return from this callback
+ // so don't count the current conversation.
+
+ if(fClient)
+ {
+
+ // *** Count Client Connections ****
+
+ cClienthConvs = 0;
+ hConvList=GetThreadLong(dwid,OFFSET_HCONVLIST);
+
+ if (hConvList)
+ {
+ hC = 0;
+ while (hC = DdeQueryNextServer(hConvList, hC))
+ {
+ if (hC!=hConv) cClienthConvs++;
+ } // while
+
+ } // if hConvList
+
+ SetThreadLong(dwid,OFFSET_CCLIENTCONVS,cClienthConvs);
+
+ } // if fClient
+
+ InvalidateRect(hwndMain, NULL, TRUE);
+
+ break;
+
+ case XTYP_REGISTER:
+ case XTYP_UNREGISTER:
+ lflags=GetWindowLong(hwndMain,OFFSET_FLAGS);
+ if(fClient && (FLAG_STOP!=(lflags&FLAG_STOP)))
+ {
+ ReconnectList();
+ }
+ break;
+ }
+
+ return(0);
+}
+
+BOOL Balance( INT itype ) {
+
+ if(itype==OFFSET_SERVER) {
+ UpdateCount(hwndMain,OFFSET_SERVER,INC);
+ }
+ else {
+ UpdateCount(hwndMain,OFFSET_CLIENT,INC);
+ }
+
+ return TRUE;
+
+}
+
diff --git a/private/mvdm/wow16/ddeml/tests/ddestrs/sources b/private/mvdm/wow16/ddeml/tests/ddestrs/sources
new file mode 100644
index 000000000..03153145f
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/ddestrs/sources
@@ -0,0 +1,24 @@
+MAJORCOMP=test
+MINORCOMP=ddestrs
+
+TARGETNAME=ddestrs
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+TARGETLIBS=
+
+INCLUDES=.
+
+SOURCES=ddestrs.c ddestrs.rc client.c server.c globals.c wrapper.c cmdln.c
+
+C_DEFINES=-DWIN32
+
+!if 0
+NTDEBUG=ntsd
+NTDEBUGTYPE=windbg
+386_OPTIMIZATION=/Od
+!endif
+
+UMTYPE=windows
+UMAPPL=ddestrs
+UMENTRY=winmain
+UMLIBS=obj\*\ddestrs.lib obj\*\ddestrs.res
diff --git a/private/mvdm/wow16/ddeml/tests/ddestrs/wrapper.c b/private/mvdm/wow16/ddeml/tests/ddestrs/wrapper.c
new file mode 100644
index 000000000..f477f76cf
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/ddestrs/wrapper.c
@@ -0,0 +1,793 @@
+/***************************************************************************\
+
+ PROGRAM : wrapper.c
+
+ PURPOSE : This is not a full program but a module you can include
+ in your code. It implements a standard DDEML callback
+ function that allows you to have most of your DDE table
+ driven. The default callback function handles all basic
+ System Topic information based on the tables you give
+ to this app.
+
+ LIMITATIONS : This only supports servers that:
+ have only one service name
+ have enumerable topics and items
+ do not change the topics or items they support over time.
+
+
+ EXPORTED ROUTINES:
+
+ InitializeDDE()
+ Use this to initialize the callback function tables and the DDEML
+
+ UninitializeDDE()
+ Use this to cleanup this module and uninitialize the DDEML instance.
+
+\***************************************************************************/
+
+#include <windows.h>
+#include <ddeml.h>
+#include <string.h>
+#include "wrapper.h"
+#include <port1632.h>
+#include "ddestrs.h"
+
+extern BOOL fServer;
+extern LPSTR pszNetName;
+extern LONG SetThreadLong(DWORD,INT,LONG);
+extern LONG GetThreadLong(DWORD,INT);
+extern LPSTR TStrCpy( LPSTR, LPSTR);
+
+BOOL InExit(VOID);
+VOID InitHszs(LPDDESERVICETBL psi);
+UINT GetFormat(LPSTR pszFormat);
+VOID FreeHszs(LPDDESERVICETBL psi);
+HDDEDATA APIENTRY WrapperCallback(UINT wType, UINT wFmt, HCONV hConv, HSZ hsz1,
+ HSZ hsz2, HDDEDATA hData, DWORD dwData1, DWORD dwData2);
+
+BOOL DoCallback(HCONV,HSZ,HSZ,UINT,UINT,HDDEDATA,LPDDESERVICETBL,HDDEDATA *);
+
+HDDEDATA ReqItems(HDDEDATA hDataOut, LPDDETOPICTBL ptpc);
+HDDEDATA AddReqFormat(HDDEDATA hDataOut, LPSTR pszFmt);
+HDDEDATA ReqFormats(HDDEDATA hDataOut, LPDDETOPICTBL ptpc);
+HDDEDATA DoWildConnect(HSZ hszTopic);
+
+PFNCALLBACK lpfnUserCallback = NULL;
+PFNCALLBACK lpfnWrapperCallback = NULL;
+
+LPDDESERVICETBL pasi = NULL;
+char tab[] = "\t";
+
+#define FOR_EACH_TOPIC(psvc, ptpc, i) for (i = 0, ptpc=(psvc)->topic; i < (int)(psvc)->cTopics; i++, ptpc++)
+#define FOR_EACH_ITEM(ptpc, pitm, i) for (i = 0, pitm=(ptpc)->item; i < (int)(ptpc)->cItems; i++, pitm++)
+#define FOR_EACH_FORMAT(pitm, pfmt, i) for (i = 0, pfmt=(pitm)->fmt; i < (int)(pitm)->cFormats;i++, pfmt++)
+
+
+
+/* STANDARD PREDEFINED FORMATS */
+
+#ifdef WIN32
+#define CSTDFMTS 14
+#else
+#define CSTDFMTS 12
+#endif
+
+struct {
+ UINT wFmt;
+ PSTR pszFmt;
+} StdFmts[CSTDFMTS] = {
+ { CF_TEXT , "TEXT" } ,
+ { CF_BITMAP , "BITMAP" } ,
+ { CF_METAFILEPICT, "METAFILEPICT" } ,
+ { CF_SYLK , "SYLK" } ,
+ { CF_DIF , "DIF" } ,
+ { CF_TIFF , "TIFF" } ,
+ { CF_OEMTEXT , "OEMTEXT" } ,
+ { CF_DIB , "DIB" } ,
+ { CF_PALETTE , "PALETTE" } ,
+ { CF_PENDATA , "PENDATA" } ,
+ { CF_RIFF , "RIFF" } ,
+ { CF_WAVE , "WAVE" } ,
+#ifdef WIN32
+ { CF_UNICODETEXT , "UNICODETEXT" } ,
+ { CF_ENHMETAFILE , "ENHMETAFILE" } ,
+#endif
+};
+
+
+
+HDDEDATA SysReqTopics(HDDEDATA hDataOut);
+HDDEDATA SysReqSysItems(HDDEDATA hDataOut);
+HDDEDATA SysReqFormats(HDDEDATA hDataOut);
+
+ /* STANDARD SERVICE INFO TABLES */
+
+DDEFORMATTBL StdSvcSystopicTopicsFormats[] = {
+ "TEXT", 0, 0, NULL, SysReqTopics
+};
+
+DDEFORMATTBL StdSvcSystopicSysitemsFormats[] = {
+ "TEXT", 0, 0, NULL, SysReqSysItems
+};
+
+DDEFORMATTBL StdSvcSystopicFormatsFormats[] = {
+ "TEXT", 0, 0, NULL, SysReqFormats
+};
+
+#define ITPC_TOPICS 0
+#define ITPC_SYSITEMS 1
+#define ITPC_FORMATS 2
+#define ITPC_ITEMLIST 3
+
+#define ITPC_COUNT 4
+
+DDEITEMTBL StdSvcSystopicItems[] = {
+ { SZDDESYS_ITEM_TOPICS, 0, 1, 0, StdSvcSystopicTopicsFormats },
+ { SZDDESYS_ITEM_SYSITEMS, 0, 1, 0, StdSvcSystopicSysitemsFormats },
+ { SZDDESYS_ITEM_FORMATS, 0, 1, 0, StdSvcSystopicFormatsFormats },
+ { SZDDE_ITEM_ITEMLIST, 0, 1, 0, StdSvcSystopicSysitemsFormats },
+};
+
+DDETOPICTBL StdSvc[] = {
+ SZDDESYS_TOPIC, 0, ITPC_COUNT, 0, StdSvcSystopicItems
+};
+
+DDESERVICETBL SSI = {
+ NULL, 0, 1, 0, StdSvc
+};
+
+/*********************************************************************/
+
+
+BOOL InitializeDDE(
+PFNCALLBACK lpfnCustomCallback,
+LPDWORD pidInst,
+LPDDESERVICETBL AppSvcInfo,
+DWORD dwFilterFlags,
+HANDLE hInst)
+{
+DWORD idI=0;
+
+ if (lpfnCustomCallback) {
+ lpfnUserCallback = (PFNCALLBACK)MakeProcInstance((FARPROC)lpfnCustomCallback, hInst);
+ }
+ lpfnWrapperCallback = (PFNCALLBACK)MakeProcInstance((FARPROC)WrapperCallback, hInst);
+
+ if (DdeInitialize(&idI, lpfnWrapperCallback, dwFilterFlags, 0)) {
+ SetThreadLong(GETCURRENTTHREADID(),OFFSET_IDINST,idI);
+ if (lpfnCustomCallback) {
+ FreeProcInstance((FARPROC)lpfnUserCallback);
+ }
+ FreeProcInstance((FARPROC)lpfnWrapperCallback);
+ return(FALSE);
+ }
+ else SetThreadLong(GETCURRENTTHREADID(),OFFSET_IDINST,idI);
+ *pidInst = idI;
+ InitHszs(AppSvcInfo);
+ InitHszs(&SSI);
+ pasi = AppSvcInfo;
+
+ if (fServer) {
+ DdeNameService(idI, pasi->hszService, 0, DNS_REGISTER);
+ }
+
+ return(TRUE);
+}
+
+
+
+VOID InitHszs(
+LPDDESERVICETBL psi)
+{
+ int iTopic, iItem, iFmt;
+ LPDDETOPICTBL ptpc;
+ LPDDEITEMTBL pitm;
+ LPDDEFORMATTBL pfmt;
+ DWORD idI;
+ CHAR sz[120];
+ LPBYTE psz;
+ LPBYTE pNet;
+
+ pNet=pszNetName;
+
+ idI=GetThreadLong(GETCURRENTTHREADID(),OFFSET_IDINST);
+
+ if (psi->pszService) {
+
+ // This area of code inplements the clients ability
+ // to see net drives. This is the -n option.
+
+ if(pNet)
+ {
+
+ sz[0]='\\';
+ sz[1]='\\';
+ psz=&sz[2];
+
+ psz=TStrCpy(psz,pNet);
+
+ while(*++psz!='\0');
+
+ *psz++='\\';
+
+ psz=TStrCpy(psz,psi->pszService);
+ psz=&sz[0];
+
+ psi->hszService = DdeCreateStringHandle(idI, psz, 0);
+
+ } // pNet
+
+ else psi->hszService = DdeCreateStringHandle(idI, psi->pszService, 0);
+ }
+ FOR_EACH_TOPIC(psi, ptpc, iTopic) {
+ ptpc->hszTopic = DdeCreateStringHandle(idI, ptpc->pszTopic, 0);
+ FOR_EACH_ITEM(ptpc, pitm, iItem) {
+ pitm->hszItem = DdeCreateStringHandle(idI, pitm->pszItem, 0);
+ FOR_EACH_FORMAT(pitm, pfmt, iFmt) {
+ pfmt->wFmt = GetFormat(pfmt->pszFormat);
+ }
+ }
+ }
+}
+
+
+/*
+ * This function allows apps to use standard CF_ formats. The string
+ * given may be in the StdFmts[] table.
+ */
+
+UINT GetFormat(
+LPSTR pszFormat)
+{
+ int iFmt;
+
+ for (iFmt = 0; iFmt < CSTDFMTS; iFmt++) {
+ if (!lstrcmp(pszFormat, StdFmts[iFmt].pszFmt)) {
+ return(StdFmts[iFmt].wFmt);
+ }
+ }
+ return(RegisterClipboardFormat(pszFormat));
+}
+
+
+
+VOID UninitializeDDE()
+{
+DWORD idI;
+
+ if (pasi == NULL) {
+ return;
+ }
+
+ idI=GetThreadLong(GETCURRENTTHREADID(),OFFSET_IDINST);
+
+ DdeNameService(idI, pasi->hszService, 0, DNS_UNREGISTER);
+ FreeHszs(pasi);
+ FreeHszs(&SSI);
+ DdeUninitialize(idI);
+ if (lpfnUserCallback) {
+ FreeProcInstance((FARPROC)lpfnUserCallback);
+ }
+ FreeProcInstance((FARPROC)lpfnWrapperCallback);
+}
+
+
+
+VOID FreeHszs(
+LPDDESERVICETBL psi)
+{
+ int iTopic, iItem;
+ LPDDETOPICTBL ptpc;
+ LPDDEITEMTBL pitm;
+ DWORD idI;
+
+ idI=GetThreadLong(GETCURRENTTHREADID(),OFFSET_IDINST);
+
+ DdeFreeStringHandle(idI, psi->hszService);
+ FOR_EACH_TOPIC(psi, ptpc, iTopic) {
+ DdeFreeStringHandle(idI, ptpc->hszTopic);
+ FOR_EACH_ITEM(ptpc, pitm, iItem) {
+ DdeFreeStringHandle(idI, pitm->hszItem);
+ }
+ }
+}
+
+BOOL InExit( VOID ) {
+LONG l;
+
+ if(!IsWindow((HWND)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HWNDDISPLAY))) {
+ DDEMLERROR("DdeStrs.Exe -- INF:Invalid hwndDisplay, returning NAck!\r\n");
+ return TRUE;
+ }
+
+ if(!IsWindow(hwndMain)) {
+ DDEMLERROR("DdeStrs.Exe -- INF:Invalid hwndMain, returning NAck!\r\n");
+ return TRUE;
+ }
+
+ // No need for error message on this one. This is expected to happen
+ // when queues fill up under extreme conditions.
+
+ l=GetWindowLong(hwndMain,OFFSET_FLAGS);
+ if(l&FLAG_STOP) {
+ return TRUE;
+ }
+
+ return FALSE;
+
+}
+
+HDDEDATA APIENTRY WrapperCallback(
+UINT wType,
+UINT wFmt,
+HCONV hConv,
+HSZ hsz1,
+HSZ hsz2,
+HDDEDATA hData,
+DWORD dwData1,
+DWORD dwData2)
+{
+ HDDEDATA hDataRet;
+
+ switch (wType) {
+ case XTYP_WILDCONNECT:
+ if (!hsz2 || !DdeCmpStringHandles(hsz2, pasi->hszService)) {
+ return(DoWildConnect(hsz1));
+ }
+ break;
+
+ case XTYP_CONNECT:
+
+ if(!fServer) {
+ DDEMLERROR("DdeStrs.Exe -- Recieved XTYP_CONNECT when client!\r\n");
+ }
+
+ case XTYP_ADVSTART:
+ case XTYP_EXECUTE:
+ case XTYP_REQUEST:
+ case XTYP_ADVREQ:
+ case XTYP_ADVDATA:
+ case XTYP_POKE:
+
+ if(InExit()) return(0);
+
+ if(DoCallback(hConv, hsz1, hsz2, wFmt, wType, hData,
+ &SSI, &hDataRet))
+ return(hDataRet);
+
+ if (DoCallback(hConv, hsz1, hsz2, wFmt, wType, hData,
+ pasi, &hDataRet))
+ return(hDataRet);
+
+ /* Fall Through */
+ default:
+ if (lpfnUserCallback != NULL) {
+ return(lpfnUserCallback(wType, wFmt, hConv, hsz1, hsz2, hData,
+ dwData1, dwData2));
+ }
+ }
+ return(0);
+}
+
+
+
+
+BOOL DoCallback(
+HCONV hConv,
+HSZ hszTopic,
+HSZ hszItem,
+UINT wFmt,
+UINT wType,
+HDDEDATA hDataIn,
+LPDDESERVICETBL psi,
+HDDEDATA *phDataRet)
+{
+ int iTopic, iItem, iFmt;
+ LPDDEFORMATTBL pfmt;
+ LPDDEITEMTBL pitm;
+ LPDDETOPICTBL ptpc;
+#ifdef WIN32
+ CONVINFO ci;
+#endif
+ LONG l;
+ BOOL fCreate=FALSE;
+ HANDLE hmem;
+ HDDEDATA FAR *hAppOwned;
+
+ FOR_EACH_TOPIC(psi, ptpc, iTopic) {
+ if (DdeCmpStringHandles(ptpc->hszTopic, hszTopic))
+ continue;
+
+ if (wType == XTYP_EXECUTE) {
+ if (ptpc->lpfnExecute) {
+ if ((*ptpc->lpfnExecute)(hDataIn))
+ *phDataRet = (HDDEDATA)DDE_FACK;
+ } else {
+ *phDataRet = (HDDEDATA)DDE_FNOTPROCESSED;
+ }
+ return(TRUE);
+ }
+
+ if (wType == XTYP_CONNECT) {
+ *phDataRet = (HDDEDATA)TRUE;
+ return(TRUE);
+ }
+
+ FOR_EACH_ITEM(ptpc, pitm, iItem) {
+ if (DdeCmpStringHandles(pitm->hszItem, hszItem))
+ continue;
+
+ FOR_EACH_FORMAT(pitm, pfmt, iFmt) {
+ if (pfmt->wFmt != wFmt)
+ continue;
+
+ switch (wType) {
+ case XTYP_ADVSTART:
+ *phDataRet = (HDDEDATA)TRUE;
+ break;
+
+// XTYP_POKE CHANGE
+#if 0
+ case XTYP_POKE:
+#endif
+
+ case XTYP_ADVDATA:
+ if (pfmt->lpfnPoke) {
+ if ((*pfmt->lpfnPoke)(hDataIn))
+ {
+ *phDataRet = (HDDEDATA)DDE_FACK;
+ break;
+ }
+ } else {
+ *phDataRet = (HDDEDATA)DDE_FNOTPROCESSED;
+ }
+ break;
+
+// XTYP_POKE CHANGE
+#ifdef WIN32 // TURNED BACK ON
+ case XTYP_POKE:
+ *phDataRet = (HDDEDATA)DDE_FACK;
+ ci.cb = sizeof(CONVINFO);
+
+ if (DdeQueryConvInfo(hConv, QID_SYNC, &ci))
+ {
+ if (!(ci.wStatus & ST_ISSELF)) {
+ DdePostAdvise(GetThreadLong(GETCURRENTTHREADID(),OFFSET_IDINST), hszTopic, hszItem);
+ }
+ }
+ else
+ {
+ *phDataRet = (HDDEDATA)DDE_FNOTPROCESSED;
+ }
+ break;
+#endif
+
+
+ case XTYP_REQUEST:
+ case XTYP_ADVREQ:
+ if (pfmt->lpfnRequest) {
+ HDDEDATA hDataOut;
+
+ l=GetWindowLong(hwndMain,OFFSET_FLAGS);
+ if(l&FLAG_APPOWNED) {
+
+ hmem=(HANDLE)GetThreadLong(GETCURRENTTHREADID(),OFFSET_HAPPOWNED);
+ hAppOwned=(HDDEDATA FAR *)GlobalLock(hmem);
+
+ switch (pfmt->wFmt) {
+ case CF_TEXT: if(hAppOwned[TXT]==0L) fCreate=TRUE;
+ break;
+ case CF_DIB: if(hAppOwned[DIB]==0L) fCreate=TRUE;
+ break;
+ case CF_BITMAP: if(hAppOwned[BITMAP]==0L) fCreate=TRUE;
+ break;
+#ifdef WIN32
+ case CF_ENHMETAFILE: if(hAppOwned[ENHMETA]==0L) fCreate=TRUE;
+ break;
+#endif
+ case CF_METAFILEPICT: if(hAppOwned[METAPICT]==0L) fCreate=TRUE;
+ break;
+ case CF_PALETTE: if(hAppOwned[PALETTE]==0L) fCreate=TRUE;
+ break;
+ default:
+ DDEMLERROR("DdeStrs.Exe -- ERR: Unexpected switch constant in DoCallback!\r\n");
+ break;
+
+ } // switch
+
+ GlobalUnlock(hmem);
+
+ if (fCreate) {
+ hDataOut = DdeCreateDataHandle( GetThreadLong(GETCURRENTTHREADID(),OFFSET_IDINST),
+ NULL,
+ 0,
+ 0,
+ pitm->hszItem,
+ pfmt->wFmt,
+ HDATA_APPOWNED);
+ } // fCreate
+
+ } // l&FLAG_APPOWNED
+ else {
+ hDataOut = DdeCreateDataHandle( GetThreadLong(GETCURRENTTHREADID(),OFFSET_IDINST),
+ NULL,
+ 0,
+ 0,
+ pitm->hszItem,
+ pfmt->wFmt,
+ 0);
+ } // else l&FLAG_APPOWNED
+
+ *phDataRet = (HDDEDATA)(*pfmt->lpfnRequest)(hDataOut);
+ if (!*phDataRet) {
+ DdeFreeDataHandle(hDataOut);
+ }
+ } else {
+ *phDataRet = 0;
+ }
+ break;
+ }
+ return(TRUE);
+ }
+ }
+
+ /* item not found in tables */
+
+ if (wFmt == CF_TEXT && (wType == XTYP_REQUEST || wType == XTYP_ADVREQ)) {
+ /*
+ * If formats item was requested and not found in the tables,
+ * return a list of formats supported under this topic.
+ */
+ if (!DdeCmpStringHandles(hszItem, SSI.topic[0].item[ITPC_FORMATS].hszItem)) {
+ *phDataRet = DdeCreateDataHandle(GetThreadLong(GETCURRENTTHREADID(),OFFSET_IDINST),
+ NULL,
+ 0,
+ 0,
+ hszItem,
+ wFmt,
+ 0);
+ *phDataRet = ReqFormats(*phDataRet, ptpc);
+ return(TRUE);
+ }
+ /*
+ * If sysitems or topicitemlist item was requested and not found,
+ * return a list of items supported under this topic.
+ */
+ if (!DdeCmpStringHandles(hszItem, SSI.topic[0].item[ITPC_SYSITEMS].hszItem) ||
+ !DdeCmpStringHandles(hszItem, SSI.topic[0].item[ITPC_ITEMLIST].hszItem)) {
+ *phDataRet = ReqItems(DdeCreateDataHandle(GetThreadLong(GETCURRENTTHREADID(),OFFSET_IDINST),
+ NULL,
+ 0,
+ 0,
+ hszItem,
+ wFmt,
+ 0),
+ ptpc);
+ return(TRUE);
+ }
+ }
+ }
+
+ /* no topics fit */
+
+ return(FALSE);
+}
+
+
+/*
+ * These are Request routines for supporting the system topic.
+ * Their behavior depends on the table contents.
+ */
+
+HDDEDATA SysReqTopics(
+HDDEDATA hDataOut) // data handle to add output data to.
+{
+ int iTopic, cb, cbOff;
+ LPDDETOPICTBL ptpc;
+
+ /*
+ * This code assumes SSI only contains the system topic.
+ */
+
+ cbOff = 0;
+ FOR_EACH_TOPIC(pasi, ptpc, iTopic) {
+ if (!DdeCmpStringHandles(ptpc->hszTopic, SSI.topic[0].hszTopic)) {
+ continue; // don't add systopic twice.
+ }
+ cb = lstrlen(ptpc->pszTopic);
+ hDataOut = DdeAddData(hDataOut, ptpc->pszTopic, (DWORD)cb, (DWORD)cbOff);
+ cbOff += cb;
+ hDataOut = DdeAddData(hDataOut, (LPBYTE)&tab, (DWORD)1, (DWORD)cbOff);
+ cbOff++;
+ }
+
+ hDataOut = DdeAddData(hDataOut, SSI.topic[0].pszTopic,
+ (DWORD)lstrlen(SSI.topic[0].pszTopic) + 1, (DWORD)cbOff);
+
+ return(hDataOut);
+}
+
+
+
+HDDEDATA SysReqSysItems(
+HDDEDATA hDataOut)
+{
+ return(ReqItems(hDataOut, &SSI.topic[ITPC_SYSITEMS]));
+}
+
+
+/*
+ * Given a topic table, this function returns a tab delimited list of
+ * items supported under that topic.
+ */
+HDDEDATA ReqItems(
+HDDEDATA hDataOut,
+LPDDETOPICTBL ptpc)
+{
+ int cb, iItem, cbOff = 0;
+ LPDDEITEMTBL pitm;
+
+ /*
+ * return a list of all the items within this topic
+ */
+ FOR_EACH_ITEM(ptpc, pitm, iItem) {
+ cb = lstrlen(pitm->pszItem);
+ hDataOut = DdeAddData(hDataOut, pitm->pszItem, (DWORD)cb, (DWORD)cbOff);
+ cbOff += cb;
+ hDataOut = DdeAddData(hDataOut, (LPBYTE)&tab, (DWORD)1, (DWORD)cbOff);
+ cbOff++;
+ }
+
+
+ /*
+ * if this is for the System Topic, add to the list our default items.
+ */
+
+ if (!DdeCmpStringHandles(ptpc->hszTopic, SSI.topic[0].hszTopic)) {
+ ptpc = &SSI.topic[0];
+ FOR_EACH_ITEM(ptpc, pitm, iItem) {
+ cb = lstrlen(pitm->pszItem);
+ hDataOut = DdeAddData(hDataOut, pitm->pszItem, (DWORD)cb, (DWORD)cbOff);
+ cbOff += cb;
+ hDataOut = DdeAddData(hDataOut, (LPBYTE)&tab, (DWORD)1, (DWORD)cbOff);
+ cbOff++;
+ }
+ } else {
+ /*
+ * Add the standard TopicListItems and SysItem items.
+ */
+ cb = lstrlen(SSI.topic[0].item[ITPC_SYSITEMS].pszItem);
+ hDataOut = DdeAddData(hDataOut,
+ SSI.topic[0].item[ITPC_SYSITEMS].pszItem, (DWORD)cb, (DWORD)cbOff);
+ cbOff += cb;
+ hDataOut = DdeAddData(hDataOut, (LPBYTE)&tab, (DWORD)1, (DWORD)cbOff);
+ cbOff++;
+
+ cb = lstrlen(SSI.topic[0].item[ITPC_ITEMLIST].pszItem);
+ hDataOut = DdeAddData(hDataOut,
+ SSI.topic[0].item[ITPC_ITEMLIST].pszItem, (DWORD)cb, (DWORD)cbOff);
+ cbOff += cb;
+ hDataOut = DdeAddData(hDataOut, (LPBYTE)&tab, (DWORD)1, (DWORD)cbOff);
+ cbOff++;
+
+ cb = lstrlen(SSI.topic[0].item[ITPC_FORMATS].pszItem);
+ hDataOut = DdeAddData(hDataOut,
+ SSI.topic[0].item[ITPC_FORMATS].pszItem, (DWORD)cb, (DWORD)cbOff);
+ cbOff += cb;
+ hDataOut = DdeAddData(hDataOut, (LPBYTE)&tab, (DWORD)1, (DWORD)cbOff);
+ cbOff++;
+ }
+
+ hDataOut = DdeAddData(hDataOut, '\0', (DWORD)1, (DWORD)--cbOff);
+ return(hDataOut);
+}
+
+
+
+
+HDDEDATA SysReqFormats(
+HDDEDATA hDataOut)
+{
+ int iTopic, iItem, iFmt;
+ LPDDETOPICTBL ptpc;
+ LPDDEITEMTBL pitm;
+ LPDDEFORMATTBL pfmt;
+
+ hDataOut = DdeAddData(hDataOut, (LPBYTE)"TEXT", 5, 0);
+ FOR_EACH_TOPIC(pasi, ptpc, iTopic) {
+ FOR_EACH_ITEM(ptpc, pitm, iItem) {
+ FOR_EACH_FORMAT(pitm, pfmt, iFmt) {
+ hDataOut = AddReqFormat(hDataOut, pfmt->pszFormat);
+ }
+ }
+ }
+ return(hDataOut);
+}
+
+
+
+HDDEDATA AddReqFormat(
+HDDEDATA hDataOut,
+LPSTR pszFmt)
+{
+ LPSTR pszList;
+ DWORD cbOff;
+
+ pszList = DdeAccessData(hDataOut, NULL);
+
+#if WIN16
+ if (_fstrstr(pszList, pszFmt) == NULL) {
+#else
+ if (strstr(pszList, pszFmt) == NULL) {
+#endif
+ cbOff = lstrlen(pszList);
+ DdeUnaccessData(hDataOut);
+ hDataOut = DdeAddData(hDataOut, (LPBYTE)&tab, 1, cbOff++);
+ hDataOut = DdeAddData(hDataOut, (LPBYTE)pszFmt, lstrlen(pszFmt) + 1, cbOff);
+ } else {
+ DdeUnaccessData(hDataOut);
+ }
+
+ return(hDataOut);
+}
+
+
+HDDEDATA ReqFormats(
+HDDEDATA hDataOut,
+LPDDETOPICTBL ptpc)
+{
+ int iItem, iFmt;
+ LPDDEITEMTBL pitm;
+ LPDDEFORMATTBL pfmt;
+
+ hDataOut = DdeAddData(hDataOut, "", 1, 0);
+ FOR_EACH_ITEM(ptpc, pitm, iItem) {
+ FOR_EACH_FORMAT(pitm, pfmt, iFmt) {
+ hDataOut = AddReqFormat(hDataOut, pfmt->pszFormat);
+ }
+ }
+ return(hDataOut);
+}
+
+
+
+HDDEDATA DoWildConnect(
+HSZ hszTopic)
+{
+ LPDDETOPICTBL ptpc;
+ HDDEDATA hData;
+ PHSZPAIR pHszPair;
+ int iTopic, cTopics = 2;
+
+ if (!hszTopic) {
+ cTopics += pasi->cTopics;
+ }
+
+ hData = DdeCreateDataHandle(GetThreadLong(GETCURRENTTHREADID(),OFFSET_IDINST),
+ NULL,
+ cTopics * sizeof(HSZPAIR),
+ 0,
+ 0,
+ 0,
+ 0);
+ pHszPair = (HSZPAIR FAR *)DdeAccessData(hData, NULL);
+ pHszPair->hszSvc = pasi->hszService;
+ pHszPair->hszTopic = SSI.topic[0].hszTopic; // always support systopic.
+ pHszPair++;
+ ptpc = &pasi->topic[0];
+ FOR_EACH_TOPIC(pasi, ptpc, iTopic) {
+ if (hszTopic && DdeCmpStringHandles(hszTopic, ptpc->hszTopic)) {
+ continue;
+ }
+ if (!DdeCmpStringHandles(ptpc->hszTopic, SSI.topic[0].hszTopic)) {
+ continue; // don't enter systopic twice.
+ }
+ pHszPair->hszSvc = pasi->hszService;
+ pHszPair->hszTopic = ptpc->hszTopic;
+ pHszPair++;
+ }
+ pHszPair->hszSvc = 0;
+ pHszPair->hszTopic = 0;
+ DdeUnaccessData(hData);
+ return(hData);
+}
diff --git a/private/mvdm/wow16/ddeml/tests/ddestrs/wrapper.h b/private/mvdm/wow16/ddeml/tests/ddestrs/wrapper.h
new file mode 100644
index 000000000..5cfbc261b
--- /dev/null
+++ b/private/mvdm/wow16/ddeml/tests/ddestrs/wrapper.h
@@ -0,0 +1,80 @@
+/***************************************************************************\
+
+ MODULE : wrapper.h
+
+ PURPOSE : This is not a full program but a module you can include
+ in your code. It implements a standard DDEML callback
+ function that allows you to have most of your DDE table
+ driven. The default callback function handles all basic
+ System Topic information based on the tables you give
+ to this app.
+
+ LIMITATIONS : This only supports servers that:
+ have only one service name
+ have enumerable topics and items
+ do not change the topics or items they support over time.
+
+\***************************************************************************/
+
+
+/* TYPES */
+
+typedef BOOL (*CBFNIN)(HDDEDATA);
+typedef HDDEDATA (*CBFNOUT)(HDDEDATA);
+
+
+
+/* STRUCTURES */
+
+typedef struct _DDEFORMATTBL {
+ LPSTR pszFormat;
+ UINT wFmt;
+ UINT wFmtFlags;
+ CBFNIN lpfnPoke;
+ CBFNOUT lpfnRequest;
+} DDEFORMATTBL;
+typedef DDEFORMATTBL *PDDEFORMATTBL;
+typedef DDEFORMATTBL FAR *LPDDEFORMATTBL;
+
+typedef struct _DDEITEMTBL {
+ LPSTR pszItem;
+ HSZ hszItem;
+ UINT cFormats;
+ UINT wItemFlags;
+ LPDDEFORMATTBL fmt;
+} DDEITEMTBL;
+typedef DDEITEMTBL *PDDEITEMTBL;
+typedef DDEITEMTBL FAR *LPDDEITEMTBL;
+
+
+typedef struct _DDETOPICTBL {
+ LPSTR pszTopic;
+ HSZ hszTopic;
+ UINT cItems;
+ UINT wTopicFlags;
+ LPDDEITEMTBL item;
+ CBFNIN lpfnExecute;
+} DDETOPICTBL;
+typedef DDETOPICTBL *PDDETOPICTBL;
+typedef DDETOPICTBL FAR *LPDDETOPICTBL;
+
+typedef struct _DDESERVICETBL {
+ LPSTR pszService;
+ HSZ hszService;
+ UINT cTopics;
+ UINT wServiceFlags;
+ LPDDETOPICTBL topic;
+} DDESERVICETBL;
+typedef DDESERVICETBL *PDDESERVICETBL;
+typedef DDESERVICETBL FAR *LPDDESERVICETBL;
+
+
+
+/* PROTOTYPES */
+
+BOOL InitializeDDE(PFNCALLBACK lpfnCustomCallback, LPDWORD pidInst,
+ LPDDESERVICETBL AppSvcInfo, DWORD dwFilterFlags, HANDLE hInst);
+
+VOID UninitializeDDE(VOID);
+
+