Process Hacker
settings.c
Go to the documentation of this file.
1 /*
2  * Process Hacker -
3  * program settings
4  *
5  * Copyright (C) 2010-2015 wj32
6  *
7  * This file is part of Process Hacker.
8  *
9  * Process Hacker is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * Process Hacker is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 /*
24  * This file contains a program-specific settings system. All possible
25  * settings are defined at program startup and added to a hashtable.
26  * The values of these settings can then be read in from a XML file or
27  * saved to a XML file at any time. Settings which are not recognized
28  * are added to a list of "ignored settings"; this is necessary to
29  * support plugin settings, as we don't want their settings to get
30  * deleted whenever the plugins are disabled.
31  *
32  * The get/set functions are very strict. If the wrong function is used
33  * (the get-integer-setting function is used on a string setting) or
34  * the setting does not exist, an exception will be raised.
35  */
36 
37 #define PH_SETTINGS_PRIVATE
38 #include <phapp.h>
39 #include "mxml/mxml.h"
40 #include <settings.h>
41 #include <settingsp.h>
42 
45 
47 
48 // These macros make sure the C strings can be seamlessly converted into
49 // PH_STRINGREFs at compile time, for a small speed boost.
50 
51 #define ADD_SETTING_WRAPPER(Type, Name, DefaultValue) \
52  { \
53  static PH_STRINGREF name = PH_STRINGREF_INIT(Name); \
54  static PH_STRINGREF defaultValue = PH_STRINGREF_INIT(DefaultValue); \
55  PhpAddSetting(Type, &name, &defaultValue); \
56  }
57 
58 #define PhpAddStringSetting(A, B) ADD_SETTING_WRAPPER(StringSettingType, A, B)
59 #define PhpAddIntegerSetting(A, B) ADD_SETTING_WRAPPER(IntegerSettingType, A, B)
60 #define PhpAddIntegerPairSetting(A, B) ADD_SETTING_WRAPPER(IntegerPairSettingType, A, B)
61 
63  VOID
64  )
65 {
66  PhSettingsHashtable = PhCreateHashtable(
67  sizeof(PH_SETTING),
70  256
71  );
72  PhIgnoredSettings = PhCreateList(4);
73 
74  PhpAddIntegerSetting(L"AllowOnlyOneInstance", L"1");
75  PhpAddIntegerSetting(L"CloseOnEscape", L"0");
76  PhpAddIntegerSetting(L"CollapseServicesOnStart", L"0");
77  PhpAddStringSetting(L"DbgHelpPath", L"dbghelp.dll");
78  PhpAddStringSetting(L"DbgHelpSearchPath", L"");
79  PhpAddIntegerSetting(L"DbgHelpUndecorate", L"1");
80  PhpAddStringSetting(L"DisabledPlugins", L"");
81  PhpAddIntegerSetting(L"ElevationLevel", L"1"); // PromptElevateAction
82  PhpAddIntegerSetting(L"EnableCycleCpuUsage", L"1");
83  PhpAddIntegerSetting(L"EnableInstantTooltips", L"0");
84  PhpAddIntegerSetting(L"EnableKph", L"1");
85  PhpAddIntegerSetting(L"EnableNetworkResolve", L"1");
86  PhpAddIntegerSetting(L"EnablePlugins", L"1");
87  PhpAddIntegerSetting(L"EnableServiceNonPoll", L"0");
88  PhpAddIntegerSetting(L"EnableStage2", L"1");
89  PhpAddIntegerSetting(L"EnableWarnings", L"1");
90  PhpAddStringSetting(L"EnvironmentListViewColumns", L"");
91  PhpAddStringSetting(L"FindObjListViewColumns", L"");
92  PhpAddIntegerPairSetting(L"FindObjWindowPosition", L"350,350");
93  PhpAddIntegerPairSetting(L"FindObjWindowSize", L"550,420");
94  PhpAddIntegerSetting(L"FirstRun", L"1");
95  PhpAddStringSetting(L"Font", L""); // null
96  PhpAddIntegerSetting(L"ForceNoParent", L"0");
97  PhpAddStringSetting(L"HandleTreeListColumns", L"");
98  PhpAddStringSetting(L"HandleTreeListSort", L"0,1"); // 0, AscendingSortOrder
99  PhpAddStringSetting(L"HiddenProcessesListViewColumns", L"");
100  PhpAddIntegerPairSetting(L"HiddenProcessesWindowPosition", L"400,400");
101  PhpAddIntegerPairSetting(L"HiddenProcessesWindowSize", L"520,400");
102  PhpAddIntegerSetting(L"HideDriverServices", L"0");
103  PhpAddIntegerSetting(L"HideOnClose", L"0");
104  PhpAddIntegerSetting(L"HideOnMinimize", L"0");
105  PhpAddIntegerSetting(L"HideOtherUserProcesses", L"0");
106  PhpAddIntegerSetting(L"HideSignedProcesses", L"0");
107  PhpAddIntegerSetting(L"HideUnnamedHandles", L"1");
108  PhpAddIntegerSetting(L"HighlightingDuration", L"3e8"); // 1000ms
109  PhpAddIntegerSetting(L"IconMask", L"1"); // PH_ICON_CPU_HISTORY
110  PhpAddStringSetting(L"IconMaskList", L"");
111  PhpAddIntegerSetting(L"IconNotifyMask", L"c"); // PH_NOTIFY_SERVICE_CREATE | PH_NOTIFY_SERVICE_DELETE
112  PhpAddIntegerSetting(L"IconProcesses", L"f"); // 15
113  PhpAddIntegerSetting(L"IconSingleClick", L"0");
114  PhpAddIntegerSetting(L"IconTogglesVisibility", L"1");
115  PhpAddIntegerSetting(L"LogEntries", L"200"); // 512
116  PhpAddStringSetting(L"LogListViewColumns", L"");
117  PhpAddIntegerPairSetting(L"LogWindowPosition", L"300,300");
118  PhpAddIntegerPairSetting(L"LogWindowSize", L"450,500");
119  PhpAddIntegerSetting(L"MainWindowAlwaysOnTop", L"0");
120  PhpAddIntegerSetting(L"MainWindowOpacity", L"0"); // means 100%
121  PhpAddIntegerPairSetting(L"MainWindowPosition", L"100,100");
122  PhpAddIntegerPairSetting(L"MainWindowSize", L"800,600");
123  PhpAddIntegerSetting(L"MainWindowState", L"1");
124  PhpAddIntegerSetting(L"MaxSizeUnit", L"6");
125  PhpAddIntegerSetting(L"MemEditBytesPerRow", L"10"); // 16
126  PhpAddStringSetting(L"MemEditGotoChoices", L"");
127  PhpAddIntegerPairSetting(L"MemEditPosition", L"450,450");
128  PhpAddIntegerPairSetting(L"MemEditSize", L"600,500");
129  PhpAddStringSetting(L"MemFilterChoices", L"");
130  PhpAddStringSetting(L"MemResultsListViewColumns", L"");
131  PhpAddIntegerPairSetting(L"MemResultsPosition", L"300,300");
132  PhpAddIntegerPairSetting(L"MemResultsSize", L"500,520");
133  PhpAddStringSetting(L"MemoryTreeListColumns", L"");
134  PhpAddStringSetting(L"MemoryTreeListSort", L"0,0"); // 0, NoSortOrder
135  PhpAddIntegerPairSetting(L"MemoryListsWindowPosition", L"400,400");
136  PhpAddStringSetting(L"MemoryReadWriteAddressChoices", L"");
137  PhpAddIntegerSetting(L"MiniInfoWindowOpacity", L"0"); // means 100%
138  PhpAddIntegerSetting(L"MiniInfoWindowPinned", L"0");
139  PhpAddIntegerPairSetting(L"MiniInfoWindowPosition", L"200,200");
140  PhpAddIntegerSetting(L"MiniInfoWindowRefreshAutomatically", L"1");
141  PhpAddIntegerPairSetting(L"MiniInfoWindowSize", L"10,10");
142  PhpAddStringSetting(L"ModuleTreeListColumns", L"");
143  PhpAddStringSetting(L"ModuleTreeListSort", L"0,0"); // 0, NoSortOrder
144  PhpAddStringSetting(L"NetworkTreeListColumns", L"");
145  PhpAddStringSetting(L"NetworkTreeListSort", L"0,1"); // 0, AscendingSortOrder
146  PhpAddIntegerSetting(L"NoPurgeProcessRecords", L"0");
147  PhpAddStringSetting(L"PluginsDirectory", L"plugins");
148  PhpAddStringSetting(L"ProcessServiceListViewColumns", L"");
149  PhpAddStringSetting(L"ProcessTreeListColumns", L"");
150  PhpAddStringSetting(L"ProcessTreeListSort", L"0,0"); // 0, NoSortOrder
151  PhpAddStringSetting(L"ProcPropPage", L"General");
152  PhpAddIntegerPairSetting(L"ProcPropPosition", L"200,200");
153  PhpAddIntegerPairSetting(L"ProcPropSize", L"460,580");
154  PhpAddStringSetting(L"ProgramInspectExecutables", L"peview.exe \"%s\"");
155  PhpAddIntegerSetting(L"PropagateCpuUsage", L"0");
156  PhpAddStringSetting(L"RunAsProgram", L"");
157  PhpAddStringSetting(L"RunAsUserName", L"");
158  PhpAddIntegerSetting(L"SampleCount", L"200"); // 512
159  PhpAddIntegerSetting(L"SampleCountAutomatic", L"1");
160  PhpAddIntegerSetting(L"ScrollToNewProcesses", L"0");
161  PhpAddStringSetting(L"SearchEngine", L"http://www.google.com/search?q=\"%s\"");
162  PhpAddStringSetting(L"ServiceListViewColumns", L"");
163  PhpAddStringSetting(L"ServiceTreeListColumns", L"");
164  PhpAddStringSetting(L"ServiceTreeListSort", L"0,1"); // 0, AscendingSortOrder
165  PhpAddIntegerPairSetting(L"SessionShadowHotkey", L"106,2"); // VK_MULTIPLY,KBDCTRL
166  PhpAddIntegerSetting(L"ShowCommitInSummary", L"1");
167  PhpAddIntegerSetting(L"ShowCpuBelow001", L"0");
168  PhpAddIntegerSetting(L"StartHidden", L"0");
169  PhpAddIntegerSetting(L"SysInfoWindowAlwaysOnTop", L"0");
170  PhpAddIntegerSetting(L"SysInfoWindowOneGraphPerCpu", L"0");
171  PhpAddIntegerPairSetting(L"SysInfoWindowPosition", L"200,200");
172  PhpAddStringSetting(L"SysInfoWindowSection", L"");
173  PhpAddIntegerPairSetting(L"SysInfoWindowSize", L"620,590");
174  PhpAddIntegerSetting(L"ThinRows", L"0");
175  PhpAddStringSetting(L"ThreadTreeListColumns", L"");
176  PhpAddStringSetting(L"ThreadTreeListSort", L"1,2"); // 1, DescendingSortOrder
177  PhpAddStringSetting(L"ThreadStackListViewColumns", L"");
178  PhpAddIntegerPairSetting(L"ThreadStackWindowSize", L"420,380");
179  PhpAddIntegerSetting(L"UpdateInterval", L"3e8"); // 1000ms
180 
181  // Colors are specified with R in the lowest byte, then G, then B.
182  // So: bbggrr.
183  PhpAddIntegerSetting(L"ColorNew", L"00ff7f"); // Chartreuse
184  PhpAddIntegerSetting(L"ColorRemoved", L"283cff");
185  PhpAddIntegerSetting(L"UseColorOwnProcesses", L"1");
186  PhpAddIntegerSetting(L"ColorOwnProcesses", L"aaffff");
187  PhpAddIntegerSetting(L"UseColorSystemProcesses", L"1");
188  PhpAddIntegerSetting(L"ColorSystemProcesses", L"ffccaa");
189  PhpAddIntegerSetting(L"UseColorServiceProcesses", L"1");
190  PhpAddIntegerSetting(L"ColorServiceProcesses", L"ffffcc");
191  PhpAddIntegerSetting(L"UseColorJobProcesses", L"1");
192  PhpAddIntegerSetting(L"ColorJobProcesses", L"3f85cd"); // Peru
193  PhpAddIntegerSetting(L"UseColorWow64Processes", L"1");
194  PhpAddIntegerSetting(L"ColorWow64Processes", L"8f8fbc"); // Rosy Brown
195  PhpAddIntegerSetting(L"UseColorPosixProcesses", L"1");
196  PhpAddIntegerSetting(L"ColorPosixProcesses", L"8b3d48"); // Dark Slate Blue
197  PhpAddIntegerSetting(L"UseColorDebuggedProcesses", L"1");
198  PhpAddIntegerSetting(L"ColorDebuggedProcesses", L"ffbbcc");
199  PhpAddIntegerSetting(L"UseColorElevatedProcesses", L"1");
200  PhpAddIntegerSetting(L"ColorElevatedProcesses", L"00aaff");
201  PhpAddIntegerSetting(L"UseColorImmersiveProcesses", L"1");
202  PhpAddIntegerSetting(L"ColorImmersiveProcesses", L"cbc0ff"); // Pink
203  PhpAddIntegerSetting(L"UseColorSuspended", L"1");
204  PhpAddIntegerSetting(L"ColorSuspended", L"777777");
205  PhpAddIntegerSetting(L"UseColorDotNet", L"1");
206  PhpAddIntegerSetting(L"ColorDotNet", L"00ffde");
207  PhpAddIntegerSetting(L"UseColorPacked", L"1");
208  PhpAddIntegerSetting(L"ColorPacked", L"9314ff"); // Deep Pink
209  PhpAddIntegerSetting(L"UseColorGuiThreads", L"1");
210  PhpAddIntegerSetting(L"ColorGuiThreads", L"77ffff");
211  PhpAddIntegerSetting(L"UseColorRelocatedModules", L"1");
212  PhpAddIntegerSetting(L"ColorRelocatedModules", L"80c0ff");
213  PhpAddIntegerSetting(L"UseColorProtectedHandles", L"1");
214  PhpAddIntegerSetting(L"ColorProtectedHandles", L"777777");
215  PhpAddIntegerSetting(L"UseColorInheritHandles", L"1");
216  PhpAddIntegerSetting(L"ColorInheritHandles", L"ffff77");
217 
218  PhpAddIntegerSetting(L"GraphShowText", L"1");
219  PhpAddIntegerSetting(L"GraphColorMode", L"0");
220  PhpAddIntegerSetting(L"ColorCpuKernel", L"00ff00");
221  PhpAddIntegerSetting(L"ColorCpuUser", L"0000ff");
222  PhpAddIntegerSetting(L"ColorIoReadOther", L"00ffff");
223  PhpAddIntegerSetting(L"ColorIoWrite", L"ff0077");
224  PhpAddIntegerSetting(L"ColorPrivate", L"0077ff");
225  PhpAddIntegerSetting(L"ColorPhysical", L"ffff00");
226 
228 }
229 
231  VOID
232  )
233 {
234 #define UPDATE_INTEGER_CS(Name) (PhCs##Name = PhGetIntegerSetting(L#Name))
235 
236  UPDATE_INTEGER_CS(CollapseServicesOnStart);
237  UPDATE_INTEGER_CS(ForceNoParent);
238  UPDATE_INTEGER_CS(HighlightingDuration);
239  UPDATE_INTEGER_CS(PropagateCpuUsage);
240  UPDATE_INTEGER_CS(ScrollToNewProcesses);
241  UPDATE_INTEGER_CS(ShowCpuBelow001);
242  UPDATE_INTEGER_CS(UpdateInterval);
243 
244  UPDATE_INTEGER_CS(ColorNew);
245  UPDATE_INTEGER_CS(ColorRemoved);
246  UPDATE_INTEGER_CS(UseColorOwnProcesses);
247  UPDATE_INTEGER_CS(ColorOwnProcesses);
248  UPDATE_INTEGER_CS(UseColorSystemProcesses);
249  UPDATE_INTEGER_CS(ColorSystemProcesses);
250  UPDATE_INTEGER_CS(UseColorServiceProcesses);
251  UPDATE_INTEGER_CS(ColorServiceProcesses);
252  UPDATE_INTEGER_CS(UseColorJobProcesses);
253  UPDATE_INTEGER_CS(ColorJobProcesses);
254  UPDATE_INTEGER_CS(UseColorWow64Processes);
255  UPDATE_INTEGER_CS(ColorWow64Processes);
256  UPDATE_INTEGER_CS(UseColorPosixProcesses);
257  UPDATE_INTEGER_CS(ColorPosixProcesses);
258  UPDATE_INTEGER_CS(UseColorDebuggedProcesses);
259  UPDATE_INTEGER_CS(ColorDebuggedProcesses);
260  UPDATE_INTEGER_CS(UseColorElevatedProcesses);
261  UPDATE_INTEGER_CS(ColorElevatedProcesses);
262  UPDATE_INTEGER_CS(UseColorImmersiveProcesses);
263  UPDATE_INTEGER_CS(ColorImmersiveProcesses);
264  UPDATE_INTEGER_CS(UseColorSuspended);
265  UPDATE_INTEGER_CS(ColorSuspended);
266  UPDATE_INTEGER_CS(UseColorDotNet);
267  UPDATE_INTEGER_CS(ColorDotNet);
268  UPDATE_INTEGER_CS(UseColorPacked);
269  UPDATE_INTEGER_CS(ColorPacked);
270  UPDATE_INTEGER_CS(UseColorGuiThreads);
271  UPDATE_INTEGER_CS(ColorGuiThreads);
272  UPDATE_INTEGER_CS(UseColorRelocatedModules);
273  UPDATE_INTEGER_CS(ColorRelocatedModules);
274  UPDATE_INTEGER_CS(UseColorProtectedHandles);
275  UPDATE_INTEGER_CS(ColorProtectedHandles);
276  UPDATE_INTEGER_CS(UseColorInheritHandles);
277  UPDATE_INTEGER_CS(ColorInheritHandles);
278  UPDATE_INTEGER_CS(GraphShowText);
279  UPDATE_INTEGER_CS(GraphColorMode);
280  UPDATE_INTEGER_CS(ColorCpuKernel);
281  UPDATE_INTEGER_CS(ColorCpuUser);
282  UPDATE_INTEGER_CS(ColorIoReadOther);
283  UPDATE_INTEGER_CS(ColorIoWrite);
284  UPDATE_INTEGER_CS(ColorPrivate);
285  UPDATE_INTEGER_CS(ColorPhysical);
286 }
287 
289  _In_ PVOID Entry1,
290  _In_ PVOID Entry2
291  )
292 {
293  PPH_SETTING setting1 = (PPH_SETTING)Entry1;
294  PPH_SETTING setting2 = (PPH_SETTING)Entry2;
295 
296  return PhEqualStringRef(&setting1->Name, &setting2->Name, FALSE);
297 }
298 
300  _In_ PVOID Entry
301  )
302 {
303  PPH_SETTING setting = (PPH_SETTING)Entry;
304 
305  return PhHashBytes((PUCHAR)setting->Name.Buffer, setting->Name.Length);
306 }
307 
308 static VOID PhpAddSetting(
309  _In_ PH_SETTING_TYPE Type,
310  _In_ PPH_STRINGREF Name,
311  _In_ PPH_STRINGREF DefaultValue
312  )
313 {
314  PH_SETTING setting;
315 
316  setting.Type = Type;
317  setting.Name = *Name;
318  setting.DefaultValue = *DefaultValue;
319  memset(&setting.u, 0, sizeof(setting.u));
320 
321  PhpSettingFromString(Type, &setting.DefaultValue, NULL, &setting);
322 
323  PhAddEntryHashtable(PhSettingsHashtable, &setting);
324 }
325 
327  _In_ PH_SETTING_TYPE Type,
328  _In_ PPH_SETTING Setting
329  )
330 {
331  switch (Type)
332  {
333  case StringSettingType:
334  {
335  if (!Setting->u.Pointer)
336  return PhReferenceEmptyString();
337 
338  PhReferenceObject(Setting->u.Pointer);
339 
340  return (PPH_STRING)Setting->u.Pointer;
341  }
342  case IntegerSettingType:
343  {
344  return PhFormatString(L"%x", Setting->u.Integer);
345  }
347  {
348  PPH_INTEGER_PAIR integerPair = &Setting->u.IntegerPair;
349 
350  return PhFormatString(L"%u,%u", integerPair->X, integerPair->Y);
351  }
352  }
353 
354  return PhReferenceEmptyString();
355 }
356 
357 static BOOLEAN PhpSettingFromString(
358  _In_ PH_SETTING_TYPE Type,
359  _In_ PPH_STRINGREF StringRef,
360  _In_opt_ PPH_STRING String,
361  _Inout_ PPH_SETTING Setting
362  )
363 {
364  switch (Type)
365  {
366  case StringSettingType:
367  {
368  if (String)
369  {
370  PhSetReference(&Setting->u.Pointer, String);
371  }
372  else
373  {
374  Setting->u.Pointer = PhCreateString2(StringRef);
375  }
376 
377  return TRUE;
378  }
379  case IntegerSettingType:
380  {
381  ULONG64 integer;
382 
383  if (PhStringToInteger64(StringRef, 16, &integer))
384  {
385  Setting->u.Integer = (ULONG)integer;
386  return TRUE;
387  }
388  else
389  {
390  return FALSE;
391  }
392  }
394  {
395  LONG64 x;
396  LONG64 y;
397  PH_STRINGREF xString;
398  PH_STRINGREF yString;
399 
400  if (!PhSplitStringRefAtChar(StringRef, ',', &xString, &yString))
401  return FALSE;
402 
403  if (PhStringToInteger64(&xString, 10, &x) && PhStringToInteger64(&yString, 10, &y))
404  {
405  Setting->u.IntegerPair.X = (LONG)x;
406  Setting->u.IntegerPair.Y = (LONG)y;
407  return TRUE;
408  }
409  else
410  {
411  return FALSE;
412  }
413  }
414  }
415 
416  return FALSE;
417 }
418 
420  _In_ PH_SETTING_TYPE Type,
421  _In_ PPH_SETTING Setting
422  )
423 {
424  switch (Type)
425  {
426  case StringSettingType:
427  if (Setting->u.Pointer)
428  PhDereferenceObject(Setting->u.Pointer);
429  break;
430  }
431 }
432 
433 static PVOID PhpLookupSetting(
434  _In_ PPH_STRINGREF Name
435  )
436 {
437  PH_SETTING lookupSetting;
438  PPH_SETTING setting;
439 
440  lookupSetting.Name = *Name;
442  PhSettingsHashtable,
443  &lookupSetting
444  );
445 
446  return setting;
447 }
448 
450  _In_ PWSTR Name
451  )
452 {
453  PPH_SETTING setting;
454  PH_STRINGREF name;
455  ULONG value;
456 
457  PhInitializeStringRef(&name, Name);
458 
459  PhAcquireQueuedLockShared(&PhSettingsLock);
460 
461  setting = PhpLookupSetting(&name);
462 
463  if (setting && setting->Type == IntegerSettingType)
464  {
465  value = setting->u.Integer;
466  }
467  else
468  {
469  setting = NULL;
470  }
471 
472  PhReleaseQueuedLockShared(&PhSettingsLock);
473 
474  if (!setting)
475  PhRaiseStatus(STATUS_NOT_FOUND);
476 
477  return value;
478 }
479 
481  _In_ PWSTR Name
482  )
483 {
484  PPH_SETTING setting;
485  PH_STRINGREF name;
486  PH_INTEGER_PAIR value;
487 
488  PhInitializeStringRef(&name, Name);
489 
490  PhAcquireQueuedLockShared(&PhSettingsLock);
491 
492  setting = PhpLookupSetting(&name);
493 
494  if (setting && setting->Type == IntegerPairSettingType)
495  {
496  value = setting->u.IntegerPair;
497  }
498  else
499  {
500  setting = NULL;
501  }
502 
503  PhReleaseQueuedLockShared(&PhSettingsLock);
504 
505  if (!setting)
506  PhRaiseStatus(STATUS_NOT_FOUND);
507 
508  return value;
509 }
510 
512  _In_ PWSTR Name
513  )
514 {
515  PPH_SETTING setting;
516  PH_STRINGREF name;
517  PPH_STRING value;
518 
519  PhInitializeStringRef(&name, Name);
520 
521  PhAcquireQueuedLockShared(&PhSettingsLock);
522 
523  setting = PhpLookupSetting(&name);
524 
525  if (setting && setting->Type == StringSettingType)
526  {
527  if (setting->u.Pointer)
528  {
529  PhSetReference(&value, setting->u.Pointer);
530  }
531  else
532  {
533  // Set to NULL, create an empty string
534  // outside of the lock.
535  value = NULL;
536  }
537  }
538  else
539  {
540  setting = NULL;
541  }
542 
543  PhReleaseQueuedLockShared(&PhSettingsLock);
544 
545  if (!setting)
546  PhRaiseStatus(STATUS_NOT_FOUND);
547 
548  if (!value)
549  value = PhReferenceEmptyString();
550 
551  return value;
552 }
553 
555  _In_ PWSTR Name,
556  _In_ ULONG Value
557  )
558 {
559  PPH_SETTING setting;
560  PH_STRINGREF name;
561 
562  PhInitializeStringRef(&name, Name);
563 
564  PhAcquireQueuedLockExclusive(&PhSettingsLock);
565 
566  setting = PhpLookupSetting(&name);
567 
568  if (setting && setting->Type == IntegerSettingType)
569  {
570  setting->u.Integer = Value;
571  }
572 
573  PhReleaseQueuedLockExclusive(&PhSettingsLock);
574 
575  if (!setting)
576  PhRaiseStatus(STATUS_NOT_FOUND);
577 }
578 
580  _In_ PWSTR Name,
581  _In_ PH_INTEGER_PAIR Value
582  )
583 {
584  PPH_SETTING setting;
585  PH_STRINGREF name;
586 
587  PhInitializeStringRef(&name, Name);
588 
589  PhAcquireQueuedLockExclusive(&PhSettingsLock);
590 
591  setting = PhpLookupSetting(&name);
592 
593  if (setting && setting->Type == IntegerPairSettingType)
594  {
595  setting->u.IntegerPair = Value;
596  }
597 
598  PhReleaseQueuedLockExclusive(&PhSettingsLock);
599 
600  if (!setting)
601  PhRaiseStatus(STATUS_NOT_FOUND);
602 }
603 
605  _In_ PWSTR Name,
606  _In_ PWSTR Value
607  )
608 {
609  PPH_SETTING setting;
610  PH_STRINGREF name;
611 
612  PhInitializeStringRef(&name, Name);
613 
614  PhAcquireQueuedLockExclusive(&PhSettingsLock);
615 
616  setting = PhpLookupSetting(&name);
617 
618  if (setting && setting->Type == StringSettingType)
619  {
621  setting->u.Pointer = PhCreateString(Value);
622  }
623 
624  PhReleaseQueuedLockExclusive(&PhSettingsLock);
625 
626  if (!setting)
627  PhRaiseStatus(STATUS_NOT_FOUND);
628 }
629 
631  _In_ PWSTR Name,
632  _In_ PPH_STRINGREF Value
633  )
634 {
635  PPH_SETTING setting;
636  PH_STRINGREF name;
637 
638  PhInitializeStringRef(&name, Name);
639 
640  PhAcquireQueuedLockExclusive(&PhSettingsLock);
641 
642  setting = PhpLookupSetting(&name);
643 
644  if (setting && setting->Type == StringSettingType)
645  {
647  setting->u.Pointer = PhCreateString2(Value);
648  }
649 
650  PhReleaseQueuedLockExclusive(&PhSettingsLock);
651 
652  if (!setting)
653  PhRaiseStatus(STATUS_NOT_FOUND);
654 }
655 
657  _In_ PPH_SETTING Setting
658  )
659 {
660  PhFree(Setting->Name.Buffer);
661  PhDereferenceObject(Setting->u.Pointer);
662 
663  PhFree(Setting);
664 }
665 
667  VOID
668  )
669 {
670  ULONG i;
671 
672  PhAcquireQueuedLockExclusive(&PhSettingsLock);
673 
674  for (i = 0; i < PhIgnoredSettings->Count; i++)
675  {
676  PhpFreeIgnoredSetting(PhIgnoredSettings->Items[i]);
677  }
678 
679  PhClearList(PhIgnoredSettings);
680 
681  PhReleaseQueuedLockExclusive(&PhSettingsLock);
682 }
683 
685  VOID
686  )
687 {
689 }
690 
692  VOID
693  )
694 {
695  ULONG i;
696 
697  PhAcquireQueuedLockExclusive(&PhSettingsLock);
698 
699  for (i = 0; i < PhIgnoredSettings->Count; i++)
700  {
701  PPH_SETTING ignoredSetting = PhIgnoredSettings->Items[i];
702  PPH_SETTING setting;
703 
704  setting = PhpLookupSetting(&ignoredSetting->Name);
705 
706  if (setting)
707  {
708  PhpFreeSettingValue(setting->Type, setting);
709 
711  setting->Type,
712  &((PPH_STRING)ignoredSetting->u.Pointer)->sr,
713  ignoredSetting->u.Pointer,
714  setting
715  ))
716  {
718  setting->Type,
719  &setting->DefaultValue,
720  NULL,
721  setting
722  );
723  }
724 
725  PhpFreeIgnoredSetting(ignoredSetting);
726 
727  PhRemoveItemList(PhIgnoredSettings, i);
728  i--;
729  }
730  }
731 
732  PhReleaseQueuedLockExclusive(&PhSettingsLock);
733 }
734 
736  _In_ mxml_node_t *node
737  )
738 {
739  return MXML_OPAQUE;
740 }
741 
742 NTSTATUS PhLoadSettings(
743  _In_ PWSTR FileName
744  )
745 {
746  NTSTATUS status;
747  HANDLE fileHandle;
748  LARGE_INTEGER fileSize;
749  mxml_node_t *topNode;
750  mxml_node_t *currentNode;
751 
753 
754  status = PhCreateFileWin32(
755  &fileHandle,
756  FileName,
757  FILE_GENERIC_READ,
758  0,
759  FILE_SHARE_READ | FILE_SHARE_DELETE,
760  FILE_OPEN,
762  );
763 
764  if (!NT_SUCCESS(status))
765  return status;
766 
767  if (NT_SUCCESS(PhGetFileSize(fileHandle, &fileSize)) && fileSize.QuadPart == 0)
768  {
769  // A blank file is OK. There are no settings to load.
770  NtClose(fileHandle);
771  return status;
772  }
773 
774  topNode = mxmlLoadFd(NULL, fileHandle, PhpSettingsLoadCallback);
775  NtClose(fileHandle);
776 
777  if (!topNode)
778  return STATUS_FILE_CORRUPT_ERROR;
779 
780  if (topNode->type != MXML_ELEMENT)
781  {
782  mxmlDelete(topNode);
783  return STATUS_FILE_CORRUPT_ERROR;
784  }
785 
786  currentNode = topNode->child;
787 
788  while (currentNode)
789  {
790  PPH_STRING settingName = NULL;
791 
792  if (
793  currentNode->type == MXML_ELEMENT &&
794  currentNode->value.element.num_attrs >= 1 &&
795  stricmp(currentNode->value.element.attrs[0].name, "name") == 0
796  )
797  {
798  settingName = PhConvertUtf8ToUtf16(currentNode->value.element.attrs[0].value);
799  }
800 
801  if (settingName)
802  {
803  PPH_STRING settingValue;
804 
805  settingValue = PhGetOpaqueXmlNodeText(currentNode);
806 
807  PhAcquireQueuedLockExclusive(&PhSettingsLock);
808 
809  {
810  PPH_SETTING setting;
811 
812  setting = PhpLookupSetting(&settingName->sr);
813 
814  if (setting)
815  {
816  PhpFreeSettingValue(setting->Type, setting);
817 
819  setting->Type,
820  &settingValue->sr,
821  settingValue,
822  setting
823  ))
824  {
826  setting->Type,
827  &setting->DefaultValue,
828  NULL,
829  setting
830  );
831  }
832  }
833  else
834  {
835  setting = PhAllocate(sizeof(PH_SETTING));
836  setting->Name.Buffer = PhAllocateCopy(settingName->Buffer, settingName->Length + sizeof(WCHAR));
837  setting->Name.Length = settingName->Length;
838  PhReferenceObject(settingValue);
839  setting->u.Pointer = settingValue;
840 
841  PhAddItemList(PhIgnoredSettings, setting);
842  }
843  }
844 
845  PhReleaseQueuedLockExclusive(&PhSettingsLock);
846 
847  PhDereferenceObject(settingValue);
848  PhDereferenceObject(settingName);
849  }
850 
851  currentNode = currentNode->next;
852  }
853 
854  mxmlDelete(topNode);
855 
857 
858  return STATUS_SUCCESS;
859 }
860 
862  _In_ mxml_node_t *node,
863  _In_ int position
864  )
865 {
866  if (PhEqualBytesZ(node->value.element.name, "setting", TRUE))
867  {
868  if (position == MXML_WS_BEFORE_OPEN)
869  return " ";
870  else if (position == MXML_WS_AFTER_CLOSE)
871  return "\r\n";
872  }
873  else if (PhEqualBytesZ(node->value.element.name, "settings", TRUE))
874  {
875  if (position == MXML_WS_AFTER_OPEN)
876  return "\r\n";
877  }
878 
879  return NULL;
880 }
881 
883  _Inout_ mxml_node_t *ParentNode,
884  _In_ PPH_STRINGREF SettingName,
885  _In_ PPH_STRINGREF SettingValue
886  )
887 {
888  mxml_node_t *settingNode;
889  mxml_node_t *textNode;
890  PPH_BYTES settingNameUtf8;
891  PPH_BYTES settingValueUtf8;
892 
893  // Create the setting element.
894 
895  settingNode = mxmlNewElement(ParentNode, "setting");
896 
897  settingNameUtf8 = PhConvertUtf16ToUtf8Ex(SettingName->Buffer, SettingName->Length);
898  mxmlElementSetAttr(settingNode, "name", settingNameUtf8->Buffer);
899  PhDereferenceObject(settingNameUtf8);
900 
901  // Set the value.
902 
903  settingValueUtf8 = PhConvertUtf16ToUtf8Ex(SettingValue->Buffer, SettingValue->Length);
904  textNode = mxmlNewOpaque(settingNode, settingValueUtf8->Buffer);
905  PhDereferenceObject(settingValueUtf8);
906 
907  return settingNode;
908 }
909 
910 NTSTATUS PhSaveSettings(
911  _In_ PWSTR FileName
912  )
913 {
914  NTSTATUS status;
915  HANDLE fileHandle;
916  mxml_node_t *topNode;
917  PH_HASHTABLE_ENUM_CONTEXT enumContext;
918  PPH_SETTING setting;
919 
920  topNode = mxmlNewElement(MXML_NO_PARENT, "settings");
921 
922  PhAcquireQueuedLockShared(&PhSettingsLock);
923 
924  PhBeginEnumHashtable(PhSettingsHashtable, &enumContext);
925 
926  while (setting = PhNextEnumHashtable(&enumContext))
927  {
928  PPH_STRING settingValue;
929 
930  settingValue = PhpSettingToString(setting->Type, setting);
931  PhpCreateSettingElement(topNode, &setting->Name, &settingValue->sr);
932  PhDereferenceObject(settingValue);
933  }
934 
935  // Write the ignored settings.
936  {
937  ULONG i;
938 
939  for (i = 0; i < PhIgnoredSettings->Count; i++)
940  {
941  PPH_STRING settingValue;
942 
943  setting = PhIgnoredSettings->Items[i];
944  settingValue = setting->u.Pointer;
945  PhpCreateSettingElement(topNode, &setting->Name, &settingValue->sr);
946  }
947  }
948 
949  PhReleaseQueuedLockShared(&PhSettingsLock);
950 
951  // Create the directory if it does not exist.
952  {
953  PPH_STRING fullPath;
954  ULONG indexOfFileName;
955  PPH_STRING directoryName;
956 
957  fullPath = PhGetFullPath(FileName, &indexOfFileName);
958 
959  if (fullPath)
960  {
961  if (indexOfFileName != -1)
962  {
963  directoryName = PhSubstring(fullPath, 0, indexOfFileName);
964  SHCreateDirectoryEx(NULL, directoryName->Buffer, NULL);
965  PhDereferenceObject(directoryName);
966  }
967 
968  PhDereferenceObject(fullPath);
969  }
970  }
971 
972  status = PhCreateFileWin32(
973  &fileHandle,
974  FileName,
975  FILE_GENERIC_WRITE,
976  0,
977  FILE_SHARE_READ,
980  );
981 
982  if (!NT_SUCCESS(status))
983  {
984  mxmlDelete(topNode);
985  return status;
986  }
987 
988  mxmlSaveFd(topNode, fileHandle, PhpSettingsSaveCallback);
989  mxmlDelete(topNode);
990  NtClose(fileHandle);
991 
992  return STATUS_SUCCESS;
993 }
994 
996  VOID
997  )
998 {
999  PH_HASHTABLE_ENUM_CONTEXT enumContext;
1000  PPH_SETTING setting;
1001 
1002  PhAcquireQueuedLockExclusive(&PhSettingsLock);
1003 
1004  PhBeginEnumHashtable(PhSettingsHashtable, &enumContext);
1005 
1006  while (setting = PhNextEnumHashtable(&enumContext))
1007  {
1008  PhpFreeSettingValue(setting->Type, setting);
1009  PhpSettingFromString(setting->Type, &setting->DefaultValue, NULL, setting);
1010  }
1011 
1012  PhReleaseQueuedLockExclusive(&PhSettingsLock);
1013 }
1014 
1016  _In_ PPH_SETTING_CREATE Settings,
1017  _In_ ULONG NumberOfSettings
1018  )
1019 {
1020  ULONG i;
1021 
1022  PhAcquireQueuedLockExclusive(&PhSettingsLock);
1023 
1024  for (i = 0; i < NumberOfSettings; i++)
1025  {
1026  PH_STRINGREF name;
1027  PH_STRINGREF defaultValue;
1028 
1029  PhInitializeStringRefLongHint(&name, Settings[i].Name);
1030  PhInitializeStringRefLongHint(&defaultValue, Settings[i].DefaultValue);
1031  PhpAddSetting(Settings[i].Type, &name, &defaultValue);
1032  }
1033 
1034  PhReleaseQueuedLockExclusive(&PhSettingsLock);
1035 }