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 TCHAR szConfirmTitle
[256];
112 TCHAR szConfirmText
[256];
113 WORD wID
= LOWORD(wParam
);
116 /* Parse the menu selections: */
117 case ID_REGISTRY_EXIT
:
120 case ID_VIEW_REFRESH
:
123 case ID_TREE_EXPANDBRANCH
:
124 TreeView_Expand(pChildWnd
->hTreeWnd
, TreeView_GetSelection(pChildWnd
->hTreeWnd
), TVE_EXPAND
);
126 case ID_TREE_COLLAPSEBRANCH
:
127 TreeView_Expand(pChildWnd
->hTreeWnd
, TreeView_GetSelection(pChildWnd
->hTreeWnd
), TVE_COLLAPSE
);
130 SetFocus(pChildWnd
->hTreeWnd
);
131 TreeView_EditLabel(pChildWnd
->hTreeWnd
, TreeView_GetSelection(pChildWnd
->hTreeWnd
));
134 hSelection
= TreeView_GetSelection(pChildWnd
->hTreeWnd
);
135 keyPath
= GetItemPath(pChildWnd
->hTreeWnd
, hSelection
, &hRootKey
);
137 LoadString(hInst
, IDS_QUERY_DELETE_KEY_CONFIRM
, szConfirmTitle
, sizeof(szConfirmTitle
) / sizeof(szConfirmTitle
[0]));
138 LoadString(hInst
, IDS_QUERY_DELETE_KEY_ONE
, szConfirmText
, sizeof(szConfirmText
) / sizeof(szConfirmText
[0]));
140 if (MessageBox(pChildWnd
->hWnd
, szConfirmText
, szConfirmTitle
, MB_YESNO
) == IDYES
)
142 if (RegDeleteKeyRecursive(hRootKey
, keyPath
) == ERROR_SUCCESS
)
143 TreeView_DeleteItem(pChildWnd
->hTreeWnd
, hSelection
);
146 case ID_EDIT_COPYKEYNAME
:
147 hSelection
= TreeView_GetSelection(pChildWnd
->hTreeWnd
);
148 keyPath
= GetItemPath(pChildWnd
->hTreeWnd
, hSelection
, &hRootKey
);
149 CopyKeyName(hWnd
, hRootKey
, keyPath
);
151 case ID_EDIT_NEW_KEY
:
152 CreateNewKey(pChildWnd
->hTreeWnd
, TreeView_GetSelection(pChildWnd
->hTreeWnd
));
154 case ID_EDIT_NEW_STRINGVALUE
:
155 case ID_EDIT_NEW_BINARYVALUE
:
156 case ID_EDIT_NEW_DWORDVALUE
:
157 SendMessage(hFrameWnd
, WM_COMMAND
, wParam
, lParam
);
159 case ID_SWITCH_PANELS
:
160 pChildWnd
->nFocusPanel
= !pChildWnd
->nFocusPanel
;
161 SetFocus(pChildWnd
->nFocusPanel
? pChildWnd
->hListWnd
: pChildWnd
->hTreeWnd
);
164 if ((wID
>= ID_TREE_SUGGESTION_MIN
) && (wID
<= ID_TREE_SUGGESTION_MAX
))
167 while(wID
> ID_TREE_SUGGESTION_MIN
)
173 SelectNode(pChildWnd
->hTreeWnd
, s
);
181 /*******************************************************************************
186 #define MIN(a,b) ((a < b) ? (a) : (b))
188 static void SuggestKeys(HKEY hRootKey
, LPCTSTR pszKeyPath
, LPTSTR pszSuggestions
,
189 size_t iSuggestionsLength
)
192 TCHAR szLastFound
[256];
194 HKEY hOtherKey
, hSubKey
;
197 memset(pszSuggestions
, 0, iSuggestionsLength
* sizeof(*pszSuggestions
));
198 iSuggestionsLength
--;
200 /* Are we a root key in HKEY_CLASSES_ROOT? */
201 if ((hRootKey
== HKEY_CLASSES_ROOT
) && pszKeyPath
[0] && !_tcschr(pszKeyPath
, '\\'))
207 /* Check default key */
208 if (RegQueryStringValue(hRootKey
, pszKeyPath
, NULL
,
209 szBuffer
, sizeof(szBuffer
) / sizeof(szBuffer
[0])) == ERROR_SUCCESS
)
211 /* Sanity check this key; it cannot be empty, nor can it be a
213 if ((szBuffer
[0] != '\0') && _tcsicmp(szBuffer
, pszKeyPath
))
215 if (RegOpenKey(hRootKey
, szBuffer
, &hOtherKey
) == ERROR_SUCCESS
)
217 lstrcpyn(pszSuggestions
, TEXT("HKCR\\"), iSuggestionsLength
);
218 i
= _tcslen(pszSuggestions
);
220 iSuggestionsLength
-= i
;
222 lstrcpyn(pszSuggestions
, szBuffer
, iSuggestionsLength
);
223 i
= MIN(_tcslen(pszSuggestions
) + 1, iSuggestionsLength
);
225 iSuggestionsLength
-= i
;
226 RegCloseKey(hOtherKey
);
229 _tcscpy(szLastFound
, szBuffer
);
230 pszKeyPath
= szLastFound
;
235 while(bFound
&& (iSuggestionsLength
> 0));
237 /* Check CLSID key */
238 if (RegOpenKey(hRootKey
, pszKeyPath
, &hSubKey
) == ERROR_SUCCESS
)
240 if (RegQueryStringValue(hSubKey
, TEXT("CLSID"), NULL
,
241 szBuffer
, sizeof(szBuffer
) / sizeof(szBuffer
[0])) == ERROR_SUCCESS
)
243 lstrcpyn(pszSuggestions
, TEXT("HKCR\\CLSID\\"), iSuggestionsLength
);
244 i
= _tcslen(pszSuggestions
);
246 iSuggestionsLength
-= i
;
248 lstrcpyn(pszSuggestions
, szBuffer
, iSuggestionsLength
);
249 i
= MIN(_tcslen(pszSuggestions
) + 1, iSuggestionsLength
);
251 iSuggestionsLength
-= i
;
253 RegCloseKey(hSubKey
);
258 /*******************************************************************************
260 * FUNCTION: ChildWndProc(HWND, unsigned, WORD, LONG)
262 * PURPOSE: Processes messages for the child windows.
264 * WM_COMMAND - process the application menu
265 * WM_PAINT - Paint the main window
266 * WM_DESTROY - post a quit message and return
269 LRESULT CALLBACK
ChildWndProc(HWND hWnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
271 static short last_split
;
273 ChildWnd
* pChildWnd
= g_pChildWnd
;
278 TCHAR buffer
[MAX_PATH
];
279 /* load "My Computer" string */
280 LoadString(hInst
, IDS_MY_COMPUTER
, buffer
, sizeof(buffer
)/sizeof(TCHAR
));
282 g_pChildWnd
= pChildWnd
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(ChildWnd
));
284 if (!pChildWnd
) return 0;
285 _tcsncpy(pChildWnd
->szPath
, buffer
, MAX_PATH
);
286 pChildWnd
->nSplitPos
= 250;
287 pChildWnd
->hWnd
= hWnd
;
288 pChildWnd
->hTreeWnd
= CreateTreeView(hWnd
, pChildWnd
->szPath
, TREE_WINDOW
);
289 pChildWnd
->hListWnd
= CreateListView(hWnd
, LIST_WINDOW
/*, pChildWnd->szPath*/);
290 SetFocus(pChildWnd
->hTreeWnd
);
294 if (!_CmdWndProc(hWnd
, message
, wParam
, lParam
)) {
302 if (LOWORD(lParam
) == HTCLIENT
) {
305 ScreenToClient(hWnd
, &pt
);
306 if (pt
.x
>=pChildWnd
->nSplitPos
-SPLIT_WIDTH
/2 && pt
.x
<pChildWnd
->nSplitPos
+SPLIT_WIDTH
/2+1) {
307 SetCursor(LoadCursor(0, IDC_SIZEWE
));
313 HeapFree(GetProcessHeap(), 0, pChildWnd
);
317 case WM_LBUTTONDOWN
: {
320 pt
= MAKEPOINTS(lParam
);
321 GetClientRect(hWnd
, &rt
);
322 if (pt
.x
>=pChildWnd
->nSplitPos
-SPLIT_WIDTH
/2 && pt
.x
<pChildWnd
->nSplitPos
+SPLIT_WIDTH
/2+1) {
323 last_split
= pChildWnd
->nSplitPos
;
324 draw_splitbar(hWnd
, last_split
);
331 if (GetCapture() == hWnd
) {
334 pt
= MAKEPOINTS(lParam
);
335 GetClientRect(hWnd
, &rt
);
336 pt
.x
= (SHORT
) min(max(pt
.x
, SPLIT_MIN
), rt
.right
- SPLIT_MIN
);
337 draw_splitbar(hWnd
, last_split
);
339 pChildWnd
->nSplitPos
= pt
.x
;
340 ResizeWnd(pChildWnd
, rt
.right
, rt
.bottom
);
345 case WM_CAPTURECHANGED
:
346 if (GetCapture()==hWnd
&& last_split
>=0)
347 draw_splitbar(hWnd
, last_split
);
351 if (wParam
== VK_ESCAPE
)
352 if (GetCapture() == hWnd
) {
354 draw_splitbar(hWnd
, last_split
);
355 GetClientRect(hWnd
, &rt
);
356 ResizeWnd(pChildWnd
, rt
.right
, rt
.bottom
);
359 SetCursor(LoadCursor(0, IDC_ARROW
));
364 if (GetCapture() == hWnd
) {
371 const DWORD Pattern
[4] = {0x5555AAAA, 0x5555AAAA, 0x5555AAAA, 0x5555AAAA};
372 SizingPattern
= CreateBitmap(8, 8, 1, 1, Pattern
);
376 SizingBrush
= CreatePatternBrush(SizingPattern
);
379 pt
= MAKEPOINTS(lParam
);
380 GetClientRect(hWnd
, &rt
);
381 pt
.x
= (SHORT
) min(max(pt
.x
, SPLIT_MIN
), rt
.right
- SPLIT_MIN
);
382 if(last_split
!= pt
.x
)
384 rt
.left
= last_split
-SPLIT_WIDTH
/2;
385 rt
.right
= last_split
+SPLIT_WIDTH
/2+1;
387 OldObj
= SelectObject(hdc
, SizingBrush
);
388 PatBlt(hdc
, rt
.left
, rt
.top
, rt
.right
- rt
.left
, rt
.bottom
- rt
.top
, PATINVERT
);
390 rt
.left
= pt
.x
-SPLIT_WIDTH
/2;
391 rt
.right
= pt
.x
+SPLIT_WIDTH
/2+1;
392 PatBlt(hdc
, rt
.left
, rt
.top
, rt
.right
- rt
.left
, rt
.bottom
- rt
.top
, PATINVERT
);
393 SelectObject(hdc
, OldObj
);
394 ReleaseDC(hWnd
, hdc
);
400 if (pChildWnd
!= NULL
) {
401 SetFocus(pChildWnd
->nFocusPanel
? pChildWnd
->hListWnd
: pChildWnd
->hTreeWnd
);
409 if ((int)wParam
== TREE_WINDOW
) {
410 switch (((LPNMHDR
)lParam
)->code
) {
411 case TVN_ITEMEXPANDING
:
412 return !OnTreeExpanding(pChildWnd
->hTreeWnd
, (NMTREEVIEW
*)lParam
);
413 case TVN_SELCHANGED
: {
414 LPCTSTR keyPath
, rootName
;
418 keyPath
= GetItemPath(pChildWnd
->hTreeWnd
, ((NMTREEVIEW
*)lParam
)->itemNew
.hItem
, &hRootKey
);
420 RefreshListView(pChildWnd
->hListWnd
, hRootKey
, keyPath
);
421 rootName
= get_root_key_name(hRootKey
);
422 fullPath
= HeapAlloc(GetProcessHeap(), 0, (_tcslen(rootName
) + 1 + _tcslen(keyPath
) + 1) * sizeof(TCHAR
));
424 _stprintf(fullPath
, _T("%s\\%s"), rootName
, keyPath
);
425 SendMessage(hStatusBar
, SB_SETTEXT
, 0, (LPARAM
)fullPath
);
426 HeapFree(GetProcessHeap(), 0, fullPath
);
430 TCHAR szBuffer
[MAX_PATH
];
431 _sntprintf(szBuffer
, sizeof(szBuffer
) / sizeof(szBuffer
[0]), _T("My Computer\\%s\\%s"), rootName
, keyPath
);
433 if (RegOpenKey(HKEY_CURRENT_USER
,
434 _T("Software\\Microsoft\\Windows\\CurrentVersion\\Applets\\Regedit"),
435 &hKey
) == ERROR_SUCCESS
)
437 RegSetValueEx(hKey
, _T("LastKey"), 0, REG_SZ
, (LPBYTE
) szBuffer
, _tcslen(szBuffer
) * sizeof(szBuffer
[0]));
446 pChildWnd
->nFocusPanel
= 0;
448 case TVN_ENDLABELEDIT
:
452 LPNMTVDISPINFO ptvdi
;
455 ptvdi
= (LPNMTVDISPINFO
) lParam
;
456 if (ptvdi
->item
.pszText
)
458 keyPath
= GetItemPath(pChildWnd
->hTreeWnd
, ptvdi
->item
.hItem
, &hRootKey
);
459 lResult
= RegRenameKey(hRootKey
, keyPath
, ptvdi
->item
.pszText
);
460 return lResult
== ERROR_SUCCESS
;
468 if ((int)wParam
== LIST_WINDOW
)
470 switch (((LPNMHDR
)lParam
)->code
) {
472 pChildWnd
->nFocusPanel
= 1;
475 if(!ListWndNotifyProc(pChildWnd
->hListWnd
, wParam
, lParam
, &Result
))
489 if((HWND
)wParam
== pChildWnd
->hListWnd
)
493 pt
= MAKEPOINTS(lParam
);
494 cnt
= ListView_GetSelectedCount(pChildWnd
->hListWnd
);
495 i
= ListView_GetNextItem(pChildWnd
->hListWnd
, -1, LVNI_FOCUSED
| LVNI_SELECTED
);
498 TrackPopupMenu(GetSubMenu(hPopupMenus
, PM_NEW
), TPM_RIGHTBUTTON
, pt
.x
, pt
.y
, 0, hFrameWnd
, NULL
);
502 HMENU mnu
= GetSubMenu(hPopupMenus
, PM_MODIFYVALUE
);
503 SetMenuDefaultItem(mnu
, ID_EDIT_MODIFY
, MF_BYCOMMAND
);
504 IsDefault
= IsDefaultValue(pChildWnd
->hListWnd
, i
);
506 EnableMenuItem(mnu
, ID_EDIT_RENAME
, MF_BYCOMMAND
| (IsDefault
? MF_DISABLED
| MF_GRAYED
: MF_ENABLED
));
508 EnableMenuItem(mnu
, ID_EDIT_RENAME
, MF_BYCOMMAND
| MF_DISABLED
| MF_GRAYED
);
509 EnableMenuItem(mnu
, ID_EDIT_MODIFY
, MF_BYCOMMAND
| (cnt
== 1 ? MF_ENABLED
: MF_DISABLED
| MF_GRAYED
));
510 EnableMenuItem(mnu
, ID_EDIT_MODIFY_BIN
, MF_BYCOMMAND
| (cnt
== 1 ? MF_ENABLED
: MF_DISABLED
| MF_GRAYED
));
512 TrackPopupMenu(mnu
, TPM_RIGHTBUTTON
, pt
.x
, pt
.y
, 0, hFrameWnd
, NULL
);
515 else if ((HWND
)wParam
== pChildWnd
->hTreeWnd
)
529 pt
= MAKEPOINTS(lParam
);
532 ScreenToClient(pChildWnd
->hTreeWnd
, &hti
.pt
);
533 TreeView_HitTest(pChildWnd
->hTreeWnd
, &hti
);
535 if ((hti
.flags
& TVHT_ONITEM
) != 0)
537 hContextMenu
= GetSubMenu(hPopupMenus
, PM_TREECONTEXT
);
538 TreeView_SelectItem(pChildWnd
->hTreeWnd
, hti
.hItem
);
540 memset(&item
, 0, sizeof(item
));
541 item
.mask
= TVIF_STATE
| TVIF_CHILDREN
;
542 item
.hItem
= hti
.hItem
;
543 TreeView_GetItem(pChildWnd
->hTreeWnd
, &item
);
545 /* Set the Expand/Collapse menu item appropriately */
546 LoadString(hInst
, (item
.state
& TVIS_EXPANDED
) ? IDS_COLLAPSE
: IDS_EXPAND
, buffer
, sizeof(buffer
) / sizeof(buffer
[0]));
547 memset(&mii
, 0, sizeof(mii
));
548 mii
.cbSize
= sizeof(mii
);
549 mii
.fMask
= MIIM_STRING
| MIIM_STATE
| MIIM_ID
;
550 mii
.fState
= (item
.cChildren
> 0) ? MFS_DEFAULT
: MFS_GRAYED
;
551 mii
.wID
= (item
.state
& TVIS_EXPANDED
) ? ID_TREE_COLLAPSEBRANCH
: ID_TREE_EXPANDBRANCH
;
552 mii
.dwTypeData
= (LPTSTR
) buffer
;
553 SetMenuItemInfo(hContextMenu
, 0, TRUE
, &mii
);
555 /* Remove any existing suggestions */
556 memset(&mii
, 0, sizeof(mii
));
557 mii
.cbSize
= sizeof(mii
);
559 GetMenuItemInfo(hContextMenu
, GetMenuItemCount(hContextMenu
) - 1, TRUE
, &mii
);
560 if ((mii
.wID
>= ID_TREE_SUGGESTION_MIN
) && (mii
.wID
<= ID_TREE_SUGGESTION_MAX
))
564 iLastPos
= GetMenuItemCount(hContextMenu
) - 1;
565 GetMenuItemInfo(hContextMenu
, iLastPos
, TRUE
, &mii
);
566 RemoveMenu(hContextMenu
, iLastPos
, MF_BYPOSITION
);
568 while((mii
.wID
>= ID_TREE_SUGGESTION_MIN
) && (mii
.wID
<= ID_TREE_SUGGESTION_MAX
));
571 /* Come up with suggestions */
572 keyPath
= GetItemPath(pChildWnd
->hTreeWnd
, NULL
, &hRootKey
);
573 SuggestKeys(hRootKey
, keyPath
, Suggestions
, sizeof(Suggestions
) / sizeof(Suggestions
[0]));
576 AppendMenu(hContextMenu
, MF_SEPARATOR
, 0, NULL
);
578 LoadString(hInst
, IDS_GOTO_SUGGESTED_KEY
, resource
, sizeof(resource
) / sizeof(resource
[0]));
581 wID
= ID_TREE_SUGGESTION_MIN
;
582 while(*s
&& (wID
<= ID_TREE_SUGGESTION_MAX
))
584 _sntprintf(buffer
, sizeof(buffer
) / sizeof(buffer
[0]), resource
, s
);
586 memset(&mii
, 0, sizeof(mii
));
587 mii
.cbSize
= sizeof(mii
);
588 mii
.fMask
= MIIM_STRING
| MIIM_ID
;
590 mii
.dwTypeData
= buffer
;
591 InsertMenuItem(hContextMenu
, GetMenuItemCount(hContextMenu
), TRUE
, &mii
);
597 TrackPopupMenu(hContextMenu
, TPM_RIGHTBUTTON
, pt
.x
, pt
.y
, 0, pChildWnd
->hWnd
, NULL
);
604 if (wParam
!= SIZE_MINIMIZED
&& pChildWnd
!= NULL
) {
605 ResizeWnd(pChildWnd
, LOWORD(lParam
), HIWORD(lParam
));
609 return DefWindowProc(hWnd
, message
, wParam
, lParam
);