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