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