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 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 = (HTREEITEM)TVI_LAST;
50 tvis.hParent = parent;
54 lenName = sizeof(WCHAR[MAX_LOAD_STRING]);
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 = (LPWSTR)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 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 = (HTREEITEM)TVI_LAST;
217 tvis.hParent = TVI_ROOT;
222 while(*path != '\\' && *path != '\0') path += 1;
228 if(RegOpenKey(HKEY_CLASSES_ROOT, (LPWSTR)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, (LPWSTR)buffer, &hKey) != ERROR_SUCCESS) return;
264 CreateRegRec(hKey, addPlace, (LPWSTR)&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(WCHAR[MAX_LOAD_STRING]);
306 LoadString(globals.hMainInst, IDS_TAB_IMPL,
307 wszBuf, sizeof(WCHAR[MAX_LOAD_STRING]));
308 SendMessage(details.hTab, TCM_INSERTITEM, 1, (LPARAM)&tci);
310 LoadString(globals.hMainInst, IDS_TAB_ACTIV,
311 wszBuf, sizeof(WCHAR[MAX_LOAD_STRING]));
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 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(WCHAR[MAX_LOAD_STRING]);
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(WCHAR[MAX_LOAD_STRING]));
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 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;