b54c8e4f1115b563ab9bb4a26296fb4b76aa5b40
[picodrive.git] / platform / win32 / GenaDrive / Main.cpp
1 #include "app.h"\r
2 #include "version.h"\r
3 #include <crtdbg.h>\r
4 #include <commdlg.h>\r
5 #include "../../common/readpng.h"\r
6 \r
7 char *romname=NULL;\r
8 HWND FrameWnd=NULL;\r
9 RECT FrameRectMy;\r
10 int lock_to_1_1 = 1;\r
11 static HWND PicoSwWnd=NULL, PicoPadWnd=NULL;\r
12 \r
13 int MainWidth=720,MainHeight=480;\r
14 \r
15 static HMENU mmain = 0, mdisplay = 0, mpicohw = 0;\r
16 static int rom_loaded = 0;\r
17 static HBITMAP ppad_bmp = 0;\r
18 static HBITMAP ppage_bmps[7] = { 0, };\r
19 static char rom_name[0x20*3+1];\r
20 \r
21 static void UpdateRect()\r
22 {\r
23   WINDOWINFO wi;\r
24   memset(&wi, 0, sizeof(wi));\r
25   wi.cbSize = sizeof(wi);\r
26   GetWindowInfo(FrameWnd, &wi);\r
27   FrameRectMy = wi.rcClient;\r
28 }\r
29 \r
30 static int extract_rom_name(char *dest, const unsigned char *src, int len)\r
31 {\r
32         char *p = dest, s_old = 0;\r
33         int i;\r
34 \r
35         for (i = len - 1; i >= 0; i--)\r
36         {\r
37                 if (src[i^1] != ' ') break;\r
38         }\r
39         len = i + 1;\r
40 \r
41         for (i = 0; i < len; i++)\r
42         {\r
43                 unsigned char s = src[i^1];\r
44                 if (s == 0x20 && s_old == 0x20) continue;\r
45                 else if (s >= 0x20 && s < 0x7f && s != '%')\r
46                 {\r
47                         *p++ = s;\r
48                 }\r
49                 else\r
50                 {\r
51                         sprintf(p, "%%%02x", s);\r
52                         p += 3;\r
53                 }\r
54                 s_old = s;\r
55         }\r
56         *p = 0;\r
57 \r
58         return p - dest;\r
59 }\r
60 \r
61 \r
62 static HBITMAP png2hb(const char *fname, int is_480)\r
63 {\r
64   BITMAPINFOHEADER bih;\r
65   HBITMAP bmp;\r
66   void *bmem;\r
67   int ret;\r
68 \r
69   bmem = calloc(1, is_480 ? 480*240*3 : 320*240*3);\r
70   if (bmem == NULL) return NULL;\r
71   ret = readpng(bmem, fname, is_480 ? READPNG_480_24 : READPNG_320_24);\r
72   if (ret != 0) {\r
73     free(bmem);\r
74     return NULL;\r
75   }\r
76 \r
77   memset(&bih, 0, sizeof(bih));\r
78   bih.biSize = sizeof(bih);\r
79   bih.biWidth = is_480 ? 480 : 320;\r
80   bih.biHeight = -240;\r
81   bih.biPlanes = 1;\r
82   bih.biBitCount = 24;\r
83   bih.biCompression = BI_RGB;\r
84   bmp = CreateDIBitmap(GetDC(FrameWnd), &bih, CBM_INIT, bmem, (BITMAPINFO *)&bih, 0);\r
85   if (bmp == NULL)\r
86     lprintf("CreateDIBitmap failed with %i", GetLastError());\r
87 \r
88   free(bmem);\r
89   return bmp;\r
90 }\r
91 \r
92 static void PrepareForROM(unsigned char *rom_data)\r
93 {\r
94   int i, ret, show = PicoAHW & PAHW_PICO;\r
95   EnableMenuItem(mmain, 2, MF_BYPOSITION|(show ? MF_ENABLED : MF_GRAYED));\r
96   ShowWindow(PicoPadWnd, show ? SW_SHOWNA : SW_HIDE);\r
97   ShowWindow(PicoSwWnd, show ? SW_SHOWNA : SW_HIDE);\r
98   CheckMenuItem(mpicohw, 1210, show ? MF_CHECKED : MF_UNCHECKED);\r
99   CheckMenuItem(mpicohw, 1211, show ? MF_CHECKED : MF_UNCHECKED);\r
100   PostMessage(FrameWnd, WM_COMMAND, 1220 + PicoPicohw.page, 0);\r
101   DrawMenuBar(FrameWnd);\r
102   InvalidateRect(PicoSwWnd, NULL, 1);\r
103 \r
104   PicoPicohw.pen_pos[0] =\r
105   PicoPicohw.pen_pos[1] = 0x8000;\r
106   PicoPadAdd = 0;\r
107 \r
108   ret = extract_rom_name(rom_name, rom_data + 0x150, 0x20);\r
109   if (ret == 0)\r
110     extract_rom_name(rom_name, rom_data + 0x130, 0x20);\r
111 \r
112   if (show)\r
113   {\r
114     char path[MAX_PATH], *p;\r
115     GetModuleFileName(NULL, path, sizeof(path) - 32);\r
116     p = strrchr(path, '\\');\r
117     if (p == NULL) p = path;\r
118     else p++;\r
119     if (ppad_bmp == NULL) {\r
120       strcpy(p, "pico\\pad.png");\r
121       ppad_bmp = png2hb(path, 0);\r
122     }\r
123 \r
124     for (i = 0; i < 7; i++) {\r
125       if (ppage_bmps[i] != NULL) DeleteObject(ppage_bmps[i]);\r
126       sprintf(p, "pico\\%s_%i.png", rom_name, i);\r
127       ppage_bmps[i] = png2hb(path, 1);\r
128     }\r
129   }\r
130 }\r
131 \r
132 static void LoadROM(const char *cmdpath)\r
133 {\r
134   static char rompath[MAX_PATH] = { 0, };\r
135   unsigned char *rom_data_new = NULL;\r
136   unsigned int rom_size = 0;\r
137   pm_file *rom = NULL;\r
138   int oldwait=LoopWait;\r
139   int i, ret;\r
140 \r
141   if (cmdpath) {\r
142     strcpy(rompath, cmdpath + (cmdpath[0] == '\"' ? 1 : 0));\r
143     if (rompath[strlen(rompath)-1] == '\"') rompath[strlen(rompath)-1] = 0;\r
144     if (strlen(rompath) > 4) rom = pm_open(rompath);\r
145   }\r
146 \r
147   if (!rom) {\r
148     OPENFILENAME of; ZeroMemory(&of, sizeof(OPENFILENAME));\r
149     of.lStructSize = sizeof(OPENFILENAME);\r
150     of.lpstrFilter = "ROMs\0*.smd;*.bin;*.gen;*.zip\0";\r
151     of.lpstrFile = rompath; rompath[0] = 0;\r
152     of.nMaxFile = MAX_PATH;\r
153     of.Flags = OFN_FILEMUSTEXIST|OFN_HIDEREADONLY;\r
154     of.hwndOwner = FrameWnd;\r
155     if (!GetOpenFileName(&of)) return;\r
156     rom = pm_open(rompath);\r
157     if (!rom) { error("failed to open ROM"); return; }\r
158   }\r
159 \r
160   ret=PicoCartLoad(rom, &rom_data_new, &rom_size);\r
161   pm_close(rom);\r
162   if (ret) {\r
163     error("failed to load ROM");\r
164     return;\r
165   }\r
166 \r
167   // halt the work thread..\r
168   // just a hack, should've used proper sync. primitives here, but who will use this emu anyway..\r
169   LoopWaiting=0;\r
170   LoopWait=1;\r
171   for (i = 0; LoopWaiting == 0 && i < 10; i++) Sleep(100);\r
172 \r
173   PicoCartUnload();\r
174   PicoCartInsert(rom_data_new, rom_size);\r
175 \r
176   PrepareForROM(rom_data_new);\r
177 \r
178   rom_loaded = 1;\r
179   romname = rompath;\r
180   LoopWait=0;\r
181 }\r
182 \r
183 static int rect_widths[4]  = { 320, 256, 640, 512 };\r
184 static int rect_heights[4] = { 224, 224, 448, 448 };\r
185 \r
186 // Window proc for the frame window:\r
187 static LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam)\r
188 {\r
189   POINT pt;\r
190   RECT rc;\r
191   int i;\r
192   switch (msg)\r
193   {\r
194     case WM_CLOSE:   PostQuitMessage(0); return 0;\r
195     case WM_DESTROY: FrameWnd=NULL; break; // Blank handle\r
196     case WM_SIZE:\r
197     case WM_MOVE:\r
198     case WM_SIZING:  UpdateRect(); break;\r
199     case WM_COMMAND:\r
200       switch (LOWORD(wparam))\r
201       {\r
202         case 1000: LoadROM(NULL); break;\r
203         case 1001: PicoReset(); return 0;\r
204         case 1002: PostQuitMessage(0); return 0;\r
205         case 1100:\r
206         case 1101:\r
207         case 1102:\r
208         case 1103:\r
209           LoopWait=1; // another sync hack\r
210           for (i = 0; !LoopWaiting && i < 10; i++) Sleep(10);\r
211           FrameRectMy.right  = FrameRectMy.left + rect_widths[wparam&3];\r
212           FrameRectMy.bottom = FrameRectMy.top  + rect_heights[wparam&3];\r
213           AdjustWindowRect(&FrameRectMy, WS_OVERLAPPEDWINDOW, 1);\r
214           MoveWindow(hwnd, FrameRectMy.left, FrameRectMy.top,\r
215             FrameRectMy.right-FrameRectMy.left, FrameRectMy.bottom-FrameRectMy.top, 1);\r
216           UpdateRect();\r
217           if (HIWORD(wparam) == 0) { // locally sent\r
218             lock_to_1_1=0;\r
219             CheckMenuItem(mdisplay, 1104, MF_UNCHECKED);\r
220           }\r
221           if (rom_loaded) LoopWait=0;\r
222           return 0;\r
223         case 1104:\r
224           lock_to_1_1=!lock_to_1_1;\r
225           CheckMenuItem(mdisplay, 1104, lock_to_1_1 ? MF_CHECKED : MF_UNCHECKED);\r
226           return 0;\r
227         case 1210:\r
228         case 1211:\r
229           i = IsWindowVisible((LOWORD(wparam)&1) ? PicoPadWnd : PicoSwWnd);\r
230           i = !i;\r
231           ShowWindow((LOWORD(wparam)&1) ? PicoPadWnd : PicoSwWnd, i ? SW_SHOWNA : SW_HIDE);\r
232           CheckMenuItem(mpicohw, LOWORD(wparam), i ? MF_CHECKED : MF_UNCHECKED);\r
233           return 0;\r
234         case 1220:\r
235         case 1221:\r
236         case 1222:\r
237         case 1223:\r
238         case 1224:\r
239         case 1225:\r
240         case 1226:\r
241           PicoPicohw.page = LOWORD(wparam) % 10;\r
242           for (i = 0; i < 7; i++)\r
243             CheckMenuItem(mpicohw, 1220 + i, MF_UNCHECKED);\r
244           CheckMenuItem(mpicohw, 1220 + PicoPicohw.page, MF_CHECKED);\r
245           InvalidateRect(PicoSwWnd, NULL, 1);\r
246           return 0;\r
247         case 1300:\r
248           MessageBox(FrameWnd, "PicoDrive v" VERSION " (c) notaz, 2006-2008\n"\r
249               "SVP and Pico demo edition\n\n"\r
250               "Credits:\n"\r
251               "fDave: base code of PicoDrive, GenaDrive (the frontend)\n"\r
252               "Chui: Fame/C\n"\r
253               "NJ: CZ80\n"\r
254               "MAME devs: YM2612 and SN76496 cores\n"\r
255               "Stéphane Dallongeville: Gens code, base of Fame/C (C68K), CZ80\n"\r
256               "Tasco Deluxe: SVP RE work\n"\r
257               "Pierpaolo Prazzoli: info about SSP16 chips\n",\r
258               "About", 0);\r
259           return 0;\r
260       }\r
261       break;\r
262     case WM_TIMER:\r
263       GetCursorPos(&pt);\r
264       GetWindowRect(PicoSwWnd, &rc);\r
265       if (PtInRect(&rc, pt)) break;\r
266       GetWindowRect(PicoPadWnd, &rc);\r
267       if (PtInRect(&rc, pt)) break;\r
268       PicoPicohw.pen_pos[0] |= 0x8000;\r
269       PicoPicohw.pen_pos[1] |= 0x8000;\r
270       PicoPadAdd = 0;\r
271       break;\r
272   }\r
273 \r
274   return DefWindowProc(hwnd,msg,wparam,lparam);\r
275 }\r
276 \r
277 static void key_down(WPARAM key)\r
278 {\r
279   switch (key) {\r
280     case VK_LEFT:  PicoPadAdd |=    4; break;\r
281     case VK_RIGHT: PicoPadAdd |=    8; break;\r
282     case VK_UP:    PicoPadAdd |=    1; break;\r
283     case VK_DOWN:  PicoPadAdd |=    2; break;\r
284     case 'X':      PicoPadAdd |= 0x10; break;\r
285   }\r
286 }\r
287 \r
288 static void key_up(WPARAM key)\r
289 {\r
290   switch (key) {\r
291     case VK_LEFT:  PicoPadAdd &= ~0x04; break;\r
292     case VK_RIGHT: PicoPadAdd &= ~0x08; break;\r
293     case VK_UP:    PicoPadAdd &= ~0x01; break;\r
294     case VK_DOWN:  PicoPadAdd &= ~0x02; break;\r
295     case 'X':      PicoPadAdd &= ~0x10; break;\r
296   }\r
297 }\r
298 \r
299 static LRESULT CALLBACK PicoSwWndProc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam)\r
300 {\r
301   PAINTSTRUCT ps;\r
302   HDC hdc, hdc2;\r
303 \r
304   switch (msg)\r
305   {\r
306     case WM_DESTROY: PicoSwWnd=NULL; break;\r
307     case WM_LBUTTONDOWN: PicoPadAdd |=  0x20; return 0;\r
308     case WM_LBUTTONUP:   PicoPadAdd &= ~0x20; return 0;\r
309     case WM_MOUSEMOVE:\r
310       if (HIWORD(lparam) < 0x20) break;\r
311       PicoPicohw.pen_pos[0] = 0x03c + LOWORD(lparam) * 2/3;\r
312       PicoPicohw.pen_pos[1] = 0x2f8 + HIWORD(lparam) - 0x20;\r
313       SetTimer(FrameWnd, 100, 1000, NULL);\r
314       break;\r
315     case WM_KEYDOWN: key_down(wparam); break;\r
316     case WM_KEYUP:   key_up(wparam);   break;\r
317     case WM_PAINT:\r
318       hdc = BeginPaint(hwnd, &ps);\r
319       if (ppage_bmps[PicoPicohw.page] == NULL)\r
320       {\r
321         SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT));\r
322         SetTextColor(hdc, RGB(255, 255, 255));\r
323         SetBkColor(hdc, RGB(0, 0, 0));\r
324         TextOut(hdc, 2,  2, "missing PNGs for", 16);\r
325         TextOut(hdc, 2, 18, rom_name, strlen(rom_name));\r
326       }\r
327       else\r
328       {\r
329         hdc2 = CreateCompatibleDC(GetDC(FrameWnd));\r
330         SelectObject(hdc2, ppage_bmps[PicoPicohw.page]);\r
331         BitBlt(hdc, 0, 0, 480, 240, hdc2, 0, 0, SRCCOPY);\r
332         DeleteDC(hdc2);\r
333       }\r
334       EndPaint(hwnd, &ps);\r
335       return 0;\r
336   }\r
337 \r
338   return DefWindowProc(hwnd,msg,wparam,lparam);\r
339 }\r
340 \r
341 static LRESULT CALLBACK PicoPadWndProc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam)\r
342 {\r
343   PAINTSTRUCT ps;\r
344   HDC hdc, hdc2;\r
345 \r
346   switch (msg)\r
347   {\r
348     case WM_DESTROY: PicoPadWnd=NULL; break;\r
349     case WM_LBUTTONDOWN: PicoPadAdd |=  0x20; return 0;\r
350     case WM_LBUTTONUP:   PicoPadAdd &= ~0x20; return 0;\r
351     case WM_MOUSEMOVE:\r
352       PicoPicohw.pen_pos[0] = 0x03c + LOWORD(lparam);\r
353       PicoPicohw.pen_pos[1] = 0x1fc + HIWORD(lparam);\r
354       SetTimer(FrameWnd, 100, 1000, NULL);\r
355       break;\r
356     case WM_KEYDOWN: key_down(wparam); break;\r
357     case WM_KEYUP:   key_up(wparam);   break;\r
358     case WM_PAINT:\r
359       if (ppad_bmp == NULL) break;\r
360       hdc = BeginPaint(hwnd, &ps);\r
361       hdc2 = CreateCompatibleDC(GetDC(FrameWnd));\r
362       SelectObject(hdc2, ppad_bmp);\r
363       BitBlt(hdc, 0, 0, 320, 240, hdc2, 0, 0, SRCCOPY);\r
364       EndPaint(hwnd, &ps);\r
365       DeleteDC(hdc2);\r
366       return 0;\r
367   }\r
368 \r
369   return DefWindowProc(hwnd,msg,wparam,lparam);\r
370 }\r
371 \r
372 \r
373 static int FrameInit()\r
374 {\r
375   WNDCLASS wc;\r
376   RECT rect={0,0,0,0};\r
377   HMENU mfile;\r
378   int style=0;\r
379   int left=0,top=0,width=0,height=0;\r
380 \r
381   memset(&wc,0,sizeof(wc));\r
382 \r
383   // Register the window class:\r
384   wc.lpfnWndProc=WndProc;\r
385   wc.hInstance=GetModuleHandle(NULL);\r
386   wc.hCursor=LoadCursor(NULL,IDC_ARROW);\r
387   wc.hbrBackground=CreateSolidBrush(0);\r
388   wc.lpszClassName="PicoMainFrame";\r
389   RegisterClass(&wc);\r
390 \r
391   wc.lpszClassName="PicoSwWnd";\r
392   wc.lpfnWndProc=PicoSwWndProc;\r
393   RegisterClass(&wc);\r
394 \r
395   wc.lpszClassName="PicoPadWnd";\r
396   wc.lpfnWndProc=PicoPadWndProc;\r
397   RegisterClass(&wc);\r
398 \r
399   rect.right =320;//MainWidth;\r
400   rect.bottom=224;//MainHeight;\r
401 \r
402   // Adjust size of windows based on borders:\r
403   style=WS_OVERLAPPEDWINDOW;\r
404   AdjustWindowRect(&rect,style,1);\r
405   width =rect.right-rect.left;\r
406   height=rect.bottom-rect.top;\r
407 \r
408   // Place window in the centre of the screen:\r
409   SystemParametersInfo(SPI_GETWORKAREA,0,&rect,0);\r
410   left=rect.left+rect.right;\r
411   top=rect.top+rect.bottom;\r
412 \r
413   left-=width; left>>=1;\r
414   top-=height; top>>=1;\r
415 \r
416   // Create menu:\r
417   mfile = CreateMenu();\r
418   InsertMenu(mfile, -1, MF_BYPOSITION|MF_STRING, 1000, "&Load ROM");\r
419   InsertMenu(mfile, -1, MF_BYPOSITION|MF_STRING, 1001, "&Reset");\r
420   InsertMenu(mfile, -1, MF_BYPOSITION|MF_STRING, 1002, "E&xit");\r
421   mdisplay = CreateMenu();\r
422   InsertMenu(mdisplay, -1, MF_BYPOSITION|MF_STRING, 1100, "320x224");\r
423   InsertMenu(mdisplay, -1, MF_BYPOSITION|MF_STRING, 1101, "256x224");\r
424   InsertMenu(mdisplay, -1, MF_BYPOSITION|MF_STRING, 1102, "640x448");\r
425   InsertMenu(mdisplay, -1, MF_BYPOSITION|MF_STRING, 1103, "512x448");\r
426   InsertMenu(mdisplay, -1, MF_BYPOSITION|MF_STRING, 1104, "Lock to 1:1");\r
427   mpicohw = CreateMenu();\r
428   InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1210, "Show &Storyware");\r
429   InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1211, "Show &Drawing pad");\r
430   InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_SEPARATOR, 0, NULL);\r
431   InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1220, "Title page (&0)");\r
432   InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1221, "Page &1");\r
433   InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1222, "Page &2");\r
434   InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1223, "Page &3");\r
435   InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1224, "Page &4");\r
436   InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1225, "Page &5");\r
437   InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1226, "Page &6");\r
438   mmain = CreateMenu();\r
439   InsertMenu(mmain, -1, MF_BYPOSITION|MF_STRING|MF_POPUP, (UINT_PTR) mfile,    "&File");\r
440   InsertMenu(mmain, -1, MF_BYPOSITION|MF_STRING|MF_POPUP, (UINT_PTR) mdisplay, "&Display");\r
441   InsertMenu(mmain, -1, MF_BYPOSITION|MF_STRING|MF_POPUP, (UINT_PTR) mpicohw,  "&Pico");\r
442   EnableMenuItem(mmain, 2, MF_BYPOSITION|MF_GRAYED);\r
443 //  InsertMenu(mmain, -1, MF_BYPOSITION|MF_STRING|MF_POPUP, 1200, "&Config");\r
444   InsertMenu(mmain, -1, MF_BYPOSITION|MF_STRING, 1300, "&About");\r
445 \r
446   // Create the window:\r
447   FrameWnd=CreateWindow("PicoMainFrame","PicoDrive " VERSION,style|WS_VISIBLE,\r
448     left,top,width,height,NULL,mmain,NULL,NULL);\r
449 \r
450   CheckMenuItem(mdisplay, 1104, lock_to_1_1 ? MF_CHECKED : MF_UNCHECKED);\r
451   ShowWindow(FrameWnd, SW_NORMAL);\r
452   UpdateWindow(FrameWnd);\r
453   UpdateRect();\r
454 \r
455   // create Pico windows\r
456   style = WS_OVERLAPPED|WS_CAPTION|WS_BORDER;\r
457   rect.left=rect.top=0;\r
458   rect.right =320;\r
459   rect.bottom=224;\r
460 \r
461   AdjustWindowRect(&rect,style,1);\r
462   width =rect.right-rect.left;\r
463   height=rect.bottom-rect.top;\r
464 \r
465   left += 326;\r
466   PicoSwWnd=CreateWindow("PicoSwWnd","Storyware",style,\r
467     left,top,width+160,height,FrameWnd,NULL,NULL,NULL);\r
468 \r
469   top += 266;\r
470   PicoPadWnd=CreateWindow("PicoPadWnd","Drawing Pad",style,\r
471     left,top,width,height,FrameWnd,NULL,NULL,NULL);\r
472 \r
473   return 0;\r
474 }\r
475 \r
476 // --------------------\r
477 \r
478 static DWORD WINAPI ThreadCode(void *)\r
479 {\r
480   LoopCode();\r
481   return 0;\r
482 }\r
483 \r
484 int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR cmdline,int)\r
485 {\r
486   MSG msg;\r
487   int ret=0;\r
488   DWORD tid=0;\r
489   HANDLE thread=NULL;\r
490 \r
491   FrameInit();\r
492   ret=LoopInit(); if (ret) goto end0;\r
493 \r
494   // Make another thread to run LoopCode():\r
495   LoopQuit=0;\r
496   LoopWait=1; // wait for ROM to be loaded\r
497   thread=CreateThread(NULL,0,ThreadCode,NULL,0,&tid);\r
498 \r
499   LoadROM(cmdline);\r
500 \r
501   // Main window loop:\r
502   for (;;)\r
503   {\r
504     GetMessage(&msg,NULL,0,0);\r
505     if (msg.message==WM_QUIT) break;\r
506 \r
507     TranslateMessage(&msg);\r
508     DispatchMessage(&msg);\r
509   }\r
510 \r
511   // Signal thread to quit and wait for it to exit:\r
512   LoopQuit=1; WaitForSingleObject(thread,5000);\r
513   CloseHandle(thread); thread=NULL;\r
514 \r
515 end0:\r
516   LoopExit();\r
517   DestroyWindow(FrameWnd);\r
518 \r
519   _CrtDumpMemoryLeaks();\r
520   return 0;\r
521 }\r
522 \r
523 extern void error(char *text)\r
524 {\r
525   MessageBox(FrameWnd, text, "Error", 0);\r
526 }\r
527 \r