[WORDPAD] Sync with Wine Staging 1.7.55. CORE-10536
[reactos.git] / reactos / base / applications / wordpad / registry.c
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 {
120 rc->top = 0;
121 rc->left = 0;
122 rc->bottom = 300;
123 rc->right = 600;
124 }
125
126 RegCloseKey(hKey);
127 }
128
129 void registry_read_maximized(DWORD *bMaximized)
130 {
131 HKEY hKey = 0;
132 DWORD size = sizeof(DWORD);
133
134 if(registry_get_handle(&hKey, 0, key_options) != ERROR_SUCCESS ||
135 RegQueryValueExW(hKey, var_maximized, 0, NULL, (LPBYTE)bMaximized, &size) !=
136 ERROR_SUCCESS || size != sizeof(DWORD))
137 {
138 *bMaximized = FALSE;
139 }
140
141 RegCloseKey(hKey);
142 }
143
144 static void truncate_path(LPWSTR file, LPWSTR out, LPWSTR pos1, LPWSTR pos2)
145 {
146 static const WCHAR dots[] = {'.','.','.',0};
147
148 *++pos1 = 0;
149
150 lstrcatW(out, file);
151 lstrcatW(out, dots);
152 lstrcatW(out, pos2);
153 }
154
155 static void format_filelist_filename(LPWSTR file, LPWSTR out)
156 {
157 LPWSTR pos_basename;
158 LPWSTR truncpos1, truncpos2;
159 WCHAR myDocs[MAX_STRING_LEN];
160
161 SHGetFolderPathW(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, (LPWSTR)&myDocs);
162 pos_basename = file_basename(file);
163 truncpos1 = NULL;
164 truncpos2 = NULL;
165
166 *(pos_basename-1) = 0;
167 if(!lstrcmpiW(file, myDocs) || (lstrlenW(pos_basename) > FILELIST_ENTRY_LENGTH))
168 {
169 truncpos1 = pos_basename;
170 *(pos_basename-1) = '\\';
171 } else
172 {
173 LPWSTR pos;
174 BOOL morespace = FALSE;
175
176 *(pos_basename-1) = '\\';
177
178 for(pos = file; pos < pos_basename; pos++)
179 {
180 if(*pos == '\\' || *pos == '/')
181 {
182 if(truncpos1)
183 {
184 if((pos - file + lstrlenW(pos_basename)) > FILELIST_ENTRY_LENGTH)
185 break;
186
187 truncpos1 = pos;
188 morespace = TRUE;
189 break;
190 }
191
192 if((pos - file + lstrlenW(pos_basename)) > FILELIST_ENTRY_LENGTH)
193 break;
194
195 truncpos1 = pos;
196 }
197 }
198
199 if(morespace)
200 {
201 for(pos = pos_basename; pos >= truncpos1; pos--)
202 {
203 if(*pos == '\\' || *pos == '/')
204 {
205 if((truncpos1 - file + lstrlenW(pos_basename) + pos_basename - pos) > FILELIST_ENTRY_LENGTH)
206 break;
207
208 truncpos2 = pos;
209 }
210 }
211 }
212 }
213
214 if(truncpos1 == pos_basename)
215 lstrcatW(out, pos_basename);
216 else if(truncpos1 == truncpos2 || !truncpos2)
217 lstrcatW(out, file);
218 else
219 truncate_path(file, out, truncpos1, truncpos2);
220 }
221
222 void registry_read_filelist(HWND hMainWnd)
223 {
224 HKEY hFileKey;
225
226 if(registry_get_handle(&hFileKey, 0, key_recentfiles) == ERROR_SUCCESS)
227 {
228 WCHAR itemText[MAX_PATH+3], buffer[MAX_PATH];
229 /* The menu item name is not the same as the file name, so we need to store
230 the file name here */
231 static WCHAR file1[MAX_PATH], file2[MAX_PATH], file3[MAX_PATH], file4[MAX_PATH];
232 WCHAR numFormat[] = {'&','%','d',' ',0};
233 LPWSTR pFile[] = {file1, file2, file3, file4};
234 DWORD pathSize = MAX_PATH*sizeof(WCHAR);
235 int i;
236 WCHAR key[6];
237 MENUITEMINFOW mi;
238 HMENU hMenu = GetMenu(hMainWnd);
239
240 mi.cbSize = sizeof(MENUITEMINFOW);
241 mi.fMask = MIIM_ID | MIIM_DATA | MIIM_STRING | MIIM_FTYPE;
242 mi.fType = MFT_STRING;
243 mi.dwTypeData = itemText;
244 mi.wID = ID_FILE_RECENT1;
245
246 RemoveMenu(hMenu, ID_FILE_RECENT_SEPARATOR, MF_BYCOMMAND);
247 for(i = 0; i < FILELIST_ENTRIES; i++)
248 {
249 wsprintfW(key, var_file, i+1);
250 RemoveMenu(hMenu, ID_FILE_RECENT1+i, MF_BYCOMMAND);
251 if(RegQueryValueExW(hFileKey, (LPWSTR)key, 0, NULL, (LPBYTE)pFile[i], &pathSize)
252 != ERROR_SUCCESS)
253 break;
254
255 mi.dwItemData = (ULONG_PTR)pFile[i];
256 wsprintfW(itemText, numFormat, i+1);
257
258 lstrcpyW(buffer, pFile[i]);
259
260 format_filelist_filename(buffer, itemText);
261
262 InsertMenuItemW(hMenu, ID_FILE_EXIT, FALSE, &mi);
263 mi.wID++;
264 pathSize = MAX_PATH*sizeof(WCHAR);
265 }
266 mi.fType = MFT_SEPARATOR;
267 mi.fMask = MIIM_FTYPE | MIIM_ID;
268 InsertMenuItemW(hMenu, ID_FILE_EXIT, FALSE, &mi);
269
270 RegCloseKey(hFileKey);
271 }
272 }
273
274 void registry_set_filelist(LPCWSTR newFile, HWND hMainWnd)
275 {
276 HKEY hKey;
277 DWORD action;
278
279 if(registry_get_handle(&hKey, &action, key_recentfiles) == ERROR_SUCCESS)
280 {
281 LPCWSTR pFiles[FILELIST_ENTRIES];
282 int i;
283 HMENU hMenu = GetMenu(hMainWnd);
284 MENUITEMINFOW mi;
285 WCHAR buffer[6];
286
287 mi.cbSize = sizeof(MENUITEMINFOW);
288 mi.fMask = MIIM_DATA;
289
290 for(i = 0; i < FILELIST_ENTRIES; i++)
291 pFiles[i] = NULL;
292
293 for(i = 0; GetMenuItemInfoW(hMenu, ID_FILE_RECENT1+i, FALSE, &mi); i++)
294 pFiles[i] = (LPWSTR)mi.dwItemData;
295
296 if(lstrcmpiW(newFile, pFiles[0]))
297 {
298 for(i = 0; i < FILELIST_ENTRIES && pFiles[i]; i++)
299 {
300 if(!lstrcmpiW(pFiles[i], newFile))
301 {
302 int j;
303 for(j = 0; pFiles[j] && j < i; j++)
304 {
305 pFiles[i-j] = pFiles[i-j-1];
306 }
307 pFiles[0] = NULL;
308 break;
309 }
310 }
311
312 if(!pFiles[0])
313 {
314 pFiles[0] = newFile;
315 } else
316 {
317 for(i = 0; i < FILELIST_ENTRIES-1; i++)
318 pFiles[FILELIST_ENTRIES-1-i] = pFiles[FILELIST_ENTRIES-2-i];
319
320 pFiles[0] = newFile;
321 }
322
323 for(i = 0; i < FILELIST_ENTRIES && pFiles[i]; i++)
324 {
325 wsprintfW(buffer, var_file, i+1);
326 RegSetValueExW(hKey, (LPWSTR)&buffer, 0, REG_SZ, (const BYTE*)pFiles[i],
327 (lstrlenW(pFiles[i])+1)*sizeof(WCHAR));
328 }
329 }
330 RegCloseKey(hKey);
331 }
332 registry_read_filelist(hMainWnd);
333 }
334
335 int reg_formatindex(WPARAM format)
336 {
337 return (format & SF_TEXT) ? 1 : 0;
338 }
339
340 void registry_read_options(void)
341 {
342 HKEY hKey;
343
344 if(registry_get_handle(&hKey, 0, key_options) != ERROR_SUCCESS)
345 registry_read_pagemargins(NULL);
346 else
347 {
348 registry_read_pagemargins(hKey);
349 RegCloseKey(hKey);
350 }
351
352 if(registry_get_handle(&hKey, 0, key_settings) != ERROR_SUCCESS) {
353 registry_read_previewpages(NULL);
354 } else {
355 registry_read_previewpages(hKey);
356 RegCloseKey(hKey);
357 }
358 }
359
360 static void registry_read_formatopts(int index, LPCWSTR key, DWORD barState[], DWORD wordWrap[])
361 {
362 HKEY hKey;
363 DWORD action = 0;
364 BOOL fetched = FALSE;
365 barState[index] = 0;
366 wordWrap[index] = 0;
367
368 if(registry_get_handle(&hKey, &action, key) != ERROR_SUCCESS)
369 return;
370
371 if(action == REG_OPENED_EXISTING_KEY)
372 {
373 DWORD size = sizeof(DWORD);
374
375 if(RegQueryValueExW(hKey, var_barstate0, 0, NULL, (LPBYTE)&barState[index],
376 &size) == ERROR_SUCCESS)
377 fetched = TRUE;
378 }
379
380 if(!fetched)
381 barState[index] = (1 << BANDID_TOOLBAR) | (1 << BANDID_FORMATBAR) | (1 << BANDID_RULER) | (1 << BANDID_STATUSBAR);
382
383 fetched = FALSE;
384 if(action == REG_OPENED_EXISTING_KEY)
385 {
386 DWORD size = sizeof(DWORD);
387 if(RegQueryValueExW(hKey, var_wrap, 0, NULL, (LPBYTE)&wordWrap[index],
388 &size) == ERROR_SUCCESS)
389 fetched = TRUE;
390 }
391
392 if (!fetched)
393 {
394 if(index == reg_formatindex(SF_RTF))
395 wordWrap[index] = ID_WORDWRAP_WINDOW;
396 else if(index == reg_formatindex(SF_TEXT))
397 wordWrap[index] = ID_WORDWRAP_NONE;
398 }
399
400 RegCloseKey(hKey);
401 }
402
403 void registry_read_formatopts_all(DWORD barState[], DWORD wordWrap[])
404 {
405 registry_read_formatopts(reg_formatindex(SF_RTF), key_rtf, barState, wordWrap);
406 registry_read_formatopts(reg_formatindex(SF_TEXT), key_text, barState, wordWrap);
407 }
408
409 static void registry_set_formatopts(int index, LPCWSTR key, DWORD barState[], DWORD wordWrap[])
410 {
411 HKEY hKey;
412 DWORD action = 0;
413
414 if(registry_get_handle(&hKey, &action, key) == ERROR_SUCCESS)
415 {
416 RegSetValueExW(hKey, var_barstate0, 0, REG_DWORD, (LPBYTE)&barState[index],
417 sizeof(DWORD));
418 RegSetValueExW(hKey, var_wrap, 0, REG_DWORD, (LPBYTE)&wordWrap[index],
419 sizeof(DWORD));
420 RegCloseKey(hKey);
421 }
422 }
423
424 void registry_set_formatopts_all(DWORD barState[], DWORD wordWrap[])
425 {
426 registry_set_formatopts(reg_formatindex(SF_RTF), key_rtf, barState, wordWrap);
427 registry_set_formatopts(reg_formatindex(SF_TEXT), key_text, barState, wordWrap);
428 }