1 /* 2 * Wordpad implementation - Registry functions 3 * 4 * Copyright 2007 by Alexander N. Sørnes <alex@thehandofagony.com> 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #define WIN32_NO_STATUS 22 #define WIN32_LEAN_AND_MEAN 23 #include <windows.h> 24 #include <shlobj.h> 25 #include <richedit.h> 26 27 #include "wordpad.h" 28 29 static const WCHAR key_recentfiles[] = {'R','e','c','e','n','t',' ','f','i','l','e', 30 ' ','l','i','s','t',0}; 31 static const WCHAR key_options[] = {'O','p','t','i','o','n','s',0}; 32 static const WCHAR key_settings[] = {'S','e','t','t','i','n','g','s',0}; 33 static const WCHAR key_rtf[] = {'R','T','F',0}; 34 static const WCHAR key_text[] = {'T','e','x','t',0}; 35 36 static const WCHAR var_file[] = {'F','i','l','e','%','d',0}; 37 static const WCHAR var_framerect[] = {'F','r','a','m','e','R','e','c','t',0}; 38 static const WCHAR var_barstate0[] = {'B','a','r','S','t','a','t','e','0',0}; 39 static const WCHAR var_wrap[] = {'W','r','a','p',0}; 40 static const WCHAR var_maximized[] = {'M','a','x','i','m','i','z','e','d',0}; 41 42 static LRESULT registry_get_handle(HKEY *hKey, LPDWORD action, LPCWSTR subKey) 43 { 44 LONG ret; 45 static const WCHAR wszProgramKey[] = {'S','o','f','t','w','a','r','e','\\', 46 'M','i','c','r','o','s','o','f','t','\\', 47 'W','i','n','d','o','w','s','\\', 48 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', 49 'A','p','p','l','e','t','s','\\', 50 'W','o','r','d','p','a','d',0}; 51 LPWSTR key = (LPWSTR)wszProgramKey; 52 53 if(subKey) 54 { 55 WCHAR backslash[] = {'\\',0}; 56 key = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 57 (lstrlenW(wszProgramKey)+lstrlenW(subKey)+lstrlenW(backslash)+1) 58 *sizeof(WCHAR)); 59 60 if(!key) 61 return 1; 62 63 lstrcpyW(key, wszProgramKey); 64 lstrcatW(key, backslash); 65 lstrcatW(key, subKey); 66 } 67 68 if(action) 69 { 70 ret = RegCreateKeyExW(HKEY_CURRENT_USER, key, 0, NULL, REG_OPTION_NON_VOLATILE, 71 KEY_READ | KEY_WRITE, NULL, hKey, action); 72 } else 73 { 74 ret = RegOpenKeyExW(HKEY_CURRENT_USER, key, 0, KEY_READ | KEY_WRITE, hKey); 75 } 76 77 if(subKey) 78 HeapFree(GetProcessHeap(), 0, key); 79 80 return ret; 81 } 82 83 void registry_set_options(HWND hMainWnd) 84 { 85 HKEY hKey = 0; 86 DWORD action; 87 88 if(registry_get_handle(&hKey, &action, key_options) == ERROR_SUCCESS) 89 { 90 WINDOWPLACEMENT wp; 91 DWORD isMaximized; 92 93 wp.length = sizeof(WINDOWPLACEMENT); 94 GetWindowPlacement(hMainWnd, &wp); 95 isMaximized = (wp.showCmd == SW_SHOWMAXIMIZED); 96 97 RegSetValueExW(hKey, var_framerect, 0, REG_BINARY, (LPBYTE)&wp.rcNormalPosition, sizeof(RECT)); 98 RegSetValueExW(hKey, var_maximized, 0, REG_DWORD, (LPBYTE)&isMaximized, sizeof(DWORD)); 99 100 registry_set_pagemargins(hKey); 101 RegCloseKey(hKey); 102 } 103 104 if(registry_get_handle(&hKey, &action, key_settings) == ERROR_SUCCESS) 105 { 106 registry_set_previewpages(hKey); 107 RegCloseKey(hKey); 108 } 109 } 110 111 void registry_read_winrect(RECT* rc) 112 { 113 HKEY hKey = 0; 114 DWORD size = sizeof(RECT); 115 116 if(registry_get_handle(&hKey, 0, key_options) != ERROR_SUCCESS || 117 RegQueryValueExW(hKey, var_framerect, 0, NULL, (LPBYTE)rc, &size) != 118 ERROR_SUCCESS || size != sizeof(RECT)) 119 SetRect(rc, 0, 0, 600, 300); 120 121 RegCloseKey(hKey); 122 } 123 124 void registry_read_maximized(DWORD *bMaximized) 125 { 126 HKEY hKey = 0; 127 DWORD size = sizeof(DWORD); 128 129 if(registry_get_handle(&hKey, 0, key_options) != ERROR_SUCCESS || 130 RegQueryValueExW(hKey, var_maximized, 0, NULL, (LPBYTE)bMaximized, &size) != 131 ERROR_SUCCESS || size != sizeof(DWORD)) 132 { 133 *bMaximized = FALSE; 134 } 135 136 RegCloseKey(hKey); 137 } 138 139 static void truncate_path(LPWSTR file, LPWSTR out, LPWSTR pos1, LPWSTR pos2) 140 { 141 static const WCHAR dots[] = {'.','.','.',0}; 142 143 *++pos1 = 0; 144 145 lstrcatW(out, file); 146 lstrcatW(out, dots); 147 lstrcatW(out, pos2); 148 } 149 150 static void format_filelist_filename(LPWSTR file, LPWSTR out) 151 { 152 LPWSTR pos_basename; 153 LPWSTR truncpos1, truncpos2; 154 WCHAR myDocs[MAX_PATH]; 155 156 SHGetFolderPathW(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, myDocs); 157 pos_basename = file_basename(file); 158 truncpos1 = NULL; 159 truncpos2 = NULL; 160 161 *(pos_basename-1) = 0; 162 if(!lstrcmpiW(file, myDocs) || (lstrlenW(pos_basename) > FILELIST_ENTRY_LENGTH)) 163 { 164 truncpos1 = pos_basename; 165 *(pos_basename-1) = '\\'; 166 } else 167 { 168 LPWSTR pos; 169 BOOL morespace = FALSE; 170 171 *(pos_basename-1) = '\\'; 172 173 for(pos = file; pos < pos_basename; pos++) 174 { 175 if(*pos == '\\' || *pos == '/') 176 { 177 if(truncpos1) 178 { 179 if((pos - file + lstrlenW(pos_basename)) > FILELIST_ENTRY_LENGTH) 180 break; 181 182 truncpos1 = pos; 183 morespace = TRUE; 184 break; 185 } 186 187 if((pos - file + lstrlenW(pos_basename)) > FILELIST_ENTRY_LENGTH) 188 break; 189 190 truncpos1 = pos; 191 } 192 } 193 194 if(morespace) 195 { 196 for(pos = pos_basename; pos >= truncpos1; pos--) 197 { 198 if(*pos == '\\' || *pos == '/') 199 { 200 if((truncpos1 - file + lstrlenW(pos_basename) + pos_basename - pos) > FILELIST_ENTRY_LENGTH) 201 break; 202 203 truncpos2 = pos; 204 } 205 } 206 } 207 } 208 209 if(truncpos1 == pos_basename) 210 lstrcatW(out, pos_basename); 211 else if(truncpos1 == truncpos2 || !truncpos2) 212 lstrcatW(out, file); 213 else 214 truncate_path(file, out, truncpos1, truncpos2); 215 } 216 217 void registry_read_filelist(HWND hMainWnd) 218 { 219 HKEY hFileKey; 220 221 if(registry_get_handle(&hFileKey, 0, key_recentfiles) == ERROR_SUCCESS) 222 { 223 WCHAR itemText[MAX_PATH+3], buffer[MAX_PATH]; 224 /* The menu item name is not the same as the file name, so we need to store 225 the file name here */ 226 static WCHAR file1[MAX_PATH], file2[MAX_PATH], file3[MAX_PATH], file4[MAX_PATH]; 227 WCHAR numFormat[] = {'&','%','d',' ',0}; 228 LPWSTR pFile[] = {file1, file2, file3, file4}; 229 DWORD pathSize = MAX_PATH*sizeof(WCHAR); 230 int i; 231 WCHAR key[6]; 232 MENUITEMINFOW mi; 233 HMENU hMenu = GetMenu(hMainWnd); 234 235 mi.cbSize = sizeof(MENUITEMINFOW); 236 mi.fMask = MIIM_ID | MIIM_DATA | MIIM_STRING | MIIM_FTYPE; 237 mi.fType = MFT_STRING; 238 mi.dwTypeData = itemText; 239 mi.wID = ID_FILE_RECENT1; 240 241 RemoveMenu(hMenu, ID_FILE_RECENT_SEPARATOR, MF_BYCOMMAND); 242 for(i = 0; i < FILELIST_ENTRIES; i++) 243 { 244 wsprintfW(key, var_file, i+1); 245 RemoveMenu(hMenu, ID_FILE_RECENT1+i, MF_BYCOMMAND); 246 if(RegQueryValueExW(hFileKey, (LPWSTR)key, 0, NULL, (LPBYTE)pFile[i], &pathSize) 247 != ERROR_SUCCESS) 248 break; 249 250 mi.dwItemData = (ULONG_PTR)pFile[i]; 251 wsprintfW(itemText, numFormat, i+1); 252 253 lstrcpyW(buffer, pFile[i]); 254 255 format_filelist_filename(buffer, itemText); 256 257 InsertMenuItemW(hMenu, ID_FILE_EXIT, FALSE, &mi); 258 mi.wID++; 259 pathSize = MAX_PATH*sizeof(WCHAR); 260 } 261 mi.fType = MFT_SEPARATOR; 262 mi.fMask = MIIM_FTYPE | MIIM_ID; 263 InsertMenuItemW(hMenu, ID_FILE_EXIT, FALSE, &mi); 264 265 RegCloseKey(hFileKey); 266 } 267 } 268 269 void registry_set_filelist(LPCWSTR newFile, HWND hMainWnd) 270 { 271 HKEY hKey; 272 DWORD action; 273 274 if(registry_get_handle(&hKey, &action, key_recentfiles) == ERROR_SUCCESS) 275 { 276 LPCWSTR pFiles[FILELIST_ENTRIES]; 277 int i; 278 HMENU hMenu = GetMenu(hMainWnd); 279 MENUITEMINFOW mi; 280 WCHAR buffer[6]; 281 282 mi.cbSize = sizeof(MENUITEMINFOW); 283 mi.fMask = MIIM_DATA; 284 285 for(i = 0; i < FILELIST_ENTRIES; i++) 286 pFiles[i] = NULL; 287 288 for(i = 0; GetMenuItemInfoW(hMenu, ID_FILE_RECENT1+i, FALSE, &mi); i++) 289 pFiles[i] = (LPWSTR)mi.dwItemData; 290 291 if(lstrcmpiW(newFile, pFiles[0])) 292 { 293 for(i = 0; i < FILELIST_ENTRIES && pFiles[i]; i++) 294 { 295 if(!lstrcmpiW(pFiles[i], newFile)) 296 { 297 int j; 298 for(j = 0; j < i; j++) 299 { 300 pFiles[i-j] = pFiles[i-j-1]; 301 } 302 pFiles[0] = NULL; 303 break; 304 } 305 } 306 307 if(!pFiles[0]) 308 { 309 pFiles[0] = newFile; 310 } else 311 { 312 for(i = 0; i < FILELIST_ENTRIES-1; i++) 313 pFiles[FILELIST_ENTRIES-1-i] = pFiles[FILELIST_ENTRIES-2-i]; 314 315 pFiles[0] = newFile; 316 } 317 318 for(i = 0; i < FILELIST_ENTRIES && pFiles[i]; i++) 319 { 320 wsprintfW(buffer, var_file, i+1); 321 RegSetValueExW(hKey, (LPWSTR)&buffer, 0, REG_SZ, (const BYTE*)pFiles[i], 322 (lstrlenW(pFiles[i])+1)*sizeof(WCHAR)); 323 } 324 } 325 RegCloseKey(hKey); 326 } 327 registry_read_filelist(hMainWnd); 328 } 329 330 int reg_formatindex(WPARAM format) 331 { 332 return (format & SF_TEXT) ? 1 : 0; 333 } 334 335 void registry_read_options(void) 336 { 337 HKEY hKey; 338 339 if(registry_get_handle(&hKey, 0, key_options) != ERROR_SUCCESS) 340 registry_read_pagemargins(NULL); 341 else 342 { 343 registry_read_pagemargins(hKey); 344 RegCloseKey(hKey); 345 } 346 347 if(registry_get_handle(&hKey, 0, key_settings) != ERROR_SUCCESS) { 348 registry_read_previewpages(NULL); 349 } else { 350 registry_read_previewpages(hKey); 351 RegCloseKey(hKey); 352 } 353 } 354 355 static void registry_read_formatopts(int index, LPCWSTR key, DWORD barState[], DWORD wordWrap[]) 356 { 357 HKEY hKey; 358 DWORD action = 0; 359 BOOL fetched = FALSE; 360 barState[index] = 0; 361 wordWrap[index] = 0; 362 363 if(registry_get_handle(&hKey, &action, key) != ERROR_SUCCESS) 364 return; 365 366 if(action == REG_OPENED_EXISTING_KEY) 367 { 368 DWORD size = sizeof(DWORD); 369 370 if(RegQueryValueExW(hKey, var_barstate0, 0, NULL, (LPBYTE)&barState[index], 371 &size) == ERROR_SUCCESS) 372 fetched = TRUE; 373 } 374 375 if(!fetched) 376 barState[index] = (1 << BANDID_TOOLBAR) | (1 << BANDID_FORMATBAR) | (1 << BANDID_RULER) | (1 << BANDID_STATUSBAR); 377 378 fetched = FALSE; 379 if(action == REG_OPENED_EXISTING_KEY) 380 { 381 DWORD size = sizeof(DWORD); 382 if(RegQueryValueExW(hKey, var_wrap, 0, NULL, (LPBYTE)&wordWrap[index], 383 &size) == ERROR_SUCCESS) 384 fetched = TRUE; 385 } 386 387 if (!fetched) 388 { 389 if(index == reg_formatindex(SF_RTF)) 390 wordWrap[index] = ID_WORDWRAP_WINDOW; 391 else if(index == reg_formatindex(SF_TEXT)) 392 wordWrap[index] = ID_WORDWRAP_NONE; 393 } 394 395 RegCloseKey(hKey); 396 } 397 398 void registry_read_formatopts_all(DWORD barState[], DWORD wordWrap[]) 399 { 400 registry_read_formatopts(reg_formatindex(SF_RTF), key_rtf, barState, wordWrap); 401 registry_read_formatopts(reg_formatindex(SF_TEXT), key_text, barState, wordWrap); 402 } 403 404 static void registry_set_formatopts(int index, LPCWSTR key, DWORD barState[], DWORD wordWrap[]) 405 { 406 HKEY hKey; 407 DWORD action = 0; 408 409 if(registry_get_handle(&hKey, &action, key) == ERROR_SUCCESS) 410 { 411 RegSetValueExW(hKey, var_barstate0, 0, REG_DWORD, (LPBYTE)&barState[index], 412 sizeof(DWORD)); 413 RegSetValueExW(hKey, var_wrap, 0, REG_DWORD, (LPBYTE)&wordWrap[index], 414 sizeof(DWORD)); 415 RegCloseKey(hKey); 416 } 417 } 418 419 void registry_set_formatopts_all(DWORD barState[], DWORD wordWrap[]) 420 { 421 registry_set_formatopts(reg_formatindex(SF_RTF), key_rtf, barState, wordWrap); 422 registry_set_formatopts(reg_formatindex(SF_TEXT), key_text, barState, wordWrap); 423 } 424