1// TpcbUI.cpp : Defines the entry point for the application.
2//
3
4#include <windows.h>
5#include "resource.h"
6#include "TpcbExample.h"
7#include <commctrl.h>
8
9#define MAX_LOADSTRING 100
10
11// Global Variables:
12HINSTANCE		hInst;		// The current instance
13HWND			hWndDlgMain;	// Handle to the main dialog window.
14HWND			hWndFrame;	// Handle to the main window.
15TpcbExample		*tpcb;
16
17// Forward declarations of functions included in this code module:
18ATOM				MyRegisterClass	(HINSTANCE, LPTSTR);
19BOOL				InitInstance	(HINSTANCE, int);
20LRESULT CALLBACK	WndProc			(HWND, UINT, WPARAM, LPARAM);
21LRESULT CALLBACK	MainDialog		(HWND, UINT, WPARAM, LPARAM);
22LRESULT CALLBACK	InitDialog		(HWND, UINT, WPARAM, LPARAM);
23LRESULT CALLBACK	AdvancedDialog	(HWND, UINT, WPARAM, LPARAM);
24LRESULT CALLBACK	RunDialog		(HWND, UINT, WPARAM, LPARAM);
25BOOL				GetHomeDirectory(HWND, BOOL);
26BOOL				RecursiveDirRemove(wchar_t *);
27
28int WINAPI WinMain(	HINSTANCE hInstance,
29					HINSTANCE hPrevInstance,
30					LPTSTR    lpCmdLine,
31					int       nCmdShow)
32{
33	MSG msg;
34	HACCEL hAccelTable;
35
36	hWndDlgMain = NULL;
37	// Initialize the tpcb object.
38	tpcb = new TpcbExample();
39
40	// Perform application initialization:
41	if (!InitInstance (hInstance, nCmdShow))
42	{
43		return FALSE;
44	}
45
46	hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_WCE_TPCB);
47
48	// Main message loop:
49	while (GetMessage(&msg, NULL, 0, 0))
50	{
51		if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
52		{
53			TranslateMessage(&msg);
54			DispatchMessage(&msg);
55		}
56	}
57
58	return msg.wParam;
59}
60
61//
62//  FUNCTION: MyRegisterClass()
63//
64//  PURPOSE: Registers the window class.
65//
66//  COMMENTS:
67//
68//    It is important to call this function so that the application
69//    will get 'well formed' small icons associated with it.
70//
71ATOM MyRegisterClass(HINSTANCE hInstance, LPTSTR szWindowClass)
72{
73	WNDCLASS	wc;
74
75    wc.style			= CS_HREDRAW | CS_VREDRAW;
76    wc.lpfnWndProc		= (WNDPROC) WndProc;
77    wc.cbClsExtra		= 0;
78    wc.cbWndExtra		= 0;
79    wc.hInstance		= hInstance;
80    wc.hIcon			= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WCE_TPCB));
81    wc.hCursor			= 0;
82    wc.hbrBackground	= (HBRUSH) GetStockObject(WHITE_BRUSH);
83    wc.lpszMenuName		= 0;
84    wc.lpszClassName	= szWindowClass;
85
86	return RegisterClass(&wc);
87}
88
89//
90//  FUNCTION: InitInstance(HANDLE, int)
91//
92//  PURPOSE: Saves instance handle and creates main window
93//
94//  COMMENTS:
95//
96//    In this function, we save the instance handle in a global variable and
97//    create and display the main program window.
98//
99BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
100{
101	TCHAR	szTitle[MAX_LOADSTRING];	// The title bar text
102	TCHAR	szWindowClass[MAX_LOADSTRING];	// The window class name
103
104	hInst = hInstance;	// Store instance handle in our global variable
105	// Initialize global strings
106	LoadString(hInstance, IDC_WCE_TPCB, szWindowClass, MAX_LOADSTRING);
107	MyRegisterClass(hInstance, szWindowClass);
108	LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
109
110	hWndFrame = CreateWindow(szWindowClass, szTitle,
111	    WS_VISIBLE | WS_MINIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT,
112	    CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
113
114	if (!hWndFrame)
115	{
116		return FALSE;
117	}
118
119	ShowWindow(hWndDlgMain, nCmdShow);
120	UpdateWindow(hWndDlgMain);
121
122	return TRUE;
123}
124
125//
126//  FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
127//
128//  PURPOSE:  Processes messages for the main window.
129//
130//  WM_COMMAND	- process the application menu
131//  WM_DESTROY	- post a quit message and return
132//
133//
134LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
135{
136	HWND hDlg;
137
138	switch (message)
139	{
140		case WM_COMMAND:
141			DefWindowProc(hWnd, message, wParam, lParam);
142			break;
143		case WM_CREATE:
144			hDlg = CreateDialog(hInst,
145			    MAKEINTRESOURCE(IDD_MAINDIALOG), hWnd,
146			    (DLGPROC)MainDialog);
147			break;
148		case WM_DESTROY:
149			PostQuitMessage(0);
150			break;
151		default:
152			return DefWindowProc(hWnd, message, wParam, lParam);
153   }
154   return 0;
155}
156
157// Message handler for the Main dialog box
158LRESULT CALLBACK MainDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
159{
160	RECT rt;
161	HWND	hCurrentRadioButton;
162	wchar_t wdirname[MAX_PATH], msg[1024], *title;
163	int ret, valid, ntxns, written;
164
165	switch (message)
166	{
167		case WM_INITDIALOG:
168			// maximize the dialog.
169			GetClientRect(GetParent(hDlg), &rt);
170			SetWindowPos(hDlg, HWND_TOP, 0, 0, rt.right, rt.bottom,
171			    SWP_SHOWWINDOW);
172			CheckRadioButton(hDlg, IDC_MEDIUM_RADIO,
173			    IDC_SMALL_RADIO, IDC_SMALL_RADIO);
174			SetDlgItemText(hDlg, IDC_HOME_EDIT,
175			    tpcb->getHomeDirW(wdirname, MAX_PATH));
176			SetDlgItemInt(hDlg, IDC_TXN_EDIT, 1000, 0);
177
178			SetWindowText(hDlg, L"BDB TPCB Example app");
179			ShowWindow(hDlg, SW_SHOWNORMAL);
180			return TRUE;
181		case WM_COMMAND:
182			if (LOWORD(wParam) == IDC_INIT_BUTTON ||
183				LOWORD(wParam) == IDC_RUN_BUTTON ) {
184				hCurrentRadioButton = GetDlgItem(hDlg,
185				    IDC_SMALL_RADIO);
186				if(BST_CHECKED ==
187				    SendMessage(hCurrentRadioButton,
188				    BM_GETCHECK, NULL, NULL)) {
189					tpcb->accounts = 500;
190					tpcb->branches = 10;
191					tpcb->tellers  = 50;
192					tpcb->history  = 5000;
193				}
194				hCurrentRadioButton = GetDlgItem(hDlg,
195				    IDC_MEDIUM_RADIO);
196				if(BST_CHECKED ==
197				    SendMessage(hCurrentRadioButton,
198				    BM_GETCHECK, NULL, NULL)) {
199					tpcb->accounts = 1000;
200					tpcb->branches = 10;
201					tpcb->tellers  = 100;
202					tpcb->history  = 10000;
203				}
204				hCurrentRadioButton = GetDlgItem(hDlg,
205				    IDC_LARGE_RADIO);
206				if(BST_CHECKED ==
207				    SendMessage(hCurrentRadioButton,
208				    BM_GETCHECK, NULL, NULL)) {
209					tpcb->accounts = 100000;
210					tpcb->branches = 10;
211					tpcb->tellers  = 100;
212					tpcb->history  = 259200;
213				}
214				EnableWindow(GetDlgItem(hDlg, IDC_INIT_BUTTON),
215				    FALSE);
216				EnableWindow(GetDlgItem(hDlg, IDC_RUN_BUTTON),
217				    FALSE);
218				EnableWindow(GetDlgItem(hDlg, IDC_ADV_BUTTON),
219				    FALSE);
220			}
221			if (LOWORD(wParam) == IDC_ADV_BUTTON) {
222				CreateDialog(hInst,
223				    MAKEINTRESOURCE(IDD_ADVANCEDDIALOG), hDlg,
224				    (DLGPROC)AdvancedDialog);
225			} else if (LOWORD(wParam) == IDC_INIT_BUTTON) {
226				// Close the environment first.
227				// In case this is a re-initialization.
228				tpcb->closeEnv();
229				GetHomeDirectory(hDlg, TRUE);
230				tpcb->createEnv(0);
231				ret = tpcb->populate();
232			} else if (LOWORD(wParam) == IDC_RUN_BUTTON) {
233				GetHomeDirectory(hDlg, FALSE);
234				if (GetFileAttributes(
235				    tpcb->getHomeDirW(wdirname, MAX_PATH)) !=
236				    FILE_ATTRIBUTE_DIRECTORY) {
237					_snwprintf(msg, 1024,
238L"Target directory: %s does not exist, or is not a directory.\nMake sure the "
239L"directory name is correct, and that you ran the initialization phase.",
240					    wdirname);
241					MessageBox(hDlg, msg, L"Error", MB_OK);
242					EnableWindow(GetDlgItem(hDlg,
243					    IDC_INIT_BUTTON), TRUE);
244					EnableWindow(GetDlgItem(hDlg,
245					    IDC_RUN_BUTTON), TRUE);
246					EnableWindow(GetDlgItem(hDlg,
247					    IDC_ADV_BUTTON), TRUE);
248					return FALSE;
249				}
250				// TODO: Check for an empty directory?
251				ntxns = GetDlgItemInt(hDlg, IDC_TXN_EDIT,
252				    &valid, FALSE);
253				if (valid == FALSE) {
254					MessageBox(hDlg,
255					L"Invalid number in transaction field.",
256					    L"Error", MB_OK);
257					EnableWindow(GetDlgItem(hDlg,
258					    IDC_INIT_BUTTON), TRUE);
259					EnableWindow(GetDlgItem(hDlg,
260					    IDC_RUN_BUTTON), TRUE);
261					EnableWindow(GetDlgItem(hDlg,
262					    IDC_ADV_BUTTON), TRUE);
263					return FALSE;
264				}
265				tpcb->createEnv(0);
266				ret = tpcb->run(ntxns);
267			} else if (LOWORD(wParam) == IDC_EXIT_BUTTON) {
268				tpcb->closeEnv();
269				EndDialog(hDlg, LOWORD(wParam));
270				DestroyWindow(hDlg);
271				DestroyWindow(hWndFrame);
272				return FALSE;
273			}
274			if (LOWORD(wParam) == IDC_INIT_BUTTON ||
275				LOWORD(wParam) == IDC_RUN_BUTTON ) {
276				if (ret == 0)
277					title = L"Results";
278				else
279					title = L"Error message";
280				written = MultiByteToWideChar(CP_ACP, NULL,
281				    tpcb->msgString, strlen(tpcb->msgString),
282					msg, sizeof(msg)/sizeof(msg[0]));
283				msg[written] = L'\0';
284				MessageBox(hDlg, msg, title, MB_OK);
285				EnableWindow(GetDlgItem(hDlg, IDC_INIT_BUTTON), TRUE);
286				EnableWindow(GetDlgItem(hDlg, IDC_RUN_BUTTON),
287				    TRUE);
288				EnableWindow(GetDlgItem(hDlg, IDC_ADV_BUTTON),
289				    TRUE);
290			}
291			break;
292		case WM_DESTROY:
293			// Same functionality as WM_COMMAND->IDC_EXIT_BUTTON
294			tpcb->closeEnv();
295			EndDialog(hDlg, LOWORD(wParam));
296			DestroyWindow(hDlg);
297			DestroyWindow(hWndFrame);
298			return FALSE;
299		default:
300			return DefWindowProc(hDlg, message, wParam, lParam);
301	}
302	return TRUE;
303}
304
305// Message handler for the Advanced dialog box
306LRESULT CALLBACK AdvancedDialog(HWND hDlg, UINT message,
307				WPARAM wParam, LPARAM lParam)
308{
309	RECT rt;
310	HWND hCurrentCheckBox;
311	int currentInt, valid;
312
313	switch (message)
314	{
315		case WM_INITDIALOG:
316			GetClientRect(GetParent(hDlg), &rt);
317			SetWindowPos(hDlg, HWND_TOP, 0, 0, rt.right, rt.bottom,
318			    SWP_SHOWWINDOW);
319			if (tpcb->fast_mode == 0) {
320				hCurrentCheckBox =
321				    GetDlgItem(hDlg, IDC_FASTMODE_CHECK);
322				SendMessage(hCurrentCheckBox, BM_SETCHECK,
323				    BST_CHECKED, 0);
324			}
325			if (tpcb->verbose == 1) {
326				hCurrentCheckBox =
327				    GetDlgItem(hDlg, IDC_VERBOSE_CHECK);
328				SendMessage(hCurrentCheckBox, BM_SETCHECK,
329				    BST_CHECKED, 0);
330			}
331			if (tpcb->cachesize != 0) {
332				SetDlgItemInt(hDlg, IDC_CACHE_EDIT,
333				    tpcb->cachesize/1024, FALSE);
334			}
335			break;
336		case WM_COMMAND:
337			if (LOWORD(wParam) == IDC_DONE_BUTTON) {
338				hCurrentCheckBox =
339				    GetDlgItem(hDlg, IDC_FASTMODE_CHECK);
340				if(BST_CHECKED == SendMessage(hCurrentCheckBox,
341				    BM_GETCHECK, NULL, NULL))
342					tpcb->fast_mode = 0;
343				else
344					tpcb->fast_mode = 1;
345				hCurrentCheckBox =
346				    GetDlgItem(hDlg, IDC_VERBOSE_CHECK);
347				if(BST_CHECKED == SendMessage(hCurrentCheckBox,
348				    BM_GETCHECK, NULL, NULL))
349					tpcb->verbose = 1;
350				else
351					tpcb->verbose = 0;
352				currentInt = GetDlgItemInt(hDlg,
353				    IDC_RANDOM_EDIT, &valid, FALSE);
354				if (valid != FALSE)
355					tpcb->rand_seed = currentInt;
356				currentInt = GetDlgItemInt(hDlg,
357				    IDC_CACHE_EDIT, &valid, FALSE);
358				if (valid != FALSE) {
359					if (currentInt < 20) {
360						MessageBox(hDlg,
361						    L"Min cache size is 20kb.",
362						    L"Error", MB_OK);
363						return FALSE;
364					}
365					tpcb->cachesize = currentInt*1024;
366				}
367				EndDialog(hDlg, LOWORD(wParam));
368				DestroyWindow(hDlg);
369			}
370			break;
371		default:
372			return DefWindowProc(hDlg, message, wParam, lParam);
373	}
374	return TRUE;
375}
376
377// Utility function to retrieve the directory name
378// from the control, and set it in the tpcb object.
379// Optionally remove and create requested directory.
380BOOL
381GetHomeDirectory(HWND hDlg, BOOL init)
382{
383	wchar_t wdirname[MAX_PATH];
384	DWORD attrs;
385
386	if (GetDlgItemText(hDlg, IDC_HOME_EDIT, wdirname, MAX_PATH) == 0)
387		tpcb->setHomeDir(TESTDIR);
388	else
389		tpcb->setHomeDirW(wdirname);
390
391	if (init == TRUE) {
392		// Ensure that wdirname holds the correct version:
393		tpcb->getHomeDirW(wdirname, MAX_PATH);
394
395		// If the directory exists, ensure that it is empty.
396		attrs = GetFileAttributes(wdirname);
397		if (attrs == FILE_ATTRIBUTE_DIRECTORY)
398			RecursiveDirRemove(wdirname);
399		else if (attrs == FILE_ATTRIBUTE_NORMAL)
400			DeleteFile(wdirname);
401		else if (attrs != 0xFFFFFFFF) {
402			// Not a directory or normal file, don't try to remove
403			// it, or create a new directory over the top.
404			return FALSE;
405		}
406
407		// Create the requested directory.
408		return CreateDirectory(wdirname, NULL);
409	}
410	return TRUE;
411}
412
413BOOL
414RecursiveDirRemove(wchar_t *dirname)
415{
416	HANDLE hFind;  // file handle
417	WIN32_FIND_DATA findFileData;
418
419	wchar_t DirPath[MAX_PATH];
420	wchar_t FileName[MAX_PATH];
421
422	wcscpy(DirPath, dirname);
423	wcscat(DirPath, L"\\*");    // searching all files
424	wcscpy(FileName, dirname);
425	wcscat(FileName, L"\\");
426
427	MessageBox(hWndDlgMain, L"Cleaning directory.", L"Message", MB_OK);
428	// find the first file
429	if ((hFind = FindFirstFile(DirPath,&findFileData)) ==
430       	INVALID_HANDLE_VALUE)
431		return FALSE;
432
433	wcscpy(DirPath,FileName);
434	MessageBox(hWndDlgMain, L"Found files in directory.",
435	    L"Message", MB_OK);
436
437	bool bSearch = true;
438	do {
439
440		wcscpy(FileName + wcslen(DirPath), findFileData.cFileName);
441		if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
442		{
443			// we have found a directory, recurse
444			if (!RecursiveDirRemove(FileName))
445				break; // directory couldn't be deleted
446		} else {
447			if (findFileData.dwFileAttributes &
448			    FILE_ATTRIBUTE_READONLY)
449				SetFileAttributes(findFileData.cFileName,
450				    FILE_ATTRIBUTE_NORMAL);
451			if (!DeleteFile(FileName)) {
452				MessageBox(hWndDlgMain, L"Delete failed.",
453				    L"Message", MB_OK);
454				break; // file couldn't be deleted
455			}
456		}
457	} while (FindNextFile(hFind,&findFileData));
458
459	FindClose(hFind);  // closing file handle
460	return RemoveDirectory(dirname); // remove the empty directory
461}
462
463// Callback function used to receive error messages from DB
464// Needs to have a C calling convention.
465// Using this function, since the implementation is presenting
466// the error to the user in a message box.
467extern "C" {
468void tpcb_errcallback(const DB_ENV *, const char *errpfx, const char *errstr)
469{
470	wchar_t wstr[ERR_STRING_MAX];
471	memset(wstr, 0, sizeof(wstr));
472	MultiByteToWideChar(CP_ACP, 0, errstr, strlen(errstr),
473	    wstr, ERR_STRING_MAX-1);
474	MessageBox(hWndDlgMain, wstr, L"Error Message", MB_OK);
475	exit(1);
476}
477}
478
479