| /* |
| * OleView (tree.c) |
| * |
| * Copyright 2006 Piotr Caban |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| #include "main.h" |
| |
| TREE tree; |
| static const WCHAR wszCLSID[] = { 'C','L','S','I','D','\\','\0' }; |
| static const WCHAR wszInProcServer32[] = |
| { 'I','n','P','r','o','c','S','e','r','v','e','r','3','2','\0' }; |
| static const WCHAR wszOle32dll[] = { 'o','l','e','3','2','.','d','l','l','\0' }; |
| static const WCHAR wszOleAut32dll[] = |
| { 'o','l','e','a','u','t','3','2','.','d','l','l','\0' }; |
| static const WCHAR wszImplementedCategories[] = |
| { 'I','m','p','l','e','m','e','n','t','e','d',' ', |
| 'C','a','t','e','g','o','r','i','e','s','\0' }; |
| static const WCHAR wszAppID[] = { 'A','p','p','I','D','\\','\0' }; |
| static const WCHAR wszTypeLib[] = { 'T','y','p','e','L','i','b','\\','\0' }; |
| static const WCHAR wszInterface[] = { 'I','n','t','e','r','f','a','c','e','\\','\0' }; |
| static const WCHAR wszComponentCategories[] = { 'C','o','m','p','o','n','e','n','t', |
| ' ','C','a','t','e','g','o','r','i','e','s','\\','\0' }; |
| static const WCHAR wszGetPath[] = { '0','\\','w','i','n','3','2','\0' }; |
| |
| static LPARAM CreateITEM_INFO(INT flag, const WCHAR *info, const WCHAR *clsid, const WCHAR *path) |
| { |
| ITEM_INFO *reg; |
| |
| reg = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ITEM_INFO)); |
| |
| reg->cFlag = flag; |
| lstrcpyW(reg->info, info); |
| if(clsid) lstrcpyW(reg->clsid, clsid); |
| if(path) lstrcpyW(reg->path, path); |
| |
| return (LPARAM)reg; |
| } |
| |
| void CreateInst(HTREEITEM item, WCHAR *wszMachineName) |
| { |
| TVITEMW tvi; |
| HTREEITEM hCur; |
| TVINSERTSTRUCTW tvis; |
| WCHAR wszTitle[MAX_LOAD_STRING]; |
| WCHAR wszMessage[MAX_LOAD_STRING]; |
| WCHAR wszFlagName[MAX_LOAD_STRING]; |
| WCHAR wszTreeName[MAX_LOAD_STRING]; |
| WCHAR wszRegPath[MAX_LOAD_STRING]; |
| const WCHAR wszFormat[] = { '\n','%','s',' ','(','$','%','x',')','\n','\0' }; |
| CLSID clsid; |
| COSERVERINFO remoteInfo; |
| MULTI_QI qi; |
| IUnknown *obj, *unk; |
| HRESULT hRes; |
| |
| memset(&tvi, 0, sizeof(TVITEMW)); |
| tvi.mask = TVIF_TEXT; |
| tvi.hItem = item; |
| tvi.cchTextMax = MAX_LOAD_STRING; |
| tvi.pszText = wszTreeName; |
| |
| memset(&tvis, 0, sizeof(TVINSERTSTRUCTW)); |
| U(tvis).item.mask = TVIF_TEXT|TVIF_PARAM; |
| U(tvis).item.cchTextMax = MAX_LOAD_STRING; |
| tvis.hInsertAfter = TVI_FIRST; |
| U(tvis).item.pszText = tvi.pszText; |
| tvis.hParent = item; |
| tvis.hInsertAfter = TVI_LAST; |
| |
| if (!SendMessageW(globals.hTree, TVM_GETITEMW, 0, (LPARAM)&tvi)) return; |
| |
| if(!tvi.lParam || ((ITEM_INFO *)tvi.lParam)->loaded |
| || !(((ITEM_INFO *)tvi.lParam)->cFlag&SHOWALL)) return; |
| |
| if(FAILED(CLSIDFromString(((ITEM_INFO *)tvi.lParam)->clsid, &clsid))) return; |
| |
| if(wszMachineName) |
| { |
| remoteInfo.dwReserved1 = 0; |
| remoteInfo.dwReserved2 = 0; |
| remoteInfo.pAuthInfo = NULL; |
| remoteInfo.pwszName = wszMachineName; |
| |
| qi.pIID = &IID_IUnknown; |
| |
| CoCreateInstanceEx(&clsid, NULL, globals.dwClsCtx|CLSCTX_REMOTE_SERVER, |
| &remoteInfo, 1, &qi); |
| hRes = qi.hr; |
| obj = qi.pItf; |
| } |
| else hRes = CoCreateInstance(&clsid, NULL, globals.dwClsCtx, |
| &IID_IUnknown, (void **)&obj); |
| |
| if(FAILED(hRes)) |
| { |
| LoadStringW(globals.hMainInst, IDS_CGCOFAIL, wszMessage, |
| sizeof(wszMessage)/sizeof(wszMessage[0])); |
| LoadStringW(globals.hMainInst, IDS_ABOUT, wszTitle, |
| sizeof(wszTitle)/sizeof(wszTitle[0])); |
| |
| #define CASE_ERR(i) case i: \ |
| MultiByteToWideChar(CP_ACP, 0, #i, -1, wszFlagName, MAX_LOAD_STRING); \ |
| break |
| |
| switch(hRes) |
| { |
| CASE_ERR(REGDB_E_CLASSNOTREG); |
| CASE_ERR(E_NOINTERFACE); |
| CASE_ERR(REGDB_E_READREGDB); |
| CASE_ERR(REGDB_E_KEYMISSING); |
| CASE_ERR(CO_E_DLLNOTFOUND); |
| CASE_ERR(CO_E_APPNOTFOUND); |
| CASE_ERR(E_ACCESSDENIED); |
| CASE_ERR(CO_E_ERRORINDLL); |
| CASE_ERR(CO_E_APPDIDNTREG); |
| CASE_ERR(CLASS_E_CLASSNOTAVAILABLE); |
| default: |
| LoadStringW(globals.hMainInst, IDS_ERROR_UNKN, wszFlagName, sizeof(wszFlagName)/sizeof(wszFlagName[0])); |
| } |
| |
| wsprintfW(&wszMessage[lstrlenW(wszMessage)], wszFormat, |
| wszFlagName, (unsigned)hRes); |
| MessageBoxW(globals.hMainWnd, wszMessage, wszTitle, MB_OK|MB_ICONEXCLAMATION); |
| return; |
| } |
| |
| ((ITEM_INFO *)tvi.lParam)->loaded = 1; |
| ((ITEM_INFO *)tvi.lParam)->pU = obj; |
| |
| tvi.mask = TVIF_STATE; |
| tvi.state = TVIS_BOLD; |
| tvi.stateMask = TVIS_BOLD; |
| SendMessageW(globals.hTree, TVM_SETITEMW, 0, (LPARAM)&tvi); |
| |
| tvi.mask = TVIF_TEXT; |
| hCur = (HTREEITEM)SendMessageW(globals.hTree, TVM_GETNEXTITEM, |
| TVGN_CHILD, (LPARAM)tree.hI); |
| |
| while(hCur) |
| { |
| tvi.hItem = hCur; |
| if(!SendMessageW(globals.hTree, TVM_GETITEMW, 0, (LPARAM)&tvi) || !tvi.lParam) |
| { |
| hCur = (HTREEITEM)SendMessageW(globals.hTree, TVM_GETNEXTITEM, |
| TVGN_NEXT, (LPARAM)hCur); |
| continue; |
| } |
| |
| CLSIDFromString(((ITEM_INFO *)tvi.lParam)->clsid, &clsid); |
| hRes = IUnknown_QueryInterface(obj, &clsid, (void *)&unk); |
| |
| if(SUCCEEDED(hRes)) |
| { |
| IUnknown_Release(unk); |
| |
| lstrcpyW(wszRegPath, wszInterface); |
| lstrcpyW(&wszRegPath[lstrlenW(wszRegPath)], ((ITEM_INFO *)tvi.lParam)->clsid); |
| U(tvis).item.lParam = CreateITEM_INFO(REGTOP|INTERFACE|REGPATH, |
| wszRegPath, ((ITEM_INFO *)tvi.lParam)->clsid, NULL); |
| SendMessageW(globals.hTree, TVM_INSERTITEMW, 0, (LPARAM)&tvis); |
| } |
| hCur = (HTREEITEM)SendMessageW(globals.hTree, TVM_GETNEXTITEM, |
| TVGN_NEXT, (LPARAM)hCur); |
| } |
| |
| RefreshMenu(item); |
| RefreshDetails(item); |
| } |
| |
| void ReleaseInst(HTREEITEM item) |
| { |
| TVITEMW tvi; |
| HTREEITEM cur; |
| IUnknown *pU; |
| |
| memset(&tvi, 0, sizeof(TVITEMW)); |
| tvi.hItem = item; |
| if(!SendMessageW(globals.hTree, TVM_GETITEMW, 0, (LPARAM)&tvi) || !tvi.lParam) return; |
| |
| pU = ((ITEM_INFO *)tvi.lParam)->pU; |
| |
| if(pU) IUnknown_Release(pU); |
| ((ITEM_INFO *)tvi.lParam)->loaded = 0; |
| |
| SendMessageW(globals.hTree, TVM_EXPAND, TVE_COLLAPSE, (LPARAM)item); |
| |
| cur = (HTREEITEM)SendMessageW(globals.hTree, TVM_GETNEXTITEM, |
| TVGN_CHILD, (LPARAM)item); |
| while(cur) |
| { |
| SendMessageW(globals.hTree, TVM_DELETEITEM, 0, (LPARAM)cur); |
| cur = (HTREEITEM)SendMessageW(globals.hTree, TVM_GETNEXTITEM, |
| TVGN_CHILD, (LPARAM)item); |
| } |
| |
| tvi.mask = TVIF_CHILDREN|TVIF_STATE; |
| tvi.state = 0; |
| tvi.stateMask = TVIS_BOLD; |
| tvi.cChildren = 1; |
| SendMessageW(globals.hTree, TVM_SETITEMW, 0, (LPARAM)&tvi); |
| } |
| |
| BOOL CreateRegPath(HTREEITEM item, WCHAR *buffer, int bufSize) |
| { |
| TVITEMW tvi; |
| int bufLen; |
| BOOL ret = FALSE; |
| |
| memset(buffer, 0, bufSize * sizeof(WCHAR)); |
| memset(&tvi, 0, sizeof(TVITEMW)); |
| tvi.hItem = item; |
| |
| if (SendMessageW(globals.hTree, TVM_GETITEMW, 0, (LPARAM)&tvi)) |
| ret = (tvi.lParam && ((ITEM_INFO *)tvi.lParam)->cFlag & REGPATH); |
| |
| while(TRUE) |
| { |
| if(!SendMessageW(globals.hTree, TVM_GETITEMW, 0, (LPARAM)&tvi)) break; |
| |
| if(tvi.lParam && (((ITEM_INFO *)tvi.lParam)->cFlag & (REGPATH|REGTOP))) |
| { |
| bufLen = lstrlenW(((ITEM_INFO *)tvi.lParam)->info); |
| memmove(&buffer[bufLen], buffer, (bufSize - bufLen) * sizeof(WCHAR)); |
| memcpy(buffer, ((ITEM_INFO *)tvi.lParam)->info, bufLen * sizeof(WCHAR)); |
| } |
| |
| if(tvi.lParam && ((ITEM_INFO *)tvi.lParam)->cFlag & REGTOP) break; |
| |
| if(!tvi.lParam) return FALSE; |
| |
| tvi.hItem = (HTREEITEM)SendMessageW(globals.hTree, TVM_GETNEXTITEM, |
| TVGN_PARENT, (LPARAM)tvi.hItem); |
| } |
| return ret; |
| } |
| |
| static void AddCOMandAll(void) |
| { |
| TVINSERTSTRUCTW tvis; |
| TVITEMW tvi; |
| HTREEITEM curSearch; |
| HKEY hKey, hCurKey, hInfo; |
| WCHAR valName[MAX_LOAD_STRING]; |
| WCHAR buffer[MAX_LOAD_STRING]; |
| WCHAR wszComp[MAX_LOAD_STRING]; |
| LONG lenBuffer; |
| int i=-1; |
| |
| memset(&tvi, 0, sizeof(TVITEMW)); |
| U(tvis).item.mask = TVIF_TEXT|TVIF_PARAM|TVIF_CHILDREN; |
| U(tvis).item.cchTextMax = MAX_LOAD_STRING; |
| U(tvis).item.cChildren = 1; |
| tvis.hInsertAfter = TVI_FIRST; |
| |
| if(RegOpenKeyW(HKEY_CLASSES_ROOT, wszCLSID, &hKey) != ERROR_SUCCESS) return; |
| |
| while(TRUE) |
| { |
| i++; |
| |
| if(RegEnumKeyW(hKey, i, valName, sizeof(valName)/sizeof(valName[0])) != ERROR_SUCCESS) break; |
| |
| if(RegOpenKeyW(hKey, valName, &hCurKey) != ERROR_SUCCESS) continue; |
| |
| lenBuffer = sizeof(WCHAR[MAX_LOAD_STRING]); |
| tvis.hParent = tree.hAO; |
| |
| if(RegOpenKeyW(hCurKey, wszInProcServer32, &hInfo) == ERROR_SUCCESS) |
| { |
| if(RegQueryValueW(hInfo, NULL, buffer, &lenBuffer) == ERROR_SUCCESS |
| && *buffer) |
| if(!memcmp(buffer, wszOle32dll, sizeof(WCHAR[9])) |
| ||!memcmp(buffer, wszOleAut32dll, sizeof(WCHAR[12]))) |
| tvis.hParent = tree.hCLO; |
| |
| RegCloseKey(hInfo); |
| } |
| |
| lenBuffer = sizeof(WCHAR[MAX_LOAD_STRING]); |
| |
| if(RegQueryValueW(hCurKey, NULL, buffer, &lenBuffer) == ERROR_SUCCESS && *buffer) |
| U(tvis).item.pszText = buffer; |
| else U(tvis).item.pszText = valName; |
| |
| U(tvis).item.lParam = CreateITEM_INFO(REGPATH|SHOWALL, valName, valName, NULL); |
| if(tvis.hParent) SendMessageW(globals.hTree, TVM_INSERTITEMW, 0, (LPARAM)&tvis); |
| |
| if(RegOpenKeyW(hCurKey, wszImplementedCategories, &hInfo) == ERROR_SUCCESS) |
| { |
| if(RegEnumKeyW(hInfo, 0, wszComp, sizeof(wszComp)/sizeof(wszComp[0])) != ERROR_SUCCESS) break; |
| |
| RegCloseKey(hInfo); |
| |
| if(tree.hGBCC) curSearch = (HTREEITEM)SendMessageW(globals.hTree, |
| TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)tree.hGBCC); |
| else curSearch = (HTREEITEM)SendMessageW(globals.hTree, |
| TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)TVI_ROOT); |
| |
| while(curSearch) |
| { |
| tvi.hItem = curSearch; |
| if(!SendMessageW(globals.hTree, TVM_GETITEMW, 0, (LPARAM)&tvi)) break; |
| |
| if(tvi.lParam && !lstrcmpW(((ITEM_INFO *)tvi.lParam)->info, wszComp)) |
| { |
| tvis.hParent = curSearch; |
| |
| memmove(&valName[6], valName, sizeof(WCHAR[MAX_LOAD_STRING-6])); |
| memmove(valName, wszCLSID, sizeof(WCHAR[6])); |
| U(tvis).item.lParam = CreateITEM_INFO(REGTOP|REGPATH|SHOWALL, |
| valName, &valName[6], NULL); |
| |
| SendMessageW(globals.hTree, TVM_INSERTITEMW, 0, (LPARAM)&tvis); |
| break; |
| } |
| curSearch = (HTREEITEM)SendMessageW(globals.hTree, |
| TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)curSearch); |
| } |
| } |
| RegCloseKey(hCurKey); |
| } |
| RegCloseKey(hKey); |
| |
| SendMessageW(globals.hTree, TVM_SORTCHILDREN, FALSE, (LPARAM)tree.hCLO); |
| SendMessageW(globals.hTree, TVM_SORTCHILDREN, FALSE, (LPARAM)tree.hAO); |
| } |
| |
| static void AddApplicationID(void) |
| { |
| TVINSERTSTRUCTW tvis; |
| HKEY hKey, hCurKey; |
| WCHAR valName[MAX_LOAD_STRING]; |
| WCHAR buffer[MAX_LOAD_STRING]; |
| LONG lenBuffer; |
| int i=-1; |
| |
| U(tvis).item.mask = TVIF_TEXT|TVIF_PARAM; |
| U(tvis).item.cchTextMax = MAX_LOAD_STRING; |
| tvis.hInsertAfter = TVI_FIRST; |
| tvis.hParent = tree.hAID; |
| |
| if(RegOpenKeyW(HKEY_CLASSES_ROOT, wszAppID, &hKey) != ERROR_SUCCESS) return; |
| |
| while(TRUE) |
| { |
| i++; |
| |
| if(RegEnumKeyW(hKey, i, valName, sizeof(valName)/sizeof(valName[0])) != ERROR_SUCCESS) break; |
| |
| if(RegOpenKeyW(hKey, valName, &hCurKey) != ERROR_SUCCESS) continue; |
| |
| lenBuffer = sizeof(WCHAR[MAX_LOAD_STRING]); |
| |
| if(RegQueryValueW(hCurKey, NULL, buffer, &lenBuffer) == ERROR_SUCCESS && *buffer) |
| U(tvis).item.pszText = buffer; |
| else U(tvis).item.pszText = valName; |
| |
| RegCloseKey(hCurKey); |
| |
| U(tvis).item.lParam = CreateITEM_INFO(REGPATH, valName, valName, NULL); |
| SendMessageW(globals.hTree, TVM_INSERTITEMW, 0, (LPARAM)&tvis); |
| } |
| RegCloseKey(hKey); |
| |
| SendMessageW(globals.hTree, TVM_SORTCHILDREN, FALSE, (LPARAM)tree.hAID); |
| } |
| |
| static void AddTypeLib(void) |
| { |
| TVINSERTSTRUCTW tvis; |
| HKEY hKey, hCurKey, hInfoKey, hPath; |
| WCHAR valName[MAX_LOAD_STRING]; |
| WCHAR valParent[MAX_LOAD_STRING]; |
| WCHAR buffer[MAX_LOAD_STRING]; |
| WCHAR wszVer[MAX_LOAD_STRING]; |
| WCHAR wszPath[MAX_LOAD_STRING]; |
| const WCHAR wszFormat[] = { ' ','(','%','s',' ','%','s',')','\0' }; |
| const WCHAR wszFormat2[] = { '%','s','\\','%','s','\0' }; |
| LONG lenBuffer; |
| int i=-1, j; |
| |
| U(tvis).item.mask = TVIF_TEXT|TVIF_PARAM; |
| U(tvis).item.cchTextMax = MAX_LOAD_STRING; |
| tvis.hInsertAfter = TVI_FIRST; |
| tvis.hParent = tree.hTL; |
| |
| if(RegOpenKeyW(HKEY_CLASSES_ROOT, wszTypeLib, &hKey) != ERROR_SUCCESS) return; |
| |
| while(TRUE) |
| { |
| i++; |
| |
| if(RegEnumKeyW(hKey, i, valParent, sizeof(valParent)/sizeof(valParent[0])) != ERROR_SUCCESS) break; |
| |
| if(RegOpenKeyW(hKey, valParent, &hCurKey) != ERROR_SUCCESS) continue; |
| |
| j = -1; |
| while(TRUE) |
| { |
| j++; |
| |
| if(RegEnumKeyW(hCurKey, j, valName, sizeof(valName)/sizeof(valName[0])) != ERROR_SUCCESS) break; |
| |
| if(RegOpenKeyW(hCurKey, valName, &hInfoKey) != ERROR_SUCCESS) continue; |
| |
| lenBuffer = sizeof(WCHAR[MAX_LOAD_STRING]); |
| |
| if(RegQueryValueW(hInfoKey, NULL, buffer, &lenBuffer) == ERROR_SUCCESS |
| && *buffer) |
| { |
| LoadStringW(globals.hMainInst, IDS_TL_VER, wszVer, |
| sizeof(wszVer)/sizeof(wszVer[0])); |
| |
| wsprintfW(&buffer[lstrlenW(buffer)], wszFormat, wszVer, valName); |
| U(tvis).item.pszText = buffer; |
| |
| lenBuffer = MAX_LOAD_STRING; |
| RegOpenKeyW(hInfoKey, wszGetPath, &hPath); |
| RegQueryValueW(hPath, NULL, wszPath, &lenBuffer); |
| RegCloseKey(hPath); |
| } |
| else U(tvis).item.pszText = valName; |
| |
| RegCloseKey(hInfoKey); |
| |
| wsprintfW(wszVer, wszFormat2, valParent, valName); |
| U(tvis).item.lParam = CreateITEM_INFO(REGPATH, wszVer, valParent, wszPath); |
| |
| SendMessageW(globals.hTree, TVM_INSERTITEMW, 0, (LPARAM)&tvis); |
| } |
| RegCloseKey(hCurKey); |
| } |
| |
| RegCloseKey(hKey); |
| |
| SendMessageW(globals.hTree, TVM_SORTCHILDREN, FALSE, (LPARAM)tree.hTL); |
| } |
| |
| static void AddInterfaces(void) |
| { |
| TVINSERTSTRUCTW tvis; |
| HKEY hKey, hCurKey; |
| WCHAR valName[MAX_LOAD_STRING]; |
| WCHAR buffer[MAX_LOAD_STRING]; |
| LONG lenBuffer; |
| int i=-1; |
| |
| U(tvis).item.mask = TVIF_TEXT|TVIF_PARAM; |
| U(tvis).item.cchTextMax = MAX_LOAD_STRING; |
| tvis.hInsertAfter = TVI_FIRST; |
| tvis.hParent = tree.hI; |
| |
| if(RegOpenKeyW(HKEY_CLASSES_ROOT, wszInterface, &hKey) != ERROR_SUCCESS) return; |
| |
| while(TRUE) |
| { |
| i++; |
| |
| if(RegEnumKeyW(hKey, i, valName, sizeof(valName)/sizeof(valName[0])) != ERROR_SUCCESS) break; |
| |
| if(RegOpenKeyW(hKey, valName, &hCurKey) != ERROR_SUCCESS) continue; |
| |
| lenBuffer = sizeof(WCHAR[MAX_LOAD_STRING]); |
| |
| if(RegQueryValueW(hCurKey, NULL, buffer, &lenBuffer) == ERROR_SUCCESS && *buffer) |
| U(tvis).item.pszText = buffer; |
| else U(tvis).item.pszText = valName; |
| |
| RegCloseKey(hCurKey); |
| |
| U(tvis).item.lParam = CreateITEM_INFO(REGPATH|INTERFACE, valName, valName, NULL); |
| SendMessageW(globals.hTree, TVM_INSERTITEMW, 0, (LPARAM)&tvis); |
| } |
| |
| RegCloseKey(hKey); |
| |
| SendMessageW(globals.hTree, TVM_SORTCHILDREN, FALSE, (LPARAM)tree.hI); |
| } |
| |
| static void AddComponentCategories(void) |
| { |
| TVINSERTSTRUCTW tvis; |
| HKEY hKey, hCurKey; |
| WCHAR keyName[MAX_LOAD_STRING]; |
| WCHAR valName[MAX_LOAD_STRING]; |
| WCHAR buffer[MAX_LOAD_STRING]; |
| LONG lenBuffer; |
| DWORD lenBufferHlp; |
| DWORD lenValName; |
| int i=-1; |
| |
| U(tvis).item.mask = TVIF_TEXT|TVIF_PARAM|TVIF_CHILDREN; |
| U(tvis).item.cchTextMax = MAX_LOAD_STRING; |
| tvis.hInsertAfter = TVI_FIRST; |
| if(tree.hGBCC) tvis.hParent = tree.hGBCC; |
| else tvis.hParent = TVI_ROOT; |
| U(tvis).item.cChildren = 1; |
| |
| if(RegOpenKeyW(HKEY_CLASSES_ROOT, wszComponentCategories, &hKey) != ERROR_SUCCESS) |
| return; |
| |
| while(TRUE) |
| { |
| i++; |
| |
| if(RegEnumKeyW(hKey, i, keyName, sizeof(keyName)/sizeof(keyName[0])) != ERROR_SUCCESS) break; |
| |
| if(RegOpenKeyW(hKey, keyName, &hCurKey) != ERROR_SUCCESS) continue; |
| |
| lenBuffer = sizeof(WCHAR[MAX_LOAD_STRING]); |
| lenBufferHlp = sizeof(WCHAR[MAX_LOAD_STRING]); |
| lenValName = sizeof(WCHAR[MAX_LOAD_STRING]); |
| |
| if(RegQueryValueW(hCurKey, NULL, buffer, &lenBuffer) == ERROR_SUCCESS && *buffer) |
| U(tvis).item.pszText = buffer; |
| else if(RegEnumValueW(hCurKey, 0, valName, &lenValName, NULL, NULL, |
| (LPBYTE)buffer, &lenBufferHlp) == ERROR_SUCCESS && *buffer) |
| U(tvis).item.pszText = buffer; |
| else continue; |
| |
| RegCloseKey(hCurKey); |
| |
| U(tvis).item.lParam = CreateITEM_INFO(REGTOP, keyName, keyName, NULL); |
| SendMessageW(globals.hTree, TVM_INSERTITEMW, 0, (LPARAM)&tvis); |
| } |
| |
| RegCloseKey(hKey); |
| |
| SendMessageW(globals.hTree, TVM_SORTCHILDREN, FALSE, (LPARAM)tree.hGBCC); |
| } |
| |
| static void AddBaseEntries(void) |
| { |
| TVINSERTSTRUCTW tvis; |
| WCHAR name[MAX_LOAD_STRING]; |
| |
| U(tvis).item.mask = TVIF_TEXT|TVIF_CHILDREN|TVIF_PARAM; |
| /* FIXME add TVIF_IMAGE */ |
| U(tvis).item.pszText = name; |
| U(tvis).item.cchTextMax = MAX_LOAD_STRING; |
| U(tvis).item.cChildren = 1; |
| tvis.hInsertAfter = TVI_FIRST; |
| tvis.hParent = TVI_ROOT; |
| |
| LoadStringW(globals.hMainInst, IDS_TREE_I, U(tvis).item.pszText, |
| MAX_LOAD_STRING); |
| U(tvis).item.lParam = CreateITEM_INFO(REGTOP, wszInterface, NULL, NULL); |
| tree.hI = TreeView_InsertItemW(globals.hTree, &tvis); |
| |
| LoadStringW(globals.hMainInst, IDS_TREE_TL, U(tvis).item.pszText, |
| MAX_LOAD_STRING); |
| U(tvis).item.lParam = CreateITEM_INFO(REGTOP, wszTypeLib, NULL, NULL); |
| tree.hTL = TreeView_InsertItemW(globals.hTree, &tvis); |
| |
| LoadStringW(globals.hMainInst, IDS_TREE_AID, U(tvis).item.pszText, |
| MAX_LOAD_STRING); |
| U(tvis).item.lParam = CreateITEM_INFO(REGTOP|REGPATH, wszAppID, NULL, NULL); |
| tree.hAID = TreeView_InsertItemW(globals.hTree, &tvis); |
| |
| LoadStringW(globals.hMainInst, IDS_TREE_OC, U(tvis).item.pszText, |
| MAX_LOAD_STRING); |
| U(tvis).item.lParam = 0; |
| tree.hOC = TreeView_InsertItemW(globals.hTree, &tvis); |
| |
| |
| tvis.hParent = tree.hOC; |
| LoadStringW(globals.hMainInst, IDS_TREE_AO, U(tvis).item.pszText, |
| MAX_LOAD_STRING); |
| U(tvis).item.lParam = CreateITEM_INFO(REGTOP, wszCLSID, NULL, NULL); |
| tree.hAO = TreeView_InsertItemW(globals.hTree, &tvis); |
| |
| LoadStringW(globals.hMainInst, IDS_TREE_CLO, U(tvis).item.pszText, |
| MAX_LOAD_STRING); |
| tree.hCLO = TreeView_InsertItemW(globals.hTree, &tvis); |
| |
| LoadStringW(globals.hMainInst, IDS_TREE_O1O, U(tvis).item.pszText, |
| MAX_LOAD_STRING); |
| U(tvis).item.lParam = 0; |
| tree.hO1O = TreeView_InsertItemW(globals.hTree, &tvis); |
| |
| LoadStringW(globals.hMainInst, IDS_TREE_GBCC, U(tvis).item.pszText, |
| MAX_LOAD_STRING); |
| U(tvis).item.lParam = CreateITEM_INFO(REGTOP|REGPATH, |
| wszComponentCategories, NULL, NULL); |
| tree.hGBCC = TreeView_InsertItemW(globals.hTree, &tvis); |
| |
| SendMessageW(globals.hTree, TVM_EXPAND, TVE_EXPAND, (LPARAM)tree.hOC); |
| } |
| |
| void EmptyTree(void) |
| { |
| SendMessageW(globals.hTree, TVM_DELETEITEM, 0, (LPARAM)TVI_ROOT); |
| } |
| |
| void AddTreeEx(void) |
| { |
| AddBaseEntries(); |
| AddComponentCategories(); |
| AddCOMandAll(); |
| AddApplicationID(); |
| AddTypeLib(); |
| AddInterfaces(); |
| } |
| |
| void AddTree(void) |
| { |
| memset(&tree, 0, sizeof(TREE)); |
| AddComponentCategories(); |
| AddCOMandAll(); |
| } |
| |
| static LRESULT CALLBACK TreeProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) |
| { |
| switch(uMsg) |
| { |
| case WM_CREATE: |
| globals.hTree = CreateWindowW(WC_TREEVIEWW, NULL, |
| WS_CHILD|WS_VISIBLE|TVS_HASLINES|TVS_HASBUTTONS|TVS_LINESATROOT, |
| 0, 0, 0, 0, hWnd, (HMENU)TREE_WINDOW, globals.hMainInst, NULL); |
| AddTreeEx(); |
| break; |
| case WM_NOTIFY: |
| if((int)wParam != TREE_WINDOW) break; |
| switch(((LPNMHDR)lParam)->code) |
| { |
| case TVN_ITEMEXPANDINGW: |
| CreateInst(((NMTREEVIEWW *)lParam)->itemNew.hItem, NULL); |
| break; |
| case TVN_SELCHANGEDW: |
| RefreshMenu(((NMTREEVIEWW *)lParam)->itemNew.hItem); |
| RefreshDetails(((NMTREEVIEWW *)lParam)->itemNew.hItem); |
| break; |
| case TVN_DELETEITEMW: |
| { |
| NMTREEVIEWW *nm = (NMTREEVIEWW*)lParam; |
| ITEM_INFO *info = (ITEM_INFO*)nm->itemOld.lParam; |
| |
| if (info) |
| { |
| if (info->loaded) |
| ReleaseInst(nm->itemOld.hItem); |
| HeapFree(GetProcessHeap(), 0, info); |
| } |
| break; |
| } |
| } |
| break; |
| case WM_SIZE: |
| MoveWindow(globals.hTree, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE); |
| break; |
| default: |
| return DefWindowProcW(hWnd, uMsg, wParam, lParam); |
| } |
| return 0; |
| } |
| |
| HWND CreateTreeWindow(HINSTANCE hInst) |
| { |
| WNDCLASSW wct; |
| const WCHAR wszTreeClass[] = { 'T','R','E','E','\0' }; |
| |
| memset(&wct, 0, sizeof(WNDCLASSW)); |
| wct.lpfnWndProc = TreeProc; |
| wct.lpszClassName = wszTreeClass; |
| wct.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); |
| wct.hCursor = LoadCursorW(0, (LPCWSTR)IDC_ARROW); |
| |
| if(!RegisterClassW(&wct)) return NULL; |
| |
| return CreateWindowExW(WS_EX_CLIENTEDGE, wszTreeClass, NULL, WS_CHILD|WS_VISIBLE, |
| 0, 0, 0, 0, globals.hPaneWnd, NULL, hInst, NULL); |
| } |