988aa477f722cb7ac6606f49d66385d238d1f566
4 * Copyright (C) 2002 Robert Dickenson <robd@reactos.org>
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #define WIN32_LEAN_AND_MEAN /* Exclude rarely-used stuff from Windows headers */
30 ChildWnd
* g_pChildWnd
;
31 HBITMAP SizingPattern
= 0;
32 HBRUSH SizingBrush
= 0;
33 static TCHAR Suggestions
[256];
35 /*******************************************************************************
36 * Local module support methods
39 static LPCTSTR
get_root_key_name(HKEY hRootKey
)
41 if (hRootKey
== HKEY_CLASSES_ROOT
) return _T("HKEY_CLASSES_ROOT");
42 if (hRootKey
== HKEY_CURRENT_USER
) return _T("HKEY_CURRENT_USER");
43 if (hRootKey
== HKEY_LOCAL_MACHINE
) return _T("HKEY_LOCAL_MACHINE");
44 if (hRootKey
== HKEY_USERS
) return _T("HKEY_USERS");
45 if (hRootKey
== HKEY_CURRENT_CONFIG
) return _T("HKEY_CURRENT_CONFIG");
46 if (hRootKey
== HKEY_DYN_DATA
) return _T("HKEY_DYN_DATA");
47 return _T("UKNOWN HKEY, PLEASE REPORT");
50 static void draw_splitbar(HWND hWnd
, int x
)
54 HDC hdc
= GetDC(hWnd
);
58 const DWORD Pattern
[4] = {0x5555AAAA, 0x5555AAAA, 0x5555AAAA, 0x5555AAAA};
59 SizingPattern
= CreateBitmap(8, 8, 1, 1, Pattern
);
63 SizingBrush
= CreatePatternBrush(SizingPattern
);
65 GetClientRect(hWnd
, &rt
);
66 rt
.left
= x
- SPLIT_WIDTH
/2;
67 rt
.right
= x
+ SPLIT_WIDTH
/2+1;
68 OldObj
= SelectObject(hdc
, SizingBrush
);
69 PatBlt(hdc
, rt
.left
, rt
.top
, rt
.right
- rt
.left
, rt
.bottom
- rt
.top
, PATINVERT
);
70 SelectObject(hdc
, OldObj
);
74 static void ResizeWnd(ChildWnd
* pChildWnd
, int cx
, int cy
)
76 HDWP hdwp
= BeginDeferWindowPos(2);
77 RECT rt
= {0, 0, cx
, cy
};
79 cx
= pChildWnd
->nSplitPos
+ SPLIT_WIDTH
/2;
80 DeferWindowPos(hdwp
, pChildWnd
->hTreeWnd
, 0, rt
.left
, rt
.top
, pChildWnd
->nSplitPos
-SPLIT_WIDTH
/2-rt
.left
, rt
.bottom
-rt
.top
, SWP_NOZORDER
|SWP_NOACTIVATE
);
81 DeferWindowPos(hdwp
, pChildWnd
->hListWnd
, 0, rt
.left
+cx
, rt
.top
, rt
.right
-cx
, rt
.bottom
-rt
.top
, SWP_NOZORDER
|SWP_NOACTIVATE
);
82 EndDeferWindowPos(hdwp
);
85 static void OnPaint(HWND hWnd
)
91 GetClientRect(hWnd
, &rt
);
92 hdc
= BeginPaint(hWnd
, &ps
);
93 FillRect(ps
.hdc
, &rt
, GetSysColorBrush(COLOR_BTNFACE
));
97 /*******************************************************************************
99 * FUNCTION: _CmdWndProc(HWND, unsigned, WORD, LONG)
101 * PURPOSE: Processes WM_COMMAND messages for the main frame window.
105 static BOOL
_CmdWndProc(HWND hWnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
107 ChildWnd
* pChildWnd
= g_pChildWnd
;
108 HTREEITEM hSelection
;
111 WORD wID
= LOWORD(wParam
);
114 /* Parse the menu selections: */
115 case ID_REGISTRY_EXIT
:
118 case ID_VIEW_REFRESH
:
121 case ID_TREE_EXPANDBRANCH
:
122 TreeView_Expand(pChildWnd
->hTreeWnd
, TreeView_GetSelection(pChildWnd
->hTreeWnd
), TVE_EXPAND
);
124 case ID_TREE_COLLAPSEBRANCH
:
125 TreeView_Expand(pChildWnd
->hTreeWnd
, TreeView_GetSelection(pChildWnd
->hTreeWnd
), TVE_COLLAPSE
);
128 SetFocus(pChildWnd
->hTreeWnd
);
129 TreeView_EditLabel(pChildWnd
->hTreeWnd
, TreeView_GetSelection(pChildWnd
->hTreeWnd
));
132 hSelection
= TreeView_GetSelection(pChildWnd
->hTreeWnd
);
133 keyPath
= GetItemPath(pChildWnd
->hTreeWnd
, hSelection
, &hRootKey
);
135 if (keyPath
== 0 || *keyPath
== 0)
137 MessageBeep(MB_ICONHAND
);
139 if (DeleteKey(hWnd
, hRootKey
, keyPath
))
140 DeleteNode(g_pChildWnd
->hTreeWnd
, 0);
143 ExportRegistryFile(pChildWnd
->hTreeWnd
);
148 case ID_EDIT_COPYKEYNAME
:
149 hSelection
= TreeView_GetSelection(pChildWnd
->hTreeWnd
);
150 keyPath
= GetItemPath(pChildWnd
->hTreeWnd
, hSelection
, &hRootKey
);
151 CopyKeyName(hWnd
, hRootKey
, keyPath
);
153 case ID_EDIT_NEW_KEY
:
154 CreateNewKey(pChildWnd
->hTreeWnd
, TreeView_GetSelection(pChildWnd
->hTreeWnd
));
156 case ID_EDIT_NEW_STRINGVALUE
:
157 case ID_EDIT_NEW_BINARYVALUE
:
158 case ID_EDIT_NEW_DWORDVALUE
:
159 SendMessage(hFrameWnd
, WM_COMMAND
, wParam
, lParam
);
161 case ID_SWITCH_PANELS
:
162 pChildWnd
->nFocusPanel
= !pChildWnd
->nFocusPanel
;
163 SetFocus(pChildWnd
->nFocusPanel
? pChildWnd
->hListWnd
: pChildWnd
->hTreeWnd
);
166 if ((wID
>= ID_TREE_SUGGESTION_MIN
) && (wID
<= ID_TREE_SUGGESTION_MAX
))
169 while(wID
> ID_TREE_SUGGESTION_MIN
)
175 SelectNode(pChildWnd
->hTreeWnd
, s
);
183 /*******************************************************************************
188 #define MIN(a,b) ((a < b) ? (a) : (b))
190 static void SuggestKeys(HKEY hRootKey
, LPCTSTR pszKeyPath
, LPTSTR pszSuggestions
,
191 size_t iSuggestionsLength
)
194 TCHAR szLastFound
[256];
196 HKEY hOtherKey
, hSubKey
;
199 memset(pszSuggestions
, 0, iSuggestionsLength
* sizeof(*pszSuggestions
));
200 iSuggestionsLength
--;
202 /* Are we a root key in HKEY_CLASSES_ROOT? */
203 if ((hRootKey
== HKEY_CLASSES_ROOT
) && pszKeyPath
[0] && !_tcschr(pszKeyPath
, '\\'))
209 /* Check default key */
210 if (RegQueryStringValue(hRootKey
, pszKeyPath
, NULL
,
211 szBuffer
, sizeof(szBuffer
) / sizeof(szBuffer
[0])) == ERROR_SUCCESS
)
213 /* Sanity check this key; it cannot be empty, nor can it be a
215 if ((szBuffer
[0] != '\0') && _tcsicmp(szBuffer
, pszKeyPath
))
217 if (RegOpenKey(hRootKey
, szBuffer
, &hOtherKey
) == ERROR_SUCCESS
)
219 lstrcpyn(pszSuggestions
, TEXT("HKCR\\"), iSuggestionsLength
);
220 i
= _tcslen(pszSuggestions
);
222 iSuggestionsLength
-= i
;
224 lstrcpyn(pszSuggestions
, szBuffer
, iSuggestionsLength
);
225 i
= MIN(_tcslen(pszSuggestions
) + 1, iSuggestionsLength
);
227 iSuggestionsLength
-= i
;
228 RegCloseKey(hOtherKey
);
231 _tcscpy(szLastFound
, szBuffer
);
232 pszKeyPath
= szLastFound
;
237 while(bFound
&& (iSuggestionsLength
> 0));
239 /* Check CLSID key */
240 if (RegOpenKey(hRootKey
, pszKeyPath
, &hSubKey
) == ERROR_SUCCESS
)
242 if (RegQueryStringValue(hSubKey
, TEXT("CLSID"), NULL
,
243 szBuffer
, sizeof(szBuffer
) / sizeof(szBuffer
[0])) == ERROR_SUCCESS
)
245 lstrcpyn(pszSuggestions
, TEXT("HKCR\\CLSID\\"), iSuggestionsLength
);
246 i
= _tcslen(pszSuggestions
);
248 iSuggestionsLength
-= i
;
250 lstrcpyn(pszSuggestions
, szBuffer
, iSuggestionsLength
);
251 i
= MIN(_tcslen(pszSuggestions
) + 1, iSuggestionsLength
);
253 iSuggestionsLength
-= i
;
255 RegCloseKey(hSubKey
);
260 /*******************************************************************************
262 * FUNCTION: ChildWndProc(HWND, unsigned, WORD, LONG)
264 * PURPOSE: Processes messages for the child windows.
266 * WM_COMMAND - process the application menu
267 * WM_PAINT - Paint the main window
268 * WM_DESTROY - post a quit message and return
271 LRESULT CALLBACK
ChildWndProc(HWND hWnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
273 static short last_split
;
275 ChildWnd
* pChildWnd
= g_pChildWnd
;
280 TCHAR buffer
[MAX_PATH
];
281 /* load "My Computer" string */
282 LoadString(hInst
, IDS_MY_COMPUTER
, buffer
, sizeof(buffer
)/sizeof(TCHAR
));
284 g_pChildWnd
= pChildWnd
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(ChildWnd
));
286 if (!pChildWnd
) return 0;
287 _tcsncpy(pChildWnd
->szPath
, buffer
, MAX_PATH
);
288 pChildWnd
->nSplitPos
= 250;
289 pChildWnd
->hWnd
= hWnd
;
290 pChildWnd
->hTreeWnd
= CreateTreeView(hWnd
, pChildWnd
->szPath
, (HMENU
) TREE_WINDOW
);
291 pChildWnd
->hListWnd
= CreateListView(hWnd
, (HMENU
) LIST_WINDOW
/*, pChildWnd->szPath*/);
292 SetFocus(pChildWnd
->hTreeWnd
);
296 if (!_CmdWndProc(hWnd
, message
, wParam
, lParam
)) {
304 if (LOWORD(lParam
) == HTCLIENT
) {
307 ScreenToClient(hWnd
, &pt
);
308 if (pt
.x
>=pChildWnd
->nSplitPos
-SPLIT_WIDTH
/2 && pt
.x
<pChildWnd
->nSplitPos
+SPLIT_WIDTH
/2+1) {
309 SetCursor(LoadCursor(0, IDC_SIZEWE
));
316 DestroyListView(pChildWnd
->hListWnd
);
318 HeapFree(GetProcessHeap(), 0, pChildWnd
);
322 case WM_LBUTTONDOWN
: {
325 pt
= MAKEPOINTS(lParam
);
326 GetClientRect(hWnd
, &rt
);
327 if (pt
.x
>=pChildWnd
->nSplitPos
-SPLIT_WIDTH
/2 && pt
.x
<pChildWnd
->nSplitPos
+SPLIT_WIDTH
/2+1) {
328 last_split
= pChildWnd
->nSplitPos
;
329 draw_splitbar(hWnd
, last_split
);
336 if (GetCapture() == hWnd
) {
339 pt
= MAKEPOINTS(lParam
);
340 GetClientRect(hWnd
, &rt
);
341 pt
.x
= (SHORT
) min(max(pt
.x
, SPLIT_MIN
), rt
.right
- SPLIT_MIN
);
342 draw_splitbar(hWnd
, last_split
);
344 pChildWnd
->nSplitPos
= pt
.x
;
345 ResizeWnd(pChildWnd
, rt
.right
, rt
.bottom
);
350 case WM_CAPTURECHANGED
:
351 if (GetCapture()==hWnd
&& last_split
>=0)
352 draw_splitbar(hWnd
, last_split
);
356 if (wParam
== VK_ESCAPE
)
357 if (GetCapture() == hWnd
) {
359 draw_splitbar(hWnd
, last_split
);
360 GetClientRect(hWnd
, &rt
);
361 ResizeWnd(pChildWnd
, rt
.right
, rt
.bottom
);
364 SetCursor(LoadCursor(0, IDC_ARROW
));
369 if (GetCapture() == hWnd
) {
376 const DWORD Pattern
[4] = {0x5555AAAA, 0x5555AAAA, 0x5555AAAA, 0x5555AAAA};
377 SizingPattern
= CreateBitmap(8, 8, 1, 1, Pattern
);
381 SizingBrush
= CreatePatternBrush(SizingPattern
);
384 pt
= MAKEPOINTS(lParam
);
385 GetClientRect(hWnd
, &rt
);
386 pt
.x
= (SHORT
) min(max(pt
.x
, SPLIT_MIN
), rt
.right
- SPLIT_MIN
);
387 if(last_split
!= pt
.x
)
389 rt
.left
= last_split
-SPLIT_WIDTH
/2;
390 rt
.right
= last_split
+SPLIT_WIDTH
/2+1;
392 OldObj
= SelectObject(hdc
, SizingBrush
);
393 PatBlt(hdc
, rt
.left
, rt
.top
, rt
.right
- rt
.left
, rt
.bottom
- rt
.top
, PATINVERT
);
395 rt
.left
= pt
.x
-SPLIT_WIDTH
/2;
396 rt
.right
= pt
.x
+SPLIT_WIDTH
/2+1;
397 PatBlt(hdc
, rt
.left
, rt
.top
, rt
.right
- rt
.left
, rt
.bottom
- rt
.top
, PATINVERT
);
398 SelectObject(hdc
, OldObj
);
399 ReleaseDC(hWnd
, hdc
);
405 if (pChildWnd
!= NULL
) {
406 SetFocus(pChildWnd
->nFocusPanel
? pChildWnd
->hListWnd
: pChildWnd
->hTreeWnd
);
414 if ((int)wParam
== TREE_WINDOW
) {
415 switch (((LPNMHDR
)lParam
)->code
) {
416 case TVN_ITEMEXPANDING
:
417 return !OnTreeExpanding(pChildWnd
->hTreeWnd
, (NMTREEVIEW
*)lParam
);
418 case TVN_SELCHANGED
: {
419 LPCTSTR keyPath
, rootName
;
423 keyPath
= GetItemPath(pChildWnd
->hTreeWnd
, ((NMTREEVIEW
*)lParam
)->itemNew
.hItem
, &hRootKey
);
425 RefreshListView(pChildWnd
->hListWnd
, hRootKey
, keyPath
);
426 rootName
= get_root_key_name(hRootKey
);
427 fullPath
= HeapAlloc(GetProcessHeap(), 0, (_tcslen(rootName
) + 1 + _tcslen(keyPath
) + 1) * sizeof(TCHAR
));
429 _stprintf(fullPath
, _T("%s\\%s"), rootName
, keyPath
);
430 SendMessage(hStatusBar
, SB_SETTEXT
, 0, (LPARAM
)fullPath
);
431 HeapFree(GetProcessHeap(), 0, fullPath
);
435 TCHAR szBuffer
[MAX_PATH
];
436 _sntprintf(szBuffer
, sizeof(szBuffer
) / sizeof(szBuffer
[0]), _T("My Computer\\%s\\%s"), rootName
, keyPath
);
438 if (RegOpenKey(HKEY_CURRENT_USER
,
439 _T("Software\\Microsoft\\Windows\\CurrentVersion\\Applets\\Regedit"),
440 &hKey
) == ERROR_SUCCESS
)
442 RegSetValueEx(hKey
, _T("LastKey"), 0, REG_SZ
, (LPBYTE
) szBuffer
, _tcslen(szBuffer
) * sizeof(szBuffer
[0]));
451 pChildWnd
->nFocusPanel
= 0;
453 case TVN_ENDLABELEDIT
:
457 LPNMTVDISPINFO ptvdi
;
460 ptvdi
= (LPNMTVDISPINFO
) lParam
;
461 if (ptvdi
->item
.pszText
)
463 keyPath
= GetItemPath(pChildWnd
->hTreeWnd
, ptvdi
->item
.hItem
, &hRootKey
);
464 lResult
= RegRenameKey(hRootKey
, keyPath
, ptvdi
->item
.pszText
);
465 return lResult
== ERROR_SUCCESS
;
473 if ((int)wParam
== LIST_WINDOW
)
475 switch (((LPNMHDR
)lParam
)->code
) {
477 pChildWnd
->nFocusPanel
= 1;
480 if(!ListWndNotifyProc(pChildWnd
->hListWnd
, wParam
, lParam
, &Result
))
494 if((HWND
)wParam
== pChildWnd
->hListWnd
)
498 pt
= MAKEPOINTS(lParam
);
499 cnt
= ListView_GetSelectedCount(pChildWnd
->hListWnd
);
500 i
= ListView_GetNextItem(pChildWnd
->hListWnd
, -1, LVNI_FOCUSED
| LVNI_SELECTED
);
503 TrackPopupMenu(GetSubMenu(hPopupMenus
, PM_NEW
), TPM_RIGHTBUTTON
, pt
.x
, pt
.y
, 0, hFrameWnd
, NULL
);
507 HMENU mnu
= GetSubMenu(hPopupMenus
, PM_MODIFYVALUE
);
508 SetMenuDefaultItem(mnu
, ID_EDIT_MODIFY
, MF_BYCOMMAND
);
509 IsDefault
= IsDefaultValue(pChildWnd
->hListWnd
, i
);
511 EnableMenuItem(mnu
, ID_EDIT_RENAME
, MF_BYCOMMAND
| (IsDefault
? MF_DISABLED
| MF_GRAYED
: MF_ENABLED
));
513 EnableMenuItem(mnu
, ID_EDIT_RENAME
, MF_BYCOMMAND
| MF_DISABLED
| MF_GRAYED
);
514 EnableMenuItem(mnu
, ID_EDIT_MODIFY
, MF_BYCOMMAND
| (cnt
== 1 ? MF_ENABLED
: MF_DISABLED
| MF_GRAYED
));
515 EnableMenuItem(mnu
, ID_EDIT_MODIFY_BIN
, MF_BYCOMMAND
| (cnt
== 1 ? MF_ENABLED
: MF_DISABLED
| MF_GRAYED
));
517 TrackPopupMenu(mnu
, TPM_RIGHTBUTTON
, pt
.x
, pt
.y
, 0, hFrameWnd
, NULL
);
520 else if ((HWND
)wParam
== pChildWnd
->hTreeWnd
)
534 pt
= MAKEPOINTS(lParam
);
537 ScreenToClient(pChildWnd
->hTreeWnd
, &hti
.pt
);
538 TreeView_HitTest(pChildWnd
->hTreeWnd
, &hti
);
540 if ((hti
.flags
& TVHT_ONITEM
) != 0)
542 hContextMenu
= GetSubMenu(hPopupMenus
, PM_TREECONTEXT
);
543 TreeView_SelectItem(pChildWnd
->hTreeWnd
, hti
.hItem
);
545 memset(&item
, 0, sizeof(item
));
546 item
.mask
= TVIF_STATE
| TVIF_CHILDREN
;
547 item
.hItem
= hti
.hItem
;
548 TreeView_GetItem(pChildWnd
->hTreeWnd
, &item
);
550 /* Set the Expand/Collapse menu item appropriately */
551 LoadString(hInst
, (item
.state
& TVIS_EXPANDED
) ? IDS_COLLAPSE
: IDS_EXPAND
, buffer
, sizeof(buffer
) / sizeof(buffer
[0]));
552 memset(&mii
, 0, sizeof(mii
));
553 mii
.cbSize
= sizeof(mii
);
554 mii
.fMask
= MIIM_STRING
| MIIM_STATE
| MIIM_ID
;
555 mii
.fState
= (item
.cChildren
> 0) ? MFS_DEFAULT
: MFS_GRAYED
;
556 mii
.wID
= (item
.state
& TVIS_EXPANDED
) ? ID_TREE_COLLAPSEBRANCH
: ID_TREE_EXPANDBRANCH
;
557 mii
.dwTypeData
= (LPTSTR
) buffer
;
558 SetMenuItemInfo(hContextMenu
, 0, TRUE
, &mii
);
560 /* Remove any existing suggestions */
561 memset(&mii
, 0, sizeof(mii
));
562 mii
.cbSize
= sizeof(mii
);
564 GetMenuItemInfo(hContextMenu
, GetMenuItemCount(hContextMenu
) - 1, TRUE
, &mii
);
565 if ((mii
.wID
>= ID_TREE_SUGGESTION_MIN
) && (mii
.wID
<= ID_TREE_SUGGESTION_MAX
))
569 iLastPos
= GetMenuItemCount(hContextMenu
) - 1;
570 GetMenuItemInfo(hContextMenu
, iLastPos
, TRUE
, &mii
);
571 RemoveMenu(hContextMenu
, iLastPos
, MF_BYPOSITION
);
573 while((mii
.wID
>= ID_TREE_SUGGESTION_MIN
) && (mii
.wID
<= ID_TREE_SUGGESTION_MAX
));
576 /* Come up with suggestions */
577 keyPath
= GetItemPath(pChildWnd
->hTreeWnd
, NULL
, &hRootKey
);
578 SuggestKeys(hRootKey
, keyPath
, Suggestions
, sizeof(Suggestions
) / sizeof(Suggestions
[0]));
581 AppendMenu(hContextMenu
, MF_SEPARATOR
, 0, NULL
);
583 LoadString(hInst
, IDS_GOTO_SUGGESTED_KEY
, resource
, sizeof(resource
) / sizeof(resource
[0]));
586 wID
= ID_TREE_SUGGESTION_MIN
;
587 while(*s
&& (wID
<= ID_TREE_SUGGESTION_MAX
))
589 _sntprintf(buffer
, sizeof(buffer
) / sizeof(buffer
[0]), resource
, s
);
591 memset(&mii
, 0, sizeof(mii
));
592 mii
.cbSize
= sizeof(mii
);
593 mii
.fMask
= MIIM_STRING
| MIIM_ID
;
595 mii
.dwTypeData
= buffer
;
596 InsertMenuItem(hContextMenu
, GetMenuItemCount(hContextMenu
), TRUE
, &mii
);
602 TrackPopupMenu(hContextMenu
, TPM_RIGHTBUTTON
, pt
.x
, pt
.y
, 0, pChildWnd
->hWnd
, NULL
);
609 if (wParam
!= SIZE_MINIMIZED
&& pChildWnd
!= NULL
) {
610 ResizeWnd(pChildWnd
, LOWORD(lParam
), HIWORD(lParam
));
614 return DefWindowProc(hWnd
, message
, wParam
, lParam
);