Sync with trunk r63793.
[reactos.git] / dll / win32 / shimgvw / shimgvw.c
1 /*
2 *
3 * PROJECT: ReactOS Picture and Fax Viewer
4 * FILE: dll/win32/shimgvw/shimgvw.c
5 * PURPOSE: shimgvw.dll
6 * PROGRAMMER: Dmitry Chapyshev (dmitry@reactos.org)
7 *
8 * UPDATE HISTORY:
9 * 28/05/2008 Created
10 */
11
12 #define WIN32_NO_STATUS
13 #define _INC_WINDOWS
14 #define COM_NO_WINDOWS_H
15
16 #include <stdarg.h>
17
18 #include <windef.h>
19 #include <winbase.h>
20 #include <winnls.h>
21 #include <winreg.h>
22 #include <wingdi.h>
23 #include <objbase.h>
24 #include <commctrl.h>
25 #include <commdlg.h>
26 #include <gdiplus.h>
27 #include <tchar.h>
28 #include <strsafe.h>
29
30 #define NDEBUG
31 #include <debug.h>
32
33 #include "shimgvw.h"
34
35
36 HINSTANCE hInstance;
37 SHIMGVW_SETTINGS shiSettings;
38 GpImage *image;
39 WNDPROC PrevProc = NULL;
40
41 HWND hDispWnd, hToolBar;
42
43 /* ToolBar Buttons */
44 static const TBBUTTON Buttons [] =
45 { /* iBitmap, idCommand, fsState, fsStyle, bReserved[2], dwData, iString */
46 {TBICON_PREV, IDC_PREV, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0},
47 {TBICON_NEXT, IDC_NEXT, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0},
48 {15, 0, TBSTATE_ENABLED, BTNS_SEP, {0}, 0, 0},
49 {TBICON_ZOOMP, IDC_ZOOMP, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0},
50 {TBICON_ZOOMM, IDC_ZOOMM, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0},
51 {15, 0, TBSTATE_ENABLED, BTNS_SEP, {0}, 0, 0},
52 {TBICON_ROT1, IDC_ROT1, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0},
53 {TBICON_ROT2, IDC_ROT2, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0},
54 {15, 0, TBSTATE_ENABLED, BTNS_SEP, {0}, 0, 0},
55 {TBICON_SAVE, IDC_SAVE, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0},
56 {TBICON_PRINT, IDC_PRINT, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0},
57 };
58
59 static void pLoadImage(LPWSTR szOpenFileName)
60 {
61 if (GetFileAttributesW(szOpenFileName) == 0xFFFFFFFF)
62 {
63 DPRINT1("File %s not found!\n", szOpenFileName);
64 return;
65 }
66
67 GdipLoadImageFromFile(szOpenFileName, &image);
68 if (!image)
69 {
70 DPRINT1("GdipLoadImageFromFile() failed\n");
71 }
72 }
73
74 static void pSaveImageAs(HWND hwnd)
75 {
76 OPENFILENAMEW sfn;
77 ImageCodecInfo *codecInfo;
78 WCHAR szSaveFileName[MAX_PATH];
79 WCHAR szFilterMask[2048];
80 GUID rawFormat;
81 UINT num;
82 UINT size;
83 UINT sizeRemain;
84 UINT j;
85 WCHAR *c;
86
87 ZeroMemory(szSaveFileName, sizeof(szSaveFileName));
88 ZeroMemory(szFilterMask, sizeof(szFilterMask));
89 ZeroMemory(&sfn, sizeof(sfn));
90 sfn.lStructSize = sizeof(sfn);
91 sfn.hwndOwner = hwnd;
92 sfn.hInstance = hInstance;
93 sfn.lpstrFile = szSaveFileName;
94 sfn.lpstrFilter = szFilterMask;
95 sfn.nMaxFile = MAX_PATH;
96 sfn.Flags = OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY;
97
98 GdipGetImageEncodersSize(&num, &size);
99 codecInfo = malloc(size);
100 if (!codecInfo)
101 {
102 DPRINT1("malloc() failed in pSaveImageAs()\n");
103 return;
104 }
105
106 GdipGetImageEncoders(num, size, codecInfo);
107 GdipGetImageRawFormat(image, &rawFormat);
108
109 sizeRemain = sizeof(szFilterMask);
110 c = szFilterMask;
111
112 for (j = 0; j < num; ++j)
113 {
114 StringCbPrintfExW(c, sizeRemain, &c, &sizeRemain, 0, L"%ls (%ls)", codecInfo[j].FormatDescription, codecInfo[j].FilenameExtension);
115
116 /* Skip the NULL character */
117 c++;
118 sizeRemain -= sizeof(*c);
119
120 StringCbPrintfExW(c, sizeRemain, &c, &sizeRemain, 0, L"%ls", codecInfo[j].FilenameExtension);
121
122 /* Skip the NULL character */
123 c++;
124 sizeRemain -= sizeof(*c);
125
126 if (IsEqualGUID(&rawFormat, &codecInfo[j].FormatID) == TRUE)
127 {
128 sfn.nFilterIndex = j + 1;
129 }
130 }
131
132 if (GetSaveFileNameW(&sfn))
133 {
134 if (GdipSaveImageToFile(image, szSaveFileName, &codecInfo[sfn.nFilterIndex - 1].Clsid, NULL) != Ok)
135 {
136 DPRINT1("GdipSaveImageToFile() failed\n");
137 }
138 }
139
140 free(codecInfo);
141 }
142
143 static VOID
144 ImageView_DrawImage(HWND hwnd)
145 {
146 GpGraphics *graphics;
147 UINT uImgWidth, uImgHeight;
148 UINT height = 0, width = 0, x = 0, y = 0;
149 PAINTSTRUCT ps;
150 RECT rect;
151 HDC hdc;
152
153 hdc = BeginPaint(hwnd, &ps);
154 if (!hdc)
155 {
156 DPRINT1("BeginPaint() failed\n");
157 return;
158 }
159
160 GdipCreateFromHDC(hdc, &graphics);
161 if (!graphics)
162 {
163 DPRINT1("GdipCreateFromHDC() failed\n");
164 return;
165 }
166
167 GdipGetImageWidth(image, &uImgWidth);
168 GdipGetImageHeight(image, &uImgHeight);
169
170 if (GetClientRect(hwnd, &rect))
171 {
172 FillRect(hdc, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
173
174 if ((rect.right == uImgWidth)&&(rect.bottom == uImgHeight))
175 {
176 x = 0, y = 0, width = rect.right, height = rect.bottom;
177 }
178 else if ((rect.right >= uImgWidth)&&(rect.bottom >= uImgHeight))
179 {
180 x = (rect.right/2)-(uImgWidth/2);
181 y = (rect.bottom/2)-(uImgHeight/2);
182 width = uImgWidth;
183 height = uImgHeight;
184 }
185 else if ((rect.right < uImgWidth)||(rect.bottom < uImgHeight))
186 {
187 if (rect.bottom < uImgHeight)
188 {
189 height = rect.bottom;
190 width = uImgWidth*(UINT)rect.bottom/uImgHeight;
191 x = (rect.right/2)-(width/2);
192 y = (rect.bottom/2)-(height/2);
193 }
194 if (rect.right < uImgWidth)
195 {
196 width = rect.right;
197 height = uImgHeight*(UINT)rect.right/uImgWidth;
198 x = (rect.right/2)-(width/2);
199 y = (rect.bottom/2)-(height/2);
200 }
201 if ((height > rect.bottom)||(width > rect.right))
202 {
203 for (;;)
204 {
205 if (((int)width - 1 < 0)||((int)height - 1 < 0)) break;
206 width -= 1;
207 height -= 1;
208 y = (rect.bottom/2)-(height/2);
209 x = (rect.right/2)-(width/2);
210 if ((height < rect.bottom)&&(width < rect.right)) break;
211 }
212 }
213 }
214 else if ((rect.right <= uImgWidth)&&(rect.bottom <= uImgHeight))
215 {
216 height = uImgHeight*(UINT)rect.right/uImgWidth;
217 y = (rect.bottom/2)-(height/2);
218 width = rect.right;
219
220 if ((height > rect.bottom)||(width > rect.right))
221 {
222 for (;;)
223 {
224 if (((int)width - 1 < 0)||((int)height - 1 < 0)) break;
225 width -= 1;
226 height -= 1;
227 y = (rect.bottom/2)-(height/2);
228 x = (rect.right/2)-(width/2);
229 if ((height < rect.bottom)&&(width < rect.right)) break;
230 }
231 }
232 }
233
234 DPRINT("x = %d\ny = %d\nWidth = %d\nHeight = %d\n\nrect.right = %d\nrect.bottom = %d\n\nuImgWidth = %d\nuImgHeight = %d\n", x, y, width, height, rect.right, rect.bottom, uImgWidth, uImgHeight);
235 Rectangle(hdc, x - 1, y - 1, x + width + 1, y + height + 1);
236 GdipDrawImageRect(graphics, image, x, y, width, height);
237 }
238 GdipDeleteGraphics(graphics);
239 EndPaint(hwnd, &ps);
240 }
241
242 static BOOL
243 ImageView_LoadSettings()
244 {
245 HKEY hKey;
246 DWORD dwSize;
247
248 if (RegOpenKeyEx(HKEY_CURRENT_USER, _T("Software\\ReactOS\\shimgvw"), 0, KEY_READ, &hKey) == ERROR_SUCCESS)
249 {
250 dwSize = sizeof(SHIMGVW_SETTINGS);
251 if (RegQueryValueEx(hKey, _T("Settings"), NULL, NULL, (LPBYTE)&shiSettings, &dwSize) == ERROR_SUCCESS)
252 {
253 RegCloseKey(hKey);
254 return TRUE;
255 }
256
257 RegCloseKey(hKey);
258 }
259
260 return FALSE;
261 }
262
263 static VOID
264 ImageView_SaveSettings(HWND hwnd)
265 {
266 WINDOWPLACEMENT wp;
267 HKEY hKey;
268
269 ShowWindow(hwnd, SW_HIDE);
270 wp.length = sizeof(WINDOWPLACEMENT);
271 GetWindowPlacement(hwnd, &wp);
272
273 shiSettings.Left = wp.rcNormalPosition.left;
274 shiSettings.Top = wp.rcNormalPosition.top;
275 shiSettings.Right = wp.rcNormalPosition.right;
276 shiSettings.Bottom = wp.rcNormalPosition.bottom;
277 shiSettings.Maximized = (IsZoomed(hwnd) || (wp.flags & WPF_RESTORETOMAXIMIZED));
278
279 if (RegCreateKeyEx(HKEY_CURRENT_USER, _T("Software\\ReactOS\\shimgvw"), 0, NULL,
280 REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL) == ERROR_SUCCESS)
281 {
282 RegSetValueEx(hKey, _T("Settings"), 0, REG_BINARY, (LPBYTE)&shiSettings, sizeof(SHIMGVW_SETTINGS));
283 RegCloseKey(hKey);
284 }
285 }
286
287 static BOOL
288 ImageView_CreateToolBar(HWND hwnd)
289 {
290 INT numButtons = sizeof(Buttons) / sizeof(Buttons[0]);
291
292 hToolBar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL,
293 WS_CHILD | WS_VISIBLE | TBSTYLE_FLAT | CCS_BOTTOM | TBSTYLE_TOOLTIPS,
294 0, 0, 0, 0, hwnd,
295 0, hInstance, NULL);
296 if(hToolBar != NULL)
297 {
298 HIMAGELIST hImageList;
299
300 SendMessage(hToolBar, TB_SETEXTENDEDSTYLE,
301 0, TBSTYLE_EX_HIDECLIPPEDBUTTONS);
302
303 SendMessage(hToolBar, TB_BUTTONSTRUCTSIZE,
304 sizeof(Buttons[0]), 0);
305
306 hImageList = ImageList_Create(TB_IMAGE_WIDTH, TB_IMAGE_HEIGHT, ILC_MASK | ILC_COLOR24, 1, 1);
307
308 ImageList_AddMasked(hImageList, LoadImage(hInstance, MAKEINTRESOURCE(IDB_PREVICON), IMAGE_BITMAP,
309 TB_IMAGE_WIDTH, TB_IMAGE_HEIGHT, LR_DEFAULTCOLOR), RGB(255, 255, 255));
310
311 ImageList_AddMasked(hImageList, LoadImage(hInstance, MAKEINTRESOURCE(IDB_NEXTICON), IMAGE_BITMAP,
312 TB_IMAGE_WIDTH, TB_IMAGE_HEIGHT, LR_DEFAULTCOLOR), RGB(255, 255, 255));
313
314 ImageList_AddMasked(hImageList, LoadImage(hInstance, MAKEINTRESOURCE(IDB_ZOOMPICON), IMAGE_BITMAP,
315 TB_IMAGE_WIDTH, TB_IMAGE_HEIGHT, LR_DEFAULTCOLOR), RGB(255, 255, 255));
316
317 ImageList_AddMasked(hImageList, LoadImage(hInstance, MAKEINTRESOURCE(IDB_ZOOMMICON), IMAGE_BITMAP,
318 TB_IMAGE_WIDTH, TB_IMAGE_HEIGHT, LR_DEFAULTCOLOR), RGB(255, 255, 255));
319
320 ImageList_AddMasked(hImageList, LoadImage(hInstance, MAKEINTRESOURCE(IDB_SAVEICON), IMAGE_BITMAP,
321 TB_IMAGE_WIDTH, TB_IMAGE_HEIGHT, LR_DEFAULTCOLOR), RGB(255, 255, 255));
322
323 ImageList_AddMasked(hImageList, LoadImage(hInstance, MAKEINTRESOURCE(IDB_PRINTICON), IMAGE_BITMAP,
324 TB_IMAGE_WIDTH, TB_IMAGE_HEIGHT, LR_DEFAULTCOLOR), RGB(255, 255, 255));
325
326 ImageList_AddMasked(hImageList, LoadImage(hInstance, MAKEINTRESOURCE(IDB_ROT1ICON), IMAGE_BITMAP,
327 TB_IMAGE_WIDTH, TB_IMAGE_HEIGHT, LR_DEFAULTCOLOR), RGB(255, 255, 255));
328
329 ImageList_AddMasked(hImageList, LoadImage(hInstance, MAKEINTRESOURCE(IDB_ROT2ICON), IMAGE_BITMAP,
330 TB_IMAGE_WIDTH, TB_IMAGE_HEIGHT, LR_DEFAULTCOLOR), RGB(255, 255, 255));
331
332 if (hImageList == NULL) return FALSE;
333
334 ImageList_Destroy((HIMAGELIST)SendMessage(hToolBar, TB_SETIMAGELIST,
335 0, (LPARAM)hImageList));
336
337 SendMessage(hToolBar, TB_ADDBUTTONS,
338 numButtons, (LPARAM)Buttons);
339
340 return TRUE;
341 }
342
343 return FALSE;
344 }
345
346 LRESULT CALLBACK
347 ImageView_DispWndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
348 {
349 switch (Message)
350 {
351 case WM_PAINT:
352 {
353 ImageView_DrawImage(hwnd);
354 return 0L;
355 }
356 }
357 return CallWindowProc(PrevProc, hwnd, Message, wParam, lParam);
358 }
359
360 static VOID
361 ImageView_InitControls(HWND hwnd)
362 {
363 MoveWindow(hwnd, shiSettings.Left, shiSettings.Top,
364 shiSettings.Right - shiSettings.Left,
365 shiSettings.Bottom - shiSettings.Top, TRUE);
366
367 if (shiSettings.Maximized) ShowWindow(hwnd, SW_MAXIMIZE);
368
369 hDispWnd = CreateWindowEx(0, _T("STATIC"), _T(""),
370 WS_CHILD | WS_VISIBLE,
371 0, 0, 0, 0, hwnd, NULL, hInstance, NULL);
372
373 SetClassLongPtr(hDispWnd, GCL_STYLE, CS_HREDRAW | CS_VREDRAW);
374 PrevProc = (WNDPROC) SetWindowLongPtr(hDispWnd, GWL_WNDPROC, (LPARAM) ImageView_DispWndProc);
375
376 ImageView_CreateToolBar(hwnd);
377 }
378
379 LRESULT CALLBACK
380 ImageView_WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
381 {
382 switch (Message)
383 {
384 case WM_CREATE:
385 {
386 ImageView_InitControls(hwnd);
387 return 0L;
388 }
389 case WM_COMMAND:
390 {
391 switch (wParam)
392 {
393 case IDC_PREV:
394
395 break;
396 case IDC_NEXT:
397
398 break;
399 case IDC_ZOOMP:
400
401 break;
402 case IDC_ZOOMM:
403
404 break;
405 case IDC_SAVE:
406 pSaveImageAs(hwnd);
407
408 break;
409 case IDC_PRINT:
410
411 break;
412 case IDC_ROT1:
413
414 break;
415 case IDC_ROT2:
416
417 break;
418 }
419 }
420 break;
421
422 case WM_NOTIFY:
423 {
424 LPNMHDR pnmhdr = (LPNMHDR)lParam;
425
426 switch (pnmhdr->code)
427 {
428 case TTN_GETDISPINFO:
429 {
430 LPTOOLTIPTEXT lpttt;
431 UINT idButton;
432
433 lpttt = (LPTOOLTIPTEXT)lParam;
434 idButton = (UINT)lpttt->hdr.idFrom;
435
436 switch (idButton)
437 {
438 case IDC_PREV:
439 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_PREV_PIC);
440 break;
441 case IDC_NEXT:
442 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_NEXT_PIC);
443 break;
444 case IDC_ZOOMP:
445 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_ZOOM_IN);
446 break;
447 case IDC_ZOOMM:
448 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_ZOOM_OUT);
449 break;
450 case IDC_SAVE:
451 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_SAVEAS);
452 break;
453 case IDC_PRINT:
454 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_PRINT);
455 break;
456 case IDC_ROT1:
457 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_ROT_COUNCW);
458 break;
459 case IDC_ROT2:
460 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_ROT_CLOCKW);
461 break;
462 }
463 return TRUE;
464 }
465 }
466 break;
467 }
468 case WM_SIZING:
469 {
470 LPRECT pRect = (LPRECT)lParam;
471 if (pRect->right-pRect->left < 350)
472 pRect->right = pRect->left + 350;
473
474 if (pRect->bottom-pRect->top < 290)
475 pRect->bottom = pRect->top + 290;
476 return TRUE;
477 }
478 case WM_SIZE:
479 {
480 RECT rc;
481 SendMessage(hToolBar, TB_AUTOSIZE, 0, 0);
482 SendMessage(hToolBar, TB_GETITEMRECT, 1, (LPARAM)&rc);
483 MoveWindow(hDispWnd, 1, 1, LOWORD(lParam)-1, HIWORD(lParam)-rc.bottom, TRUE);
484 return 0L;
485 }
486 case WM_DESTROY:
487 {
488 ImageView_SaveSettings(hwnd);
489 SetWindowLongPtr(hDispWnd, GWL_WNDPROC, (LPARAM) PrevProc);
490 PostQuitMessage(0);
491 break;
492 }
493 }
494
495 return DefWindowProc(hwnd, Message, wParam, lParam);
496 }
497
498 LONG WINAPI
499 ImageView_CreateWindow(HWND hwnd, LPWSTR szFileName)
500 {
501 struct GdiplusStartupInput gdiplusStartupInput;
502 ULONG_PTR gdiplusToken;
503 WNDCLASS WndClass = {0};
504 TCHAR szBuf[512];
505 HWND hMainWnd;
506 MSG msg;
507
508 if (!ImageView_LoadSettings())
509 {
510 shiSettings.Maximized = FALSE;
511 shiSettings.Left = 0;
512 shiSettings.Top = 0;
513 shiSettings.Right = 520;
514 shiSettings.Bottom = 400;
515 }
516
517 // Initialize GDI+
518 gdiplusStartupInput.GdiplusVersion = 1;
519 gdiplusStartupInput.DebugEventCallback = NULL;
520 gdiplusStartupInput.SuppressBackgroundThread = FALSE;
521 gdiplusStartupInput.SuppressExternalCodecs = FALSE;
522
523 GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
524 pLoadImage(szFileName);
525
526 // Create the window
527 WndClass.lpszClassName = _T("shimgvw_window");
528 WndClass.lpfnWndProc = ImageView_WndProc;
529 WndClass.hInstance = hInstance;
530 WndClass.style = CS_HREDRAW | CS_VREDRAW;
531 WndClass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPICON));
532 WndClass.hCursor = LoadCursor(hInstance, IDC_ARROW);
533 WndClass.hbrBackground = (HBRUSH)COLOR_WINDOW;
534
535 if (!RegisterClass(&WndClass)) return -1;
536
537 LoadString(hInstance, IDS_APPTITLE, szBuf, sizeof(szBuf) / sizeof(TCHAR));
538 hMainWnd = CreateWindow(_T("shimgvw_window"), szBuf,
539 WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CAPTION,
540 CW_USEDEFAULT, CW_USEDEFAULT,
541 0, 0, NULL, NULL, hInstance, NULL);
542
543 // Show it
544 ShowWindow(hMainWnd, SW_SHOW);
545 UpdateWindow(hMainWnd);
546
547 // Message Loop
548 while(GetMessage(&msg,NULL,0,0))
549 {
550 TranslateMessage(&msg);
551 DispatchMessageW(&msg);
552 }
553
554 if (image)
555 GdipDisposeImage(image);
556 GdiplusShutdown(gdiplusToken);
557 return -1;
558 }
559
560 VOID WINAPI
561 ImageView_FullscreenW(HWND hwnd, HINSTANCE hInst, LPCWSTR path, int nShow)
562 {
563 ImageView_CreateWindow(hwnd, (LPWSTR)path);
564 }
565
566 VOID WINAPI
567 ImageView_Fullscreen(HWND hwnd, HINSTANCE hInst, LPCWSTR path, int nShow)
568 {
569 ImageView_CreateWindow(hwnd, (LPWSTR)path);
570 }
571
572 VOID WINAPI
573 ImageView_FullscreenA(HWND hwnd, HINSTANCE hInst, LPCSTR path, int nShow)
574 {
575 WCHAR szFile[MAX_PATH];
576
577 if (MultiByteToWideChar(CP_ACP, 0, (char*)path, strlen((char*)path)+1, szFile, MAX_PATH))
578 {
579 ImageView_CreateWindow(hwnd, (LPWSTR)szFile);
580 }
581 }
582
583 VOID WINAPI
584 ImageView_PrintTo(HWND hwnd, HINSTANCE hInst, LPCWSTR path, int nShow)
585 {
586 DPRINT("ImageView_PrintTo() not implemented\n");
587 }
588
589 VOID WINAPI
590 ImageView_PrintToA(HWND hwnd, HINSTANCE hInst, LPCSTR path, int nShow)
591 {
592 DPRINT("ImageView_PrintToA() not implemented\n");
593 }
594
595 VOID WINAPI
596 ImageView_PrintToW(HWND hwnd, HINSTANCE hInst, LPCWSTR path, int nShow)
597 {
598 DPRINT("ImageView_PrintToW() not implemented\n");
599 }
600
601 BOOL WINAPI
602 DllMain(IN HINSTANCE hinstDLL,
603 IN DWORD dwReason,
604 IN LPVOID lpvReserved)
605 {
606 switch (dwReason)
607 {
608 case DLL_PROCESS_ATTACH:
609 case DLL_THREAD_ATTACH:
610 hInstance = hinstDLL;
611 break;
612 }
613
614 return TRUE;
615 }
616