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(wszName
)/sizeof(WCHAR
);
55 lenData
= sizeof(wszData
);
57 retEnum
= RegEnumValueW(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_InsertItemW(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_InsertItemW(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(RegOpenKeyW(HKEY_CLASSES_ROOT
, wszData
, &hCurKey
) != ERROR_SUCCESS
)
100 tvis
.hParent
= TVI_ROOT
;
101 tvis
.hParent
= TreeView_InsertItemW(details
.hReg
, &tvis
);
103 lenName
= sizeof(wszName
);
104 RegQueryValueW(hCurKey
, NULL
, wszName
, (LONG
*)&lenName
);
105 RegCloseKey(hCurKey
);
107 wsprintfW(wszTree
, wszFormat2
, &wszData
[6], wszName
);
109 SendMessageW(details
.hReg
, TVM_INSERTITEMW
, 0, (LPARAM
)&tvis
);
110 SendMessageW(details
.hReg
, TVM_EXPAND
, TVE_EXPAND
, (LPARAM
)tvis
.hParent
);
112 tvis
.hParent
= parent
;
123 if(RegEnumKeyW(hKey
, i
, wszName
, sizeof(wszName
)/sizeof(WCHAR
)) != ERROR_SUCCESS
) break;
125 if(RegOpenKeyW(hKey
, wszName
, &hCurKey
) != ERROR_SUCCESS
) continue;
127 CreateRegRec(hCurKey
, addPlace
, wszName
, addings
);
128 SendMessageW(details
.hReg
, TVM_EXPAND
, TVE_EXPAND
, (LPARAM
)addPlace
);
130 if(addings
&& !memcmp(wszName
, wszProgID
, sizeof(WCHAR
[7])))
132 lenData
= sizeof(wszData
);
133 RegQueryValueW(hCurKey
, NULL
, wszData
, (LONG
*)&lenData
);
134 RegCloseKey(hCurKey
);
136 if(RegOpenKeyW(HKEY_CLASSES_ROOT
, wszData
, &hCurKey
) != ERROR_SUCCESS
)
138 CreateRegRec(hCurKey
, TVI_ROOT
, wszData
, FALSE
);
140 else if(addings
&& !memcmp(wszName
, wszProxyStubClsid32
, sizeof(WCHAR
[17])))
142 lenData
= sizeof(WCHAR
[MAX_LOAD_STRING
]);
144 RegQueryValueW(hCurKey
, NULL
, wszData
, (LONG
*)&lenData
);
145 RegCloseKey(hCurKey
);
147 RegOpenKeyW(HKEY_CLASSES_ROOT
, wszCLSID
, &hCurKey
);
149 lenName
= sizeof(wszName
);
150 RegQueryValueW(hCurKey
, NULL
, wszName
, (LONG
*)&lenName
);
152 tvis
.hParent
= TVI_ROOT
;
153 wsprintfW(wszTree
, wszFormat2
, wszCLSID
, wszName
);
154 tvis
.hParent
= TreeView_InsertItemW(details
.hReg
, &tvis
);
156 RegCloseKey(hCurKey
);
158 memmove(&wszData
[6], wszData
, lenData
* sizeof(WCHAR
));
159 memcpy(wszData
, wszCLSID
, sizeof(WCHAR
[6]));
162 RegOpenKeyW(HKEY_CLASSES_ROOT
, wszData
, &hCurKey
);
164 CreateRegRec(hCurKey
, tvis
.hParent
, &wszData
[6], FALSE
);
166 SendMessageW(details
.hReg
, TVM_EXPAND
, TVE_EXPAND
, (LPARAM
)tvis
.hParent
);
167 tvis
.hParent
= parent
;
169 else if(addings
&& !memcmp(wszName
, wszTypeLib
, sizeof(WCHAR
[8])))
171 lenData
= sizeof(wszData
);
172 RegQueryValueW(hCurKey
, NULL
, wszData
, (LONG
*)&lenData
);
173 RegCloseKey(hCurKey
);
175 RegOpenKeyW(HKEY_CLASSES_ROOT
, wszTypeLib
, &hCurKey
);
177 lenName
= sizeof(wszName
);
178 RegQueryValueW(hCurKey
, NULL
, wszName
, (LONG
*)&lenName
);
180 tvis
.hParent
= TVI_ROOT
;
181 wsprintfW(wszTree
, wszFormat2
, wszTypeLib
, wszName
);
182 tvis
.hParent
= TreeView_InsertItemW(details
.hReg
, &tvis
);
184 RegCloseKey(hCurKey
);
186 memmove(&wszData
[8], wszData
, lenData
* sizeof(WCHAR
));
187 memcpy(wszData
, wszTypeLib
, sizeof(WCHAR
[8]));
189 RegOpenKeyW(HKEY_CLASSES_ROOT
, wszData
, &hCurKey
);
191 CreateRegRec(hCurKey
, tvis
.hParent
, &wszData
[8], FALSE
);
193 SendMessageW(details
.hReg
, TVM_EXPAND
, TVE_EXPAND
, (LPARAM
)tvis
.hParent
);
194 tvis
.hParent
= parent
;
196 RegCloseKey(hCurKey
);
200 static void CreateReg(WCHAR
*buffer
)
203 DWORD lenBuffer
=-1, lastLenBuffer
, lenTree
;
205 WCHAR wszTree
[MAX_LOAD_STRING
];
206 TVINSERTSTRUCTW tvis
;
207 HTREEITEM addPlace
= TVI_ROOT
;
209 U(tvis
).item
.mask
= TVIF_TEXT
;
210 U(tvis
).item
.cchTextMax
= MAX_LOAD_STRING
;
211 U(tvis
).item
.pszText
= wszTree
;
212 tvis
.hInsertAfter
= TVI_LAST
;
213 tvis
.hParent
= TVI_ROOT
;
218 while(*path
!= '\\' && *path
!= '\0') path
+= 1;
224 if(RegOpenKeyW(HKEY_CLASSES_ROOT
, buffer
, &hKey
) != ERROR_SUCCESS
)
227 lastLenBuffer
= lenBuffer
+1;
228 lenBuffer
= lstrlenW(buffer
);
232 lenTree
= sizeof(WCHAR
[MAX_LOAD_STRING
]);
234 if(RegQueryValueW(hKey
, NULL
, wszTree
, (LONG
*)&lenTree
) == ERROR_SUCCESS
)
236 memmove(&wszTree
[lenBuffer
-lastLenBuffer
+3], wszTree
,
237 lenTree
* sizeof(WCHAR
));
238 memcpy(wszTree
, &buffer
[lastLenBuffer
],
239 (lenBuffer
- lastLenBuffer
) * sizeof(WCHAR
));
241 if(lenTree
== 1) wszTree
[lenBuffer
-lastLenBuffer
] = '\0';
244 wszTree
[lenBuffer
-lastLenBuffer
] = ' ';
245 wszTree
[lenBuffer
-lastLenBuffer
+1] = '=';
246 wszTree
[lenBuffer
-lastLenBuffer
+2] = ' ';
249 addPlace
= TreeView_InsertItemW(details
.hReg
, &tvis
);
252 tvis
.hParent
= addPlace
;
258 if(RegOpenKeyW(HKEY_CLASSES_ROOT
, buffer
, &hKey
) != ERROR_SUCCESS
) return;
260 CreateRegRec(hKey
, addPlace
, &buffer
[lenBuffer
+1], TRUE
);
264 SendMessageW(details
.hReg
, TVM_EXPAND
, TVE_EXPAND
, (LPARAM
)addPlace
);
265 SendMessageW(details
.hReg
, TVM_ENSUREVISIBLE
, 0, (LPARAM
)addPlace
);
268 void RefreshDetails(HTREEITEM item
)
271 WCHAR wszBuf
[MAX_LOAD_STRING
];
272 WCHAR wszStaticText
[MAX_LOAD_STRING
];
273 const WCHAR wszFormat
[] = { '%','s','\n','%','s','\0' };
276 memset(&tvi
, 0, sizeof(TVITEMW
));
277 memset(&wszStaticText
, 0, sizeof(WCHAR
[MAX_LOAD_STRING
]));
278 tvi
.mask
= TVIF_TEXT
;
280 tvi
.pszText
= wszBuf
;
281 tvi
.cchTextMax
= MAX_LOAD_STRING
;
282 SendMessageW(globals
.hTree
, TVM_GETITEMW
, 0, (LPARAM
)&tvi
);
285 wsprintfW(wszStaticText
, wszFormat
, tvi
.pszText
, ((ITEM_INFO
*)tvi
.lParam
)->clsid
);
286 else lstrcpyW(wszStaticText
, tvi
.pszText
);
288 SetWindowTextW(details
.hStatic
, wszStaticText
);
290 SendMessageW(details
.hTab
, TCM_SETCURSEL
, 0, 0);
292 if(tvi
.lParam
&& ((ITEM_INFO
*)tvi
.lParam
)->cFlag
& SHOWALL
)
294 if(SendMessageW(details
.hTab
, TCM_GETITEMCOUNT
, 0, 0) == 1)
297 memset(&tci
, 0, sizeof(TCITEMW
));
298 tci
.mask
= TCIF_TEXT
;
299 tci
.pszText
= wszBuf
;
300 tci
.cchTextMax
= sizeof(wszBuf
)/sizeof(wszBuf
[0]);
302 LoadStringW(globals
.hMainInst
, IDS_TAB_IMPL
,
303 wszBuf
, sizeof(wszBuf
)/sizeof(wszBuf
[0]));
304 SendMessageW(details
.hTab
, TCM_INSERTITEMW
, 1, (LPARAM
)&tci
);
306 LoadStringW(globals
.hMainInst
, IDS_TAB_ACTIV
,
307 wszBuf
, sizeof(wszBuf
)/sizeof(wszBuf
[0]));
308 SendMessageW(details
.hTab
, TCM_INSERTITEMW
, 2, (LPARAM
)&tci
);
313 SendMessageW(details
.hTab
, TCM_DELETEITEM
, 2, 0);
314 SendMessageW(details
.hTab
, TCM_DELETEITEM
, 1, 0);
317 show
= CreateRegPath(item
, wszBuf
, MAX_LOAD_STRING
);
318 ShowWindow(details
.hTab
, show
? SW_SHOW
: SW_HIDE
);
320 /* FIXME Next line deals with TreeView_EnsureVisible bug */
321 SendMessageW(details
.hReg
, TVM_ENSUREVISIBLE
, 0,
322 SendMessageW(details
.hReg
, TVM_GETNEXTITEM
, TVGN_CHILD
, (LPARAM
)TVI_ROOT
));
323 SendMessageW(details
.hReg
, TVM_DELETEITEM
, 0, (LPARAM
)TVI_ROOT
);
324 if(show
) CreateReg(wszBuf
);
327 static void CreateTabCtrl(HWND hWnd
)
330 WCHAR buffer
[MAX_LOAD_STRING
];
332 memset(&tci
, 0, sizeof(TCITEMW
));
333 tci
.mask
= TCIF_TEXT
;
334 tci
.pszText
= buffer
;
335 tci
.cchTextMax
= sizeof(buffer
)/sizeof(buffer
[0]);
337 details
.hTab
= CreateWindowW(WC_TABCONTROLW
, NULL
, WS_CHILD
|WS_VISIBLE
,
338 0, 0, 0, 0, hWnd
, (HMENU
)TAB_WINDOW
, globals
.hMainInst
, NULL
);
339 ShowWindow(details
.hTab
, SW_HIDE
);
341 LoadStringW(globals
.hMainInst
, IDS_TAB_REG
, buffer
, sizeof(buffer
)/sizeof(buffer
[0]));
342 SendMessageW(details
.hTab
, TCM_INSERTITEMW
, 0, (LPARAM
)&tci
);
344 details
.hReg
= CreateWindowExW(WS_EX_CLIENTEDGE
, WC_TREEVIEWW
, NULL
,
345 WS_CHILD
|WS_VISIBLE
|TVS_HASLINES
,
346 0, 0, 0, 0, details
.hTab
, NULL
, globals
.hMainInst
, NULL
);
349 static LRESULT CALLBACK
DetailsProc(HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
357 const WCHAR wszStatic
[] = { 'S','t','a','t','i','c','\0' };
359 details
.hStatic
= CreateWindowW(wszStatic
, NULL
, WS_CHILD
|WS_VISIBLE
,
360 0, 0, 0, 0, hWnd
, NULL
, globals
.hMainInst
, NULL
);
365 MoveWindow(details
.hStatic
, 0, 0, LOWORD(lParam
), 40, TRUE
);
366 MoveWindow(details
.hTab
, 3, 40, LOWORD(lParam
)-6, HIWORD(lParam
)-43, TRUE
);
367 MoveWindow(details
.hReg
, 10, 34, LOWORD(lParam
)-26,
368 HIWORD(lParam
)-87, TRUE
);
371 if((int)wParam
!= TAB_WINDOW
) break;
372 switch(((LPNMHDR
)lParam
)->code
)
375 ShowWindow(details
.hReg
, SW_HIDE
);
376 sel
= SendMessageW(details
.hTab
, TCM_GETCURSEL
, 0, 0);
378 if(sel
==0) ShowWindow(details
.hReg
, SW_SHOW
);
383 return DefWindowProcW(hWnd
, uMsg
, wParam
, lParam
);
388 HWND
CreateDetailsWindow(HINSTANCE hInst
)
391 const WCHAR wszDetailsClass
[] = { 'D','E','T','A','I','L','S','\0' };
393 memset(&wcd
, 0, sizeof(WNDCLASSW
));
394 wcd
.lpfnWndProc
= DetailsProc
;
395 wcd
.lpszClassName
= wszDetailsClass
;
396 wcd
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+1);
397 wcd
.hCursor
= LoadCursorW(0, (LPCWSTR
)IDC_ARROW
);
399 if(!RegisterClassW(&wcd
)) return NULL
;
401 globals
.hDetails
= CreateWindowExW(WS_EX_CLIENTEDGE
, wszDetailsClass
, NULL
,
402 WS_CHILD
|WS_VISIBLE
, 0, 0, 0, 0, globals
.hPaneWnd
, NULL
, hInst
, NULL
);
404 return globals
.hDetails
;