1 /* 2 * PROJECT: PAINT for ReactOS 3 * LICENSE: LGPL-2.0-or-later (https://spdx.org/licenses/LGPL-2.0-or-later) 4 * PURPOSE: Initializing everything 5 * COPYRIGHT: Copyright 2015 Benedikt Freisen <b.freisen@gmx.net> 6 */ 7 8 #include "precomp.h" 9 10 #include <dlgs.h> 11 #include <mapi.h> 12 13 BOOL g_askBeforeEnlarging = FALSE; // TODO: initialize from registry 14 HINSTANCE g_hinstExe = NULL; 15 WCHAR g_szFileName[MAX_LONG_PATH] = { 0 }; 16 WCHAR g_szMailTempFile[MAX_LONG_PATH] = { 0 }; 17 BOOL g_isAFile = FALSE; 18 BOOL g_imageSaved = FALSE; 19 BOOL g_showGrid = FALSE; 20 21 CMainWindow mainWindow; 22 23 /* FUNCTIONS ********************************************************/ 24 25 void ShowOutOfMemory(void) 26 { 27 WCHAR szText[256]; 28 ::FormatMessageW(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, 29 NULL, 30 ERROR_OUTOFMEMORY, 31 0, 32 szText, _countof(szText), 33 NULL); 34 mainWindow.MessageBox(szText, NULL, MB_ICONERROR); 35 } 36 37 // get file name extension from filter string 38 static BOOL 39 FileExtFromFilter(LPWSTR pExt, OPENFILENAME *pOFN) 40 { 41 LPWSTR pchExt = pExt; 42 *pchExt = 0; 43 44 DWORD nIndex = 1; 45 for (LPCWSTR pch = pOFN->lpstrFilter; *pch; ++nIndex) 46 { 47 pch += lstrlen(pch) + 1; 48 if (pOFN->nFilterIndex == nIndex) 49 { 50 for (++pch; *pch && *pch != L';'; ++pch) 51 { 52 *pchExt++ = *pch; 53 } 54 *pchExt = 0; 55 CharLower(pExt); 56 return TRUE; 57 } 58 pch += wcslen(pch) + 1; 59 } 60 return FALSE; 61 } 62 63 // Hook procedure for OPENFILENAME to change the file name extension 64 static UINT_PTR APIENTRY 65 OFNHookProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 66 { 67 HWND hParent; 68 OFNOTIFYW *pon; 69 WCHAR Path[MAX_PATH]; 70 switch (uMsg) 71 { 72 case WM_NOTIFY: 73 pon = (OFNOTIFYW *)lParam; 74 if (pon->hdr.code == CDN_TYPECHANGE) 75 { 76 hParent = GetParent(hwnd); 77 SendMessageW(hParent, CDM_GETFILEPATH, _countof(Path), (LPARAM)Path); 78 FileExtFromFilter(PathFindExtensionW(Path), pon->lpOFN); 79 SendMessageW(hParent, CDM_SETCONTROLTEXT, cmb13, (LPARAM)PathFindFileNameW(Path)); 80 StringCchCopyW(pon->lpOFN->lpstrFile, pon->lpOFN->nMaxFile, Path); 81 } 82 break; 83 } 84 return 0; 85 } 86 87 typedef ULONG (WINAPI *FN_MAPISendMail)(LHANDLE, ULONG_PTR, lpMapiMessage, FLAGS, ULONG); 88 typedef ULONG (WINAPI *FN_MAPISendMailW)(LHANDLE, ULONG_PTR, lpMapiMessageW, FLAGS, ULONG); 89 90 BOOL OpenMailer(HWND hWnd, LPCWSTR pszPathName) 91 { 92 // Delete the temporary file if any 93 if (g_szMailTempFile[0]) 94 { 95 ::DeleteFileW(g_szMailTempFile); 96 g_szMailTempFile[0] = UNICODE_NULL; 97 } 98 99 CStringW strFileTitle; 100 if (PathFileExistsW(pszPathName) && imageModel.IsImageSaved()) 101 { 102 strFileTitle = PathFindFileNameW(pszPathName); 103 } 104 else // Not existing or not saved 105 { 106 // Get the name of a temporary file 107 WCHAR szTempDir[MAX_PATH]; 108 ::GetTempPathW(_countof(szTempDir), szTempDir); 109 if (!::GetTempFileNameW(szTempDir, L"afx", 0, g_szMailTempFile)) 110 return FALSE; // Failure 111 112 if (PathFileExistsW(g_szFileName)) 113 { 114 // Set file title 115 strFileTitle = PathFindFileNameW(g_szFileName); 116 117 // Copy to the temporary file 118 if (!::CopyFileW(g_szFileName, g_szMailTempFile, FALSE)) 119 { 120 g_szMailTempFile[0] = UNICODE_NULL; 121 return FALSE; // Failure 122 } 123 } 124 else 125 { 126 // Set file title 127 strFileTitle.LoadString(IDS_DEFAULTFILENAME); 128 strFileTitle += L".png"; 129 130 // Save it to the temporary file 131 HBITMAP hbmLocked = imageModel.LockBitmap(); 132 BOOL ret = SaveDIBToFile(hbmLocked, g_szMailTempFile, FALSE, Gdiplus::ImageFormatPNG); 133 imageModel.UnlockBitmap(hbmLocked); 134 if (!ret) 135 { 136 g_szMailTempFile[0] = UNICODE_NULL; 137 return FALSE; // Failure 138 } 139 } 140 141 // Use the temporary file 142 pszPathName = g_szMailTempFile; 143 } 144 145 // Load "mapi32.dll" 146 HINSTANCE hMAPI = LoadLibraryW(L"mapi32.dll"); 147 if (!hMAPI) 148 return FALSE; // Failure 149 150 // Attachment 151 MapiFileDescW attachmentW = { 0 }; 152 attachmentW.nPosition = (ULONG)-1; 153 attachmentW.lpszPathName = (LPWSTR)pszPathName; 154 attachmentW.lpszFileName = (LPWSTR)(LPCWSTR)strFileTitle; 155 156 // Message with attachment 157 MapiMessageW messageW = { 0 }; 158 messageW.lpszSubject = NULL; 159 messageW.nFileCount = 1; 160 messageW.lpFiles = &attachmentW; 161 162 // First, try to open the mailer by the function of Unicode version 163 FN_MAPISendMailW pMAPISendMailW = (FN_MAPISendMailW)::GetProcAddress(hMAPI, "MAPISendMailW"); 164 if (pMAPISendMailW) 165 { 166 pMAPISendMailW(0, (ULONG_PTR)hWnd, &messageW, MAPI_DIALOG | MAPI_LOGON_UI, 0); 167 ::FreeLibrary(hMAPI); 168 return TRUE; // MAPISendMailW will show an error message on failure 169 } 170 171 // Convert to ANSI strings 172 CStringA szPathNameA(pszPathName), szFileTitleA(strFileTitle); 173 174 MapiFileDesc attachment = { 0 }; 175 attachment.nPosition = (ULONG)-1; 176 attachment.lpszPathName = (LPSTR)(LPCSTR)szPathNameA; 177 attachment.lpszFileName = (LPSTR)(LPCSTR)szFileTitleA; 178 179 MapiMessage message = { 0 }; 180 message.lpszSubject = NULL; 181 message.nFileCount = 1; 182 message.lpFiles = &attachment; 183 184 // Try again but in ANSI version 185 FN_MAPISendMail pMAPISendMail = (FN_MAPISendMail)::GetProcAddress(hMAPI, "MAPISendMail"); 186 if (pMAPISendMail) 187 { 188 pMAPISendMail(0, (ULONG_PTR)hWnd, &message, MAPI_DIALOG | MAPI_LOGON_UI, 0); 189 ::FreeLibrary(hMAPI); 190 return TRUE; // MAPISendMail will show an error message on failure 191 } 192 193 ::FreeLibrary(hMAPI); 194 return FALSE; // Failure 195 } 196 197 BOOL CMainWindow::GetOpenFileName(IN OUT LPWSTR pszFile, INT cchMaxFile) 198 { 199 static OPENFILENAMEW ofn = { 0 }; 200 static CStringW strFilter; 201 202 if (ofn.lStructSize == 0) 203 { 204 // The "All Files" item text 205 CStringW strAllPictureFiles; 206 strAllPictureFiles.LoadString(g_hinstExe, IDS_ALLPICTUREFILES); 207 208 // Get the import filter 209 CSimpleArray<GUID> aguidFileTypesI; 210 CImage::GetImporterFilterString(strFilter, aguidFileTypesI, strAllPictureFiles, 211 CImage::excludeDefaultLoad, L'|'); 212 strFilter.Replace(L'|', UNICODE_NULL); 213 214 // Initializing the OPENFILENAME structure for GetOpenFileName 215 ZeroMemory(&ofn, sizeof(ofn)); 216 ofn.lStructSize = sizeof(ofn); 217 ofn.hwndOwner = m_hWnd; 218 ofn.hInstance = g_hinstExe; 219 ofn.lpstrFilter = strFilter; 220 ofn.Flags = OFN_EXPLORER | OFN_HIDEREADONLY; 221 ofn.lpstrDefExt = L"png"; 222 } 223 224 ofn.lpstrFile = pszFile; 225 ofn.nMaxFile = cchMaxFile; 226 return ::GetOpenFileNameW(&ofn); 227 } 228 229 BOOL CMainWindow::GetSaveFileName(IN OUT LPWSTR pszFile, INT cchMaxFile) 230 { 231 static OPENFILENAMEW sfn = { 0 }; 232 static CStringW strFilter; 233 234 if (sfn.lStructSize == 0) 235 { 236 // Get the export filter 237 CSimpleArray<GUID> aguidFileTypesE; 238 CImage::GetExporterFilterString(strFilter, aguidFileTypesE, NULL, 239 CImage::excludeDefaultSave, L'|'); 240 strFilter.Replace(L'|', UNICODE_NULL); 241 242 // Initializing the OPENFILENAME structure for GetSaveFileName 243 ZeroMemory(&sfn, sizeof(sfn)); 244 sfn.lStructSize = sizeof(sfn); 245 sfn.hwndOwner = m_hWnd; 246 sfn.hInstance = g_hinstExe; 247 sfn.lpstrFilter = strFilter; 248 sfn.Flags = OFN_EXPLORER | OFN_OVERWRITEPROMPT | OFN_ENABLEHOOK; 249 sfn.lpfnHook = OFNHookProc; 250 sfn.lpstrDefExt = L"png"; 251 252 LPWSTR pchDotExt = PathFindExtensionW(pszFile); 253 if (*pchDotExt == UNICODE_NULL) 254 { 255 // Choose PNG 256 StringCchCatW(pszFile, cchMaxFile, L".png"); 257 for (INT i = 0; i < aguidFileTypesE.GetSize(); ++i) 258 { 259 if (aguidFileTypesE[i] == Gdiplus::ImageFormatPNG) 260 { 261 sfn.nFilterIndex = i + 1; 262 break; 263 } 264 } 265 } 266 } 267 268 sfn.lpstrFile = pszFile; 269 sfn.nMaxFile = cchMaxFile; 270 return ::GetSaveFileNameW(&sfn); 271 } 272 273 BOOL CMainWindow::ChooseColor(IN OUT COLORREF *prgbColor) 274 { 275 static CHOOSECOLOR choosecolor = { 0 }; 276 static COLORREF custColors[16] = 277 { 278 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 279 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff, 0xffffff 280 }; 281 282 if (choosecolor.lStructSize == 0) 283 { 284 // Initializing the CHOOSECOLOR structure for ChooseColor 285 ZeroMemory(&choosecolor, sizeof(choosecolor)); 286 choosecolor.lStructSize = sizeof(choosecolor); 287 choosecolor.hwndOwner = m_hWnd; 288 choosecolor.lpCustColors = custColors; 289 } 290 291 choosecolor.Flags = CC_RGBINIT; 292 choosecolor.rgbResult = *prgbColor; 293 if (!::ChooseColor(&choosecolor)) 294 return FALSE; 295 296 *prgbColor = choosecolor.rgbResult; 297 return TRUE; 298 } 299 300 HWND CMainWindow::DoCreate() 301 { 302 ::LoadStringW(g_hinstExe, IDS_DEFAULTFILENAME, g_szFileName, _countof(g_szFileName)); 303 304 CStringW strTitle; 305 strTitle.Format(IDS_WINDOWTITLE, PathFindFileName(g_szFileName)); 306 307 RECT& rc = registrySettings.WindowPlacement.rcNormalPosition; 308 return Create(HWND_DESKTOP, rc, strTitle, WS_OVERLAPPEDWINDOW, WS_EX_ACCEPTFILES); 309 } 310 311 // entry point 312 INT WINAPI 313 wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, INT nCmdShow) 314 { 315 g_hinstExe = hInstance; 316 317 // Initialize common controls library 318 INITCOMMONCONTROLSEX iccx; 319 iccx.dwSize = sizeof(iccx); 320 iccx.dwICC = ICC_STANDARD_CLASSES | ICC_USEREX_CLASSES | ICC_BAR_CLASSES; 321 InitCommonControlsEx(&iccx); 322 323 // Load settings from registry 324 registrySettings.Load(nCmdShow); 325 326 // Create the main window 327 if (!mainWindow.DoCreate()) 328 { 329 MessageBox(NULL, L"Failed to create main window.", NULL, MB_ICONERROR); 330 return 1; 331 } 332 333 // Initialize imageModel 334 if (__argc < 2 || !DoLoadImageFile(mainWindow, __targv[1], TRUE)) 335 InitializeImage(NULL, NULL, FALSE); 336 337 // Make the window visible on the screen 338 mainWindow.ShowWindow(registrySettings.WindowPlacement.showCmd); 339 340 // Load the access keys 341 HACCEL hAccel = ::LoadAcceleratorsW(hInstance, MAKEINTRESOURCEW(800)); 342 343 // The message loop 344 MSG msg; 345 while (::GetMessage(&msg, NULL, 0, 0)) 346 { 347 if (fontsDialog.IsWindow() && fontsDialog.IsDialogMessage(&msg)) 348 continue; 349 350 if (::TranslateAcceleratorW(mainWindow, hAccel, &msg)) 351 continue; 352 353 ::TranslateMessage(&msg); 354 ::DispatchMessage(&msg); 355 } 356 357 // Unload the access keys 358 ::DestroyAcceleratorTable(hAccel); 359 360 // Write back settings to registry 361 registrySettings.Store(); 362 363 if (g_szMailTempFile[0]) 364 ::DeleteFileW(g_szMailTempFile); 365 366 // Return the value that PostQuitMessage() gave 367 return (INT)msg.wParam; 368 } 369