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