4 * Copyright 2006 Piotr Caban
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 static const WCHAR wszAppID
[] = { 'A','p','p','I','D','\0' };
25 static const WCHAR wszCLSID
[] = { 'C','L','S','I','D','\0' };
26 static const WCHAR wszProgID
[] = { 'P','r','o','g','I','D','\0' };
27 static const WCHAR wszProxyStubClsid32
[] =
28 { 'P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2','\0' };
29 static const WCHAR wszTypeLib
[] = { 'T','y','p','e','L','i','b','\0' };
31 static void CreateRegRec(HKEY hKey
, HTREEITEM parent
, WCHAR
*wszKeyName
, BOOL addings
)
35 DWORD lenName
, lenData
, valType
;
36 WCHAR wszName
[MAX_LOAD_STRING
];
37 WCHAR wszData
[MAX_LOAD_STRING
];
38 WCHAR wszTree
[MAX_LOAD_STRING
];
39 const WCHAR wszBinary
[] = { '%','0','2','X',' ','\0' };
40 const WCHAR wszDots
[] = { '.','.','.','\0' };
41 const WCHAR wszFormat1
[] = { '%','s',' ','[','%','s',']',' ','=',' ','%','s','\0' };
42 const WCHAR wszFormat2
[] = { '%','s',' ','=',' ','%','s','\0' };
44 HTREEITEM addPlace
= parent
;
46 U(tvis
).item
.mask
= TVIF_TEXT
;
47 U(tvis
).item
.cchTextMax
= MAX_LOAD_STRING
;
48 U(tvis
).item
.pszText
= wszTree
;
49 tvis
.hInsertAfter
= TVI_LAST
;
50 tvis
.hParent
= parent
;
54 lenName
= sizeof(WCHAR
[MAX_LOAD_STRING
])/sizeof(WCHAR
);
55 lenData
= sizeof(WCHAR
[MAX_LOAD_STRING
]);
57 retEnum
= RegEnumValue(hKey
, i
, wszName
, &lenName
,
58 NULL
, &valType
, (LPBYTE
)wszData
, &lenData
);
60 if(retEnum
!= ERROR_SUCCESS
)
62 if(!i
&& lstrlenW(wszKeyName
) > 1)
64 U(tvis
).item
.pszText
= wszKeyName
;
65 addPlace
= TreeView_InsertItem(details
.hReg
, &tvis
);
66 U(tvis
).item
.pszText
= wszTree
;
71 if(valType
== REG_BINARY
)
73 WCHAR wszBuf
[MAX_LOAD_STRING
];
75 for(j
=0; j
<MAX_LOAD_STRING
/3-1; j
++)
76 wsprintfW(&wszBuf
[3*j
], wszBinary
, (int)((unsigned char)wszData
[j
]));
77 wszBuf
[(lenData
*3>=MAX_LOAD_STRING
? MAX_LOAD_STRING
-1 : lenData
*3)] = '\0';
78 lstrcpyW(wszData
, wszBuf
);
79 lstrcpyW(&wszData
[MAX_LOAD_STRING
-5], wszDots
);
82 if(lenName
) wsprintfW(wszTree
, wszFormat1
, wszKeyName
, wszName
, wszData
);
83 else wsprintfW(wszTree
, wszFormat2
, wszKeyName
, wszData
);
85 addPlace
= TreeView_InsertItem(details
.hReg
, &tvis
);
87 if(addings
&& !memcmp(wszName
, wszAppID
, sizeof(WCHAR
[6])))
89 lstrcpyW(wszTree
, wszName
);
90 memmove(&wszData
[6], wszData
, sizeof(WCHAR
[MAX_LOAD_STRING
-6]));
91 lstrcpyW(wszData
, wszCLSID
);
94 if(RegOpenKey(HKEY_CLASSES_ROOT
, wszData
, &hCurKey
) != ERROR_SUCCESS
)
100 tvis
.hParent
= TVI_ROOT
;
101 tvis
.hParent
= TreeView_InsertItem(details
.hReg
, &tvis
);
103 lenName
= sizeof(WCHAR
[MAX_LOAD_STRING
]);
105 RegQueryValue(hCurKey
, NULL
, wszName
, (LONG
*)&lenName
);
106 RegCloseKey(hCurKey
);
108 wsprintfW(wszTree
, wszFormat2
, &wszData
[6], wszName
);
110 SendMessage(details
.hReg
, TVM_INSERTITEM
, 0, (LPARAM
)&tvis
);
111 SendMessage(details
.hReg
, TVM_EXPAND
, TVE_EXPAND
, (LPARAM
)tvis
.hParent
);
113 tvis
.hParent
= parent
;
119 lenName
= sizeof(WCHAR
[MAX_LOAD_STRING
]);
125 if(RegEnumKey(hKey
, i
, wszName
, lenName
) != ERROR_SUCCESS
) break;
127 if(RegOpenKey(hKey
, wszName
, &hCurKey
) != ERROR_SUCCESS
) continue;
129 CreateRegRec(hCurKey
, addPlace
, wszName
, addings
);
130 SendMessage(details
.hReg
, TVM_EXPAND
, TVE_EXPAND
, (LPARAM
)addPlace
);
132 if(addings
&& !memcmp(wszName
, wszProgID
, sizeof(WCHAR
[7])))
134 lenData
= sizeof(WCHAR
[MAX_LOAD_STRING
]);
136 RegQueryValue(hCurKey
, NULL
, wszData
, (LONG
*)&lenData
);
137 RegCloseKey(hCurKey
);
139 if(RegOpenKey(HKEY_CLASSES_ROOT
, wszData
, &hCurKey
) != ERROR_SUCCESS
)
141 CreateRegRec(hCurKey
, TVI_ROOT
, wszData
, FALSE
);
143 else if(addings
&& !memcmp(wszName
, wszProxyStubClsid32
, sizeof(WCHAR
[17])))
145 lenData
= sizeof(WCHAR
[MAX_LOAD_STRING
]);
147 RegQueryValue(hCurKey
, NULL
, wszData
, (LONG
*)&lenData
);
148 RegCloseKey(hCurKey
);
150 RegOpenKey(HKEY_CLASSES_ROOT
, wszCLSID
, &hCurKey
);
152 lenName
= sizeof(WCHAR
[MAX_LOAD_STRING
]);
153 RegQueryValue(hCurKey
, NULL
, wszName
, (LONG
*)&lenName
);
155 tvis
.hParent
= TVI_ROOT
;
156 wsprintfW(wszTree
, wszFormat2
, wszCLSID
, wszName
);
157 tvis
.hParent
= TreeView_InsertItem(details
.hReg
, &tvis
);
159 RegCloseKey(hCurKey
);
161 memmove(&wszData
[6], wszData
, sizeof(WCHAR
[lenData
]));
162 memcpy(wszData
, wszCLSID
, sizeof(WCHAR
[6]));
165 RegOpenKey(HKEY_CLASSES_ROOT
, wszData
, &hCurKey
);
167 CreateRegRec(hCurKey
, tvis
.hParent
, &wszData
[6], FALSE
);
169 SendMessage(details
.hReg
, TVM_EXPAND
, TVE_EXPAND
, (LPARAM
)tvis
.hParent
);
170 tvis
.hParent
= parent
;
172 else if(addings
&& !memcmp(wszName
, wszTypeLib
, sizeof(WCHAR
[8])))
174 lenData
= sizeof(WCHAR
[MAX_LOAD_STRING
]);
176 RegQueryValue(hCurKey
, NULL
, wszData
, (LONG
*)&lenData
);
177 RegCloseKey(hCurKey
);
179 RegOpenKey(HKEY_CLASSES_ROOT
, wszTypeLib
, &hCurKey
);
181 lenName
= sizeof(WCHAR
[MAX_LOAD_STRING
]);
182 RegQueryValue(hCurKey
, NULL
, wszName
, (LONG
*)&lenName
);
184 tvis
.hParent
= TVI_ROOT
;
185 wsprintfW(wszTree
, wszFormat2
, wszTypeLib
, wszName
);
186 tvis
.hParent
= TreeView_InsertItem(details
.hReg
, &tvis
);
188 RegCloseKey(hCurKey
);
190 memmove(&wszData
[8], wszData
, sizeof(WCHAR
[lenData
]));
191 memcpy(wszData
, wszTypeLib
, sizeof(WCHAR
[8]));
193 RegOpenKey(HKEY_CLASSES_ROOT
, wszData
, &hCurKey
);
195 CreateRegRec(hCurKey
, tvis
.hParent
, &wszData
[8], FALSE
);
197 SendMessage(details
.hReg
, TVM_EXPAND
, TVE_EXPAND
, (LPARAM
)tvis
.hParent
);
198 tvis
.hParent
= parent
;
200 RegCloseKey(hCurKey
);
204 static void CreateReg(WCHAR
*buffer
)
207 DWORD lenBuffer
=-1, lastLenBuffer
, lenTree
;
209 WCHAR wszTree
[MAX_LOAD_STRING
];
211 HTREEITEM addPlace
= TVI_ROOT
;
213 U(tvis
).item
.mask
= TVIF_TEXT
;
214 U(tvis
).item
.cchTextMax
= MAX_LOAD_STRING
;
215 U(tvis
).item
.pszText
= wszTree
;
216 tvis
.hInsertAfter
= TVI_LAST
;
217 tvis
.hParent
= TVI_ROOT
;
222 while(*path
!= '\\' && *path
!= '\0') path
+= 1;
228 if(RegOpenKey(HKEY_CLASSES_ROOT
, buffer
, &hKey
) != ERROR_SUCCESS
)
231 lastLenBuffer
= lenBuffer
+1;
232 lenBuffer
= lstrlenW(buffer
);
236 lenTree
= sizeof(WCHAR
[MAX_LOAD_STRING
]);
238 if(RegQueryValue(hKey
, NULL
, wszTree
, (LONG
*)&lenTree
) == ERROR_SUCCESS
)
240 memmove(&wszTree
[lenBuffer
-lastLenBuffer
+3], wszTree
,
241 sizeof(WCHAR
[lenTree
]));
242 memcpy(wszTree
, &buffer
[lastLenBuffer
],
243 sizeof(WCHAR
[lenBuffer
-lastLenBuffer
]));
245 if(lenTree
== 1) wszTree
[lenBuffer
-lastLenBuffer
] = '\0';
248 wszTree
[lenBuffer
-lastLenBuffer
] = ' ';
249 wszTree
[lenBuffer
-lastLenBuffer
+1] = '=';
250 wszTree
[lenBuffer
-lastLenBuffer
+2] = ' ';
253 addPlace
= TreeView_InsertItem(details
.hReg
, &tvis
);
256 tvis
.hParent
= addPlace
;
262 if(RegOpenKey(HKEY_CLASSES_ROOT
, buffer
, &hKey
) != ERROR_SUCCESS
) return;
264 CreateRegRec(hKey
, addPlace
, &buffer
[lenBuffer
+1], TRUE
);
268 SendMessage(details
.hReg
, TVM_EXPAND
, TVE_EXPAND
, (LPARAM
)addPlace
);
269 SendMessage(details
.hReg
, TVM_ENSUREVISIBLE
, 0, (LPARAM
)addPlace
);
272 void RefreshDetails(HTREEITEM item
)
275 WCHAR wszBuf
[MAX_LOAD_STRING
];
276 WCHAR wszStaticText
[MAX_LOAD_STRING
];
277 const WCHAR wszFormat
[] = { '%','s','\n','%','s','\0' };
280 memset(&tvi
, 0, sizeof(TVITEM
));
281 memset(&wszStaticText
, 0, sizeof(WCHAR
[MAX_LOAD_STRING
]));
282 tvi
.mask
= TVIF_TEXT
;
284 tvi
.pszText
= wszBuf
;
285 tvi
.cchTextMax
= MAX_LOAD_STRING
;
286 SendMessage(globals
.hTree
, TVM_GETITEM
, 0, (LPARAM
)&tvi
);
289 wsprintfW(wszStaticText
, wszFormat
, tvi
.pszText
, ((ITEM_INFO
*)tvi
.lParam
)->clsid
);
290 else lstrcpyW(wszStaticText
, tvi
.pszText
);
292 SetWindowText(details
.hStatic
, wszStaticText
);
294 SendMessage(details
.hTab
, TCM_SETCURSEL
, 0, 0);
296 if(tvi
.lParam
&& ((ITEM_INFO
*)tvi
.lParam
)->cFlag
& SHOWALL
)
298 if(TabCtrl_GetItemCount(details
.hTab
) == 1)
301 memset(&tci
, 0, sizeof(TCITEM
));
302 tci
.mask
= TCIF_TEXT
;
303 tci
.pszText
= wszBuf
;
304 tci
.cchTextMax
= sizeof(wszBuf
)/sizeof(wszBuf
[0]);
306 LoadString(globals
.hMainInst
, IDS_TAB_IMPL
,
307 wszBuf
, sizeof(wszBuf
)/sizeof(wszBuf
[0]));
308 SendMessage(details
.hTab
, TCM_INSERTITEM
, 1, (LPARAM
)&tci
);
310 LoadString(globals
.hMainInst
, IDS_TAB_ACTIV
,
311 wszBuf
, sizeof(wszBuf
)/sizeof(wszBuf
[0]));
312 SendMessage(details
.hTab
, TCM_INSERTITEM
, 2, (LPARAM
)&tci
);
317 SendMessage(details
.hTab
, TCM_DELETEITEM
, 2, 0);
318 SendMessage(details
.hTab
, TCM_DELETEITEM
, 1, 0);
321 show
= CreateRegPath(item
, wszBuf
, MAX_LOAD_STRING
);
322 ShowWindow(details
.hTab
, show
? SW_SHOW
: SW_HIDE
);
324 /* FIXME Next line deals with TreeView_EnsureVisible bug */
325 SendMessage(details
.hReg
, TVM_ENSUREVISIBLE
, 0,
326 SendMessage(details
.hReg
, TVM_GETNEXTITEM
, TVGN_CHILD
, (LPARAM
)TVI_ROOT
));
327 SendMessage(details
.hReg
, TVM_DELETEITEM
, 0, (LPARAM
)TVI_ROOT
);
328 if(show
) CreateReg(wszBuf
);
331 static void CreateTabCtrl(HWND hWnd
)
334 WCHAR buffer
[MAX_LOAD_STRING
];
336 memset(&tci
, 0, sizeof(TCITEM
));
337 tci
.mask
= TCIF_TEXT
;
338 tci
.pszText
= buffer
;
339 tci
.cchTextMax
= sizeof(buffer
)/sizeof(buffer
[0]);
341 details
.hTab
= CreateWindow(WC_TABCONTROL
, NULL
, WS_CHILD
|WS_VISIBLE
,
342 0, 0, 0, 0, hWnd
, (HMENU
)TAB_WINDOW
, globals
.hMainInst
, NULL
);
343 ShowWindow(details
.hTab
, SW_HIDE
);
345 LoadString(globals
.hMainInst
, IDS_TAB_REG
, buffer
, sizeof(buffer
)/sizeof(buffer
[0]));
346 SendMessage(details
.hTab
, TCM_INSERTITEM
, 0, (LPARAM
)&tci
);
348 details
.hReg
= CreateWindowEx(WS_EX_CLIENTEDGE
, WC_TREEVIEW
, NULL
,
349 WS_CHILD
|WS_VISIBLE
|TVS_HASLINES
,
350 0, 0, 0, 0, details
.hTab
, NULL
, globals
.hMainInst
, NULL
);
353 static LRESULT CALLBACK
DetailsProc(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
361 const WCHAR wszStatic
[] = { 'S','t','a','t','i','c','\0' };
363 details
.hStatic
= CreateWindow(wszStatic
, NULL
, WS_CHILD
|WS_VISIBLE
,
364 0, 0, 0, 0, hWnd
, NULL
, globals
.hMainInst
, NULL
);
369 MoveWindow(details
.hStatic
, 0, 0, LOWORD(lParam
), 40, TRUE
);
370 MoveWindow(details
.hTab
, 3, 40, LOWORD(lParam
)-6, HIWORD(lParam
)-43, TRUE
);
371 MoveWindow(details
.hReg
, 10, 34, LOWORD(lParam
)-26,
372 HIWORD(lParam
)-87, TRUE
);
375 if((int)wParam
!= TAB_WINDOW
) break;
376 switch(((LPNMHDR
)lParam
)->code
)
379 ShowWindow(details
.hReg
, SW_HIDE
);
380 sel
= TabCtrl_GetCurSel(details
.hTab
);
382 if(sel
==0) ShowWindow(details
.hReg
, SW_SHOW
);
387 return DefWindowProc(hWnd
, uMsg
, wParam
, lParam
);
392 HWND
CreateDetailsWindow(HINSTANCE hInst
)
395 const WCHAR wszDetailsClass
[] = { 'D','E','T','A','I','L','S','\0' };
397 memset(&wcd
, 0, sizeof(WNDCLASS
));
398 wcd
.lpfnWndProc
= DetailsProc
;
399 wcd
.lpszClassName
= wszDetailsClass
;
400 wcd
.hbrBackground
= (HBRUSH
)COLOR_WINDOW
;
402 if(!RegisterClass(&wcd
)) return NULL
;
404 globals
.hDetails
= CreateWindowEx(WS_EX_CLIENTEDGE
, wszDetailsClass
, NULL
,
405 WS_CHILD
|WS_VISIBLE
, 0, 0, 0, 0, globals
.hPaneWnd
, NULL
, hInst
, NULL
);
407 return globals
.hDetails
;