/*************************** INCLUDE FILES ********************************/
#include <windows.h>
#include <memory.h>
#include <malloc.h>
#include "testw32.h"

// Prototype an external routine
void Test2Routine(HMENU i);

HANDLE hWindow;
HANDLE hInst;

POINT apts[5] = {{200,	10},
		 {300, 200},
		 {100, 100},
		 {300, 100},
		 {100, 200}};

HBITMAP hbitmap;
HFONT	hfont;
HRGN	hregion;
HBRUSH	hbrush;
HPEN	hpen;
HDC		hdcMeta;

HMENU	hmenu;
HMENU	hpopupmenu;
ATOM	hatom;

LONG cxChar;				// width of font character
LONG cyChar;				// height of font character
BOOL paintflag = FALSE;
char szLine[128];

char junk1[10];
char GlobalArray[10];
char junk2[10];

/**************************** PROTOTYPES ***************************/

void CreateMultipleThreads () ;
void OutputDebugStringDemo () ;
void PaintingRaceDemo ( HWND hWnd ) ;


// double free a LocalAlloc'ed block
void LocalFreeDouble(void)
{
	char *ptr;

	ptr = (char *) LocalAlloc (LMEM_FIXED | LMEM_ZEROINIT, 100);

	LocalFree((HANDLE) ptr);
	LocalFree((HANDLE) ptr);
}


// LocalFree an invalid handle
void LocalFreeBad(void)
{
	LocalFree((HLOCAL)0x10);
}


// GlobalFree an invalid handle
void GlobalFreeBad(void)
{
	GlobalFree((HLOCAL)0x10);
}


// double free a GlobalAlloc'ed block
void GlobalFreeDouble(void)
{
	HANDLE hglobal;

	hglobal = GlobalAlloc(GHND, 512);
	GlobalFree(hglobal);
	GlobalFree(hglobal);
}


void OverwriteData(char *ptr)
{
	char onechar;

	onechar = *ptr;
	*ptr = onechar;
}


void OverwriteLocal(void)
{
	char xxx[2];
	char LocalArray[50];
	char yyy[2];

	memset(LocalArray, 0x44, 51);
	xxx[0] = 1;
	yyy[0] = 1;
}

void OverwriteStaticLocal(void)
{
	static char xxx[2];
	static char StaticLocalArray[50];
	static char yyy[2];
	
	memset(StaticLocalArray, 0x44, 51);
	xxx[0] = 1;
	yyy[0] = 1;
}

// overwrite a global array
void OverwriteGlobal(void)
{
	memset(GlobalArray, 0x44, 11);
}


// overwrite a local array with lstrcpy
void lstrcpyLocal(void)
{
	char xxx[2];
	char LocalArray[10];
	char yyy[2];

	xxx[1] = 0;
	lstrcpy(LocalArray, "0123456789");
	yyy[1] = 0;
}

// overwrite a global array with lstrcpy
void lstrcpyGlobal(void)
{
	lstrcpy(GlobalArray, "0123456789");
}


// overwrite a local array with lstrcat
void lstrcatLocal(void)
{
	char xxx[10];
	char LocalArray[10];
	char yyy[10];

	lstrcpy(LocalArray, "01234");
	lstrcat(LocalArray, "01234");
	xxx[0] = 1;
	yyy[0] = 1;
}

// overwrite a global array with lstrcat
void lstrcatGlobal(void)
{
	lstrcpy(GlobalArray, "01234");
	lstrcat(GlobalArray, "01234");
}


// overwrite a malloc'ed area with memset
void DoMalloc(void)
{
	char *ptr;

	ptr = (char *) malloc(100);
	memset(ptr, 0, 102);
	free(ptr);
}


// overwrite a LocalAlloc'ed area
void DoLocalAlloc(void)
{
	char *ptr;
	int i;

	ptr = (char *) LocalAlloc (LMEM_FIXED | LMEM_ZEROINIT, 100);
	for (i=0; i<=100; ++i)
		ptr[i] = 0x77;

	LocalFree((HANDLE) ptr);
}


// do a localalloc without ever freeing
void LocalLeak(WORD leak_size)
{
	HANDLE hlocal;

	hlocal = LocalAlloc (LMEM_FIXED | LMEM_ZEROINIT, leak_size);
}


// do a globalalloc without ever freeing
void GlobalLeak(LONG leak_size)
{
	HANDLE hglobal;

	hglobal = GlobalAlloc(GHND, leak_size);
}

// do a malloc without ever freeing
void MallocLeak(LONG leak_size)
{
	malloc(leak_size);
}

#if 0
void Fault_0d(void)
{
	__asm	mov ax, 8
	__asm	mov es, ax
}

void Fault_06(void)
{
	#ifdef __BORLANDC__
	__emit__( 0xFF, 0xFF );
	#else
	__asm __emit 0x0FF
	__asm __emit 0x0FF
	#endif
}

void Fault_00(void)
{
	int i = 1, j=0;
	
	i = i / j;
}
#endif

// ====  Special Case Menu Item Support  ====

DWORD WINAPI MultipleThreadProc (LPVOID param)
{
	RECT rect;
	
	GetClientRect((HWND)(0x10), &rect);

    WaitForSingleObject ((HANDLE) param, INFINITE ) ;

	return 0;
}


void CreateMultipleThreads()
{
  DWORD newThreadID;
  RECT rect;
	

  MessageBox ( 0
             , "This example creates a number of threads which\r\n"
			   "cause errors. You can use TView to look at the\r\n"
			   "trace and log files to see which threads caused.\r\n"
			   "which errors. BCHK32NT will pop up as they occur."
             , "Create Multiple Threads Demo"
             , MB_OK
             ) ;


  // ----  Create a thread  ----

  CreateThread ( 0
               , 0
               , MultipleThreadProc
               , (LPVOID) CreateSemaphore ( 0, 0, 1, 0 )
               , 0
               , &newThreadID
               );


  // ----  Create a thread  ----

  CreateThread ( 0
               , 0
               , MultipleThreadProc
               , (LPVOID) CreateSemaphore ( 0, 0, 1, 0 )
               , 0
               , &newThreadID
               );


  // ----  Create a thread  ----

  CreateThread ( 0
               , 0
               , MultipleThreadProc
               , (LPVOID) CreateSemaphore ( 0, 0, 1, 0 )
               , 0
               , &newThreadID
               );


  // ----  Show what happened  ----

  MessageBox ( 0
             , "This example has created 3 threads which are\r\n"
			   "waiting on their own semaphore. Each has caused\r\n"
			   "an error which will be recorded in the log and\r\n"
			   "trace file. Check out the files using the Thread\r\n"
			   "button on the trace window when you run TView."
             , "Create Multiple Threads Demo"
             , MB_OK
             ) ;
}

			
void OutputDebugStringDemo ()
{
  RECT rect;
	

  // ----  Show what is going on  -----

  OutputDebugString ( "At the start of OutputDebugStringDemo ()" ) ;


  // ----  Cause an error  ----

  GetClientRect((HWND)(0x10), &rect);


  // ----  Show what is going on  -----

  OutputDebugString ( "After the induced error in OutputDebugStringDemo ()" ) ;


  // ----  Show what happened  ----

  MessageBox ( 0
             , "This example uses the OutputDebugString function\r\n"
			   "to add comments to the log and trace files.\r\n"
			   "The comment also appears in the wide status window.\r\n"
			   "The function does nothing when a program runs\r\n"
			   "without a debugger like BCHK32NT. The comments\r\n"
			   "can be any text and you can easily see what your\r\n"
			   "program does with respect to these points."
             , "OutputDebugString Demo"
             , MB_OK
             ) ;


  // ----  Show what is going on  -----

  OutputDebugString ( "At the end of OutputDebugStringDemo ()" ) ;
}



// ----  Race Condition Demo  ----

typedef struct
  {
    HWND   hWnd ;
    HANDLE hSemaphore ;
  }
  RaceParameter ;


DWORD RaceProc ( HWND hWnd, DWORD dwColor )
{
  RECT   rect;
  HDC    hDC ;
  HBRUSH hBrush ;


  hDC    = GetDC ( hWnd ) ;
  hBrush = CreateSolidBrush ( dwColor ) ;

  GetClientRect( hWnd, & rect) ;

  FillRect ( hDC, & rect, hBrush ) ;

  ReleaseDC ( hWnd, hDC ) ;

  DeleteObject ( hBrush ) ;

  return 0 ;
}


DWORD WINAPI RaceProc1 (LPVOID param)
{
  DWORD           dwResult ;
  RaceParameter * p ;

  p = (RaceParameter *) param ;

  WaitForSingleObject ( p -> hSemaphore, INFINITE ) ;

  dwResult = RaceProc ( p -> hWnd, RGB ( 255, 0, 0 )) ;


  // ----  Easy way to do a delay  ----

  WaitForSingleObject ( p -> hSemaphore, 500 ) ;


  // ----  Continue the other thread  ----

  ReleaseSemaphore ( p -> hSemaphore, 1, 0 ) ;
  
  return dwResult ;
}


DWORD WINAPI RaceProc2 (LPVOID param)
{
  RaceParameter * p ;
  DWORD           dwResult ;


  p = (RaceParameter *) param ;

  WaitForSingleObject ( p -> hSemaphore, INFINITE ) ;

  dwResult = RaceProc ( p -> hWnd, RGB ( 0, 255, 0 )) ;


  // ----  Easy way to do a delay  ----

  WaitForSingleObject ( p -> hSemaphore, 500 ) ;


  // ----  Cleanup  -----

  CloseHandle ( p -> hSemaphore ) ;

  free ( p ) ;

  InvalidateRect ( p -> hWnd, 0, TRUE ) ;
  UpdateWindow ( p -> hWnd ) ;

  return dwResult ;
}


void PaintingRaceDemo (HWND hWnd)
{
  DWORD newThreadID ;

  RaceParameter * pParameters ;
  
  pParameters = malloc ( sizeof ( RaceParameter )) ;


  // ----  Show what happened  ----

  MessageBox ( 0
             , "This example uses two threads to update the window.\r\n"
			   "\r\n"
			   "You can use TView to see which one gets done first\r\n"
			   "and why the other takes longer to finish.\r\n"
			   "\r\n"
			   "Click on OK to start the update.\r\n"
             , "Painting Race Demo"
             , MB_OK
             ) ;


  // ----  Setup  ----

  pParameters -> hWnd       = hWnd ;
  pParameters -> hSemaphore = CreateSemaphore ( 0, 0, 1, 0 ) ;


  // ----  Start threads  ----

  CreateThread ( 0
               , 0
               , RaceProc1
               , pParameters
               , 0
               , &newThreadID
               );


  CreateThread ( 0
               , 0
               , RaceProc2
               , pParameters
               , 0
               , &newThreadID
               );


  // ----  Startup update  ---

  ReleaseSemaphore ( pParameters -> hSemaphore, 1, 0 ) ;
}

DWORD WINAPI SecondaryThread(LPVOID param)
{
	RECT rect;
	
	GetClientRect((HWND)(0x10), &rect);
	MessageBox(0, "Hello from another thread!", "Threads Rock!", MB_OK);
	return 0;
}

BOOL  MakeError(WPARAM wParam, HWND hWnd)
{
	LOGBRUSH lb;
	HGDIOBJ hgdiobj;
	DWORD color;
	char FileName[260];
	int count;
	RECT rect;
	DWORD newThreadID;
	HANDLE hThread;
	
	switch (wParam)
	{
		// overwrite a malloced area
		case IDM_MALLOC:
			DoMalloc();
			break;

		// overwrite a LocalAlloc area
		case IDM_LOCALALLOC:
			DoLocalAlloc();
			break;

		// overwrite a global array
		case IDM_GLOBALSTR:
			OverwriteGlobal();
			break;

		// overwrite a local array
		case IDM_LOCALSTR:
			OverwriteLocal();
			break;

		// overwrite a static local array
		case IDM_STATICLOCALSTR:
			OverwriteStaticLocal();
			break;

		// overwrite a global array with lstrcpy
		case IDM_LSTRCPY_GLOBAL:
			lstrcpyGlobal();
			break;

		// overwrite a local array lstrcpy
		case IDM_LSTRCPY_LOCAL:
			lstrcpyLocal();
			break;

		// overwrite a global array with lstrcat
		case IDM_LSTRCAT_GLOBAL:
			lstrcatGlobal();
			break;

		// overwrite a local array lstrcat
		case IDM_LSTRCAT_LOCAL:
			lstrcatLocal();
			break;
#if 0
		// gp fault
		case IDM_FAULT0d:
			Fault_0d();
			break;

		// stack fault
		case IDM_FAULT0c:
			// Fault_0c();
			break;

		// invalid opcode fault
		case IDM_FAULT06:
			Fault_06();
			break;

		// divide by zero fault
		case IDM_FAULT00:
			Fault_00();
			break;
#endif
		// LocalAlloc memory leakage
		case IDM_LLEAK256:
			LocalLeak(256);
			break;
		   
		case IDM_LLEAK1K:
			LocalLeak(1024);
			break;
		   
		case IDM_LLEAK4K:
			LocalLeak(4096);
			break;
		   
		case IDM_LLEAK16K:
			LocalLeak(16384);
			break;

		// GlobalAlloc memory leakage
		case IDM_GLEAK1K:
			GlobalLeak(1024L);
			break;
		   
		case IDM_GLEAK4K:
			GlobalLeak(4096L);
			break;
		   
		case IDM_GLEAK16K:
			GlobalLeak(16384L);
			break;
		   
		case IDM_GLEAK64K:
			GlobalLeak(65536L);
			break;

		case IDM_MALLOCLEAK1K:
			MallocLeak(1024);
			break;
			
		case IDM_MALLOCLEAK192K:
			MallocLeak(192 * 1024);
			break;
			
		// gdi.exe resource leakage
		case IDM_BITMAP:
			hbitmap = CreateBitmap(80, 80, 1, 8, NULL);
			break;
		   
		case IDM_FONT:
			hfont = CreateFont(20, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL);
			break;
		   
		case IDM_REGION:
			hregion = CreatePolygonRgn(apts, sizeof(apts)/sizeof(POINT),
										ALTERNATE);
			break;
			
		case IDM_BRUSH:
			lb.lbStyle = BS_HATCHED;
			lb.lbColor = RGB(255, 0, 0);
			lb.lbHatch = HS_BDIAGONAL;
			hbrush = CreateBrushIndirect(&lb);
			break;
		   
		case IDM_PEN:
			hpen = CreatePen(PS_SOLID, 6, RGB(255, 0, 255));
			break;
		   
		case IDM_METAFILE:
			hdcMeta = CreateMetaFile(NULL);
			break;

		// user.exe resource leakage
		case IDM_MENU:
			hmenu = CreateMenu();
			AppendMenu(hmenu, MF_ENABLED | MF_STRING, 900,"&New Menu Item");
			break;
		   
		case IDM_POPUPMENU:
			hpopupmenu = CreatePopupMenu();
			AppendMenu(hpopupmenu, MF_ENABLED | MF_STRING, 800,
					   "&New Popup Menu Item");
			break;
		   
		case IDM_ATOM:
			hatom = GlobalAddAtom("This is a new global atom");
			break;
		   
		case IDM_PROP:
			SetProp(hWindow, "New Window Property", (HANDLE)IDM_PROP);
			break;
		   
		case IDM_ICON:
			CreateIcon(hInst, 32, 32, 1, 1,
				(LPBYTE) MakeError, (LPBYTE) MakeError);
			break;

		// bad parameters
		case IDM_STOCKOBJ:
			hgdiobj = GetStockObject(0x4567);
			break;
		   
		case IDM_TEXTCOLOR:
			color = GetTextColor((HDC)0xabcd);
			break;
		   
		case IDM_GETMODULE:
			count = 0;
			GetModuleFileName(hInst, FileName, count);
			break;
		   
		case IDM_FREELIB:
			FreeLibrary((HINSTANCE)0xeeee);
			break;
		   
		case IDM_DELETEMENU:
			DeleteMenu((HMENU)0xff00, 0, MF_BYPOSITION);
			break;
			
		case IDM_DELETEMENU2:
			Test2Routine((HMENU)0xff00);
			break;
		   
		case IDM_CLIENTRECT:
			GetClientRect((HWND)(0x10), &rect);
			break;

#if 0
		// stack usage routines
		case IDM_STACK1000:
			UseStack(1000);
			break;
		   
		case IDM_STACK500:	
			UseStack(500);
			break;
			
		case IDM_STACK100:	
			UseStack(100);
			break;
		   
		case IDM_STACKALL:	
			UseStack(0);
			break;
#endif
		case IDM_FREE1:
			LocalFreeDouble();
			break;
		   
		case IDM_FREE2:
			GlobalFreeDouble();
			break;	  
		   
		case IDM_FREE3:
			LocalFreeBad();
			break;
		   
		case IDM_FREE4:
			GlobalFreeBad();
			break;

		case IDM_NEW_THREAD:
			hThread = CreateThread(0, 0, SecondaryThread, 0, 0, &newThreadID);
			CloseHandle(hThread);	// Don't need this anymore!
			break;

		case IDM_MULTIPLE_THREADS:
			CreateMultipleThreads();
			break;
			
		case IDM_OUTPUT_DEBUG_STRING:
			OutputDebugStringDemo ();
			break;
			
		case IDM_PAINTING_RACE:
			PaintingRaceDemo ( hWnd );
			break;
			
		default:
			return (FALSE);
	}
	
	return (TRUE);
}

/***************************** THE PAINT ROUTINE ****************************/
void PaintTestWindow (HWND hWnd)
{
	PAINTSTRUCT ps;
	char szOneLine[80];
	HDC hDC;
	int i;

	BeginPaint (hWnd, (LPPAINTSTRUCT) &ps);
#if 0
	hDC = ps.hdc;

	if (paintflag)
	{
		for (i=0; i<26; ++i)
		{
			memset(szLine, i+0x41, 80);
			szLine[80] = 0;
			lstrcpy(szOneLine, szLine);
			TextOut(hDC, cxChar, i*cyChar, szOneLine, lstrlen(szOneLine));
		}
	}

	ValidateRect(hWnd, (LPRECT)NULL);
#endif
	EndPaint(hWnd, (LPPAINTSTRUCT) &ps);
}

LRESULT CALLBACK About(HWND hDlg, unsigned message, WORD wParam, LONG lParam)
{
	switch (message)
	{
		case WM_INITDIALOG:
			return (TRUE);

		case WM_COMMAND:
			if (wParam == IDOK || wParam == IDCANCEL)
			{
				EndDialog(hDlg, TRUE);
				return (TRUE);
			}
			break;
	}
	return (FALSE);				  /* Didn't process a message	 */
}

LRESULT CALLBACK TestWindowProc
(
	HWND hWnd, unsigned message, WPARAM wParam, LPARAM lParam
)
{
	FARPROC lpProcAbout;		  /* pointer to the "About" function */
	HDC hDC;
	TEXTMETRIC tm;

	switch (message)
	{
		case WM_COMMAND:	   /* message: command from application menu */
			switch (wParam)
				{
					case IDM_ABOUT:
						lpProcAbout = MakeProcInstance(About, hInst);
						DialogBox(hInst, "AboutBox", hWnd, lpProcAbout);
						FreeProcInstance(lpProcAbout);
						break;

					case IDM_PAINT:
						paintflag = !paintflag;
						break;

					default:
						if (  MakeError(wParam, hWnd) )
							break;
						return (DefWindowProc(hWnd, message, wParam, lParam));
				}
			break;

		case WM_CREATE:
			hDC = GetDC(hWnd);
			GetTextMetrics(hDC, &tm);
			cxChar = tm.tmAveCharWidth;
			cyChar = tm.tmHeight + tm.tmExternalLeading;
			ReleaseDC(hWnd, hDC);
			break;

#if 0
		case WM_PAINT:
			PaintTestWindow(hWnd);
			break;
#endif

		case WM_DESTROY:
			PostQuitMessage (0);
			break;

		default:
			return (DefWindowProc (hWnd, message, wParam, lParam));
	}
	
	return ((LONG) 0);
}


BOOL InitApplication(HANDLE hInstance)
{
	WNDCLASS  wc;

	wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
	wc.lpfnWndProc= (WNDPROC)TestWindowProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = hInstance;
	wc.hIcon = LoadIcon(hInstance, "TestW32ICON");
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
	wc.lpszMenuName =  "TestW32Menu";
	wc.lpszClassName = "TestW32Class";

	/* Register the window class and return success/failure code. */

	return (RegisterClass(&wc));

}

BOOL InitInstance(HANDLE hInstance, int nCmdShow)
{
	HWND			hWnd;				/* Main window handle.				  */

	hInst = hInstance;

	/* Create a main window for this application instance.	*/

	hWindow = hWnd = CreateWindow(
		"TestW32Class",					/* See RegisterClass() call.		  */
		"Test Application",			/* Text for window title bar.		  */
		( (WS_OVERLAPPEDWINDOW ) ),		/* Window style.					  */
		CW_USEDEFAULT,					/* Default horizontal position.		  */
		CW_USEDEFAULT,					/* Default vertical position.		  */
		CW_USEDEFAULT,					/* Default width.					  */
		CW_USEDEFAULT,					/* Default height.					  */
		NULL,							/* Overlapped windows have no parent. */
		NULL,							/* Use the window class menu.		  */
		hInstance,						/* This instance owns this window.	  */
		0L);						/* Pointer not needed.				  */

	/* If window could not be created, return "failure" */

	if (!hWnd)
		return (FALSE);


	/* Make the window visible; update its client area; and return "success" */

	ShowWindow(hWnd, nCmdShow);	 /* Show the window						   */
	UpdateWindow(hWnd);			 /* Sends WM_PAINT message				   */
	return (TRUE);				 /* Returns the value from PostQuitMessage */

}


/**************************** MAIN PROGRAM ***************************/

int PASCAL WinMain(
	HANDLE hInstance,
	HANDLE hPrevInstance,
	PSTR lpCmdLine,
	int nCmdShow
)
{
	MSG msg;			/* temp buffer to hold message */
	UINT ourMsg;

	if (hPrevInstance)		/* Other instances of app running? */
		return (FALSE);

	if (!InitApplication(hInstance))	/* Initialize shared things */
		return (FALSE);					/* Exits if unable to initialize */

	/* Perform initializations that apply to a specific instance */

	if (!InitInstance(hInstance, nCmdShow))
		return (FALSE);

	GetForegroundWindow();		// NT & Chicago only
	GetPriorityClass(GetCurrentProcess());	// NT & Chicago only
	GetProcessHeap();			// NT & Chicago only
	GetProcessWindowStation();	// NT only
	GetThreadLocale();			// NT only
	ourMsg = RegisterWindowMessage("BoundsChecker32_TestMessage");

	if ( ourMsg )
		PostMessage(hWindow, ourMsg, 0, 0);
	
	while (GetMessage((LPMSG)&msg, NULL, 0, 0))
	{
		TranslateMessage((LPMSG)&msg);	/* translate the message */
		DispatchMessage((LPMSG)&msg);	/* have windows dispatch it */
	}
	
	return msg.wParam;
}


