details.c 13.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
 * OleView (details.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
18
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 20 21 22 23
 */

#include "main.h"

DETAILS details;
24 25 26 27 28 29 30
static const WCHAR wszAppID[] = { 'A','p','p','I','D','\0' };
static const WCHAR wszCLSID[] = { 'C','L','S','I','D','\0' };
static const WCHAR wszProgID[] = { 'P','r','o','g','I','D','\0' };
static const WCHAR wszProxyStubClsid32[] = 
    { 'P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2','\0' };
static const WCHAR wszTypeLib[] = { 'T','y','p','e','L','i','b','\0' };

31
static void CreateRegRec(HKEY hKey, HTREEITEM parent, WCHAR *wszKeyName, BOOL addings)
32 33 34 35 36 37 38 39 40 41 42
{
    int i=0, j, retEnum;
    HKEY hCurKey;
    DWORD lenName, lenData, valType;
    WCHAR wszName[MAX_LOAD_STRING];
    WCHAR wszData[MAX_LOAD_STRING];
    WCHAR wszTree[MAX_LOAD_STRING];
    const WCHAR wszBinary[] = { '%','0','2','X',' ','\0' };
    const WCHAR wszDots[] = { '.','.','.','\0' };
    const WCHAR wszFormat1[] = { '%','s',' ','[','%','s',']',' ','=',' ','%','s','\0' };
    const WCHAR wszFormat2[] = { '%','s',' ','=',' ','%','s','\0' };
43
    TVINSERTSTRUCTW tvis;
44 45
    HTREEITEM addPlace = parent;

46 47 48
    U(tvis).item.mask = TVIF_TEXT;
    U(tvis).item.cchTextMax = MAX_LOAD_STRING;
    U(tvis).item.pszText = wszTree;
49
    tvis.hInsertAfter = TVI_LAST;
50 51 52 53
    tvis.hParent = parent;

    while(TRUE)
    {
54
        lenName = sizeof(WCHAR[MAX_LOAD_STRING])/sizeof(WCHAR);
55 56
        lenData = sizeof(WCHAR[MAX_LOAD_STRING]);

57
        retEnum = RegEnumValueW(hKey, i, wszName, &lenName,
58 59 60 61
                NULL, &valType, (LPBYTE)wszData, &lenData);

        if(retEnum != ERROR_SUCCESS)
        {
62
            if(!i && lstrlenW(wszKeyName) > 1)
63
            {
64
                U(tvis).item.pszText = wszKeyName;
65
                addPlace = TreeView_InsertItemW(details.hReg, &tvis);
66
                U(tvis).item.pszText = wszTree;
67 68 69 70 71 72 73 74 75 76 77
            }
            break;
        }

        if(valType == REG_BINARY)
        {
            WCHAR wszBuf[MAX_LOAD_STRING];

            for(j=0; j<MAX_LOAD_STRING/3-1; j++)
                wsprintfW(&wszBuf[3*j], wszBinary, (int)((unsigned char)wszData[j]));
            wszBuf[(lenData*3>=MAX_LOAD_STRING ? MAX_LOAD_STRING-1 : lenData*3)] = '\0';
78 79
            lstrcpyW(wszData, wszBuf);
            lstrcpyW(&wszData[MAX_LOAD_STRING-5], wszDots);
80 81 82 83 84
        }

        if(lenName) wsprintfW(wszTree, wszFormat1, wszKeyName, wszName, wszData);
        else wsprintfW(wszTree, wszFormat2, wszKeyName, wszData);

85
        addPlace = TreeView_InsertItemW(details.hReg, &tvis);
86 87 88

        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);
92 93
            wszData[5] = '\\';

94
            if(RegOpenKeyW(HKEY_CLASSES_ROOT, wszData, &hCurKey) != ERROR_SUCCESS)
95 96 97 98 99 100
            {
                i++;
                continue;
            }

            tvis.hParent = TVI_ROOT;
101
            tvis.hParent = TreeView_InsertItemW(details.hReg, &tvis);
102 103 104

            lenName = sizeof(WCHAR[MAX_LOAD_STRING]);

105
            RegQueryValueW(hCurKey, NULL, wszName, (LONG *)&lenName);
106 107 108 109
            RegCloseKey(hCurKey);

            wsprintfW(wszTree, wszFormat2, &wszData[6], wszName);

110 111
            SendMessageW(details.hReg, TVM_INSERTITEMW, 0, (LPARAM)&tvis);
            SendMessageW(details.hReg, TVM_EXPAND, TVE_EXPAND, (LPARAM)tvis.hParent);
112 113 114 115 116 117 118 119 120 121 122 123 124

            tvis.hParent = parent;
        }
        i++;
    }

    i=-1;
    lenName = sizeof(WCHAR[MAX_LOAD_STRING]);

    while(TRUE)
    {
        i++;

125
        if(RegEnumKeyW(hKey, i, wszName, lenName) != ERROR_SUCCESS) break;
126

127
        if(RegOpenKeyW(hKey, wszName, &hCurKey) != ERROR_SUCCESS) continue;
128 129

        CreateRegRec(hCurKey, addPlace, wszName, addings);
130
        SendMessageW(details.hReg, TVM_EXPAND, TVE_EXPAND, (LPARAM)addPlace);
131 132 133 134 135

        if(addings && !memcmp(wszName, wszProgID, sizeof(WCHAR[7])))
        {
            lenData = sizeof(WCHAR[MAX_LOAD_STRING]);

136
            RegQueryValueW(hCurKey, NULL, wszData, (LONG *)&lenData);
137 138
            RegCloseKey(hCurKey);

139
            if(RegOpenKeyW(HKEY_CLASSES_ROOT, wszData, &hCurKey) != ERROR_SUCCESS)
140 141 142 143 144 145 146
                continue;
            CreateRegRec(hCurKey, TVI_ROOT, wszData, FALSE);
        }
        else if(addings && !memcmp(wszName, wszProxyStubClsid32, sizeof(WCHAR[17])))
        {
            lenData = sizeof(WCHAR[MAX_LOAD_STRING]);

147
            RegQueryValueW(hCurKey, NULL, wszData, (LONG *)&lenData);
148 149
            RegCloseKey(hCurKey);

150
            RegOpenKeyW(HKEY_CLASSES_ROOT, wszCLSID, &hCurKey);
151 152

            lenName = sizeof(WCHAR[MAX_LOAD_STRING]);
153
            RegQueryValueW(hCurKey, NULL, wszName, (LONG *)&lenName);
154 155 156

            tvis.hParent = TVI_ROOT;
            wsprintfW(wszTree, wszFormat2, wszCLSID, wszName);
157
            tvis.hParent = TreeView_InsertItemW(details.hReg, &tvis);
158 159 160 161 162 163 164

            RegCloseKey(hCurKey);

            memmove(&wszData[6], wszData, sizeof(WCHAR[lenData]));
            memcpy(wszData, wszCLSID, sizeof(WCHAR[6]));
            wszData[5] = '\\';

165
            RegOpenKeyW(HKEY_CLASSES_ROOT, wszData, &hCurKey);
166 167 168

            CreateRegRec(hCurKey, tvis.hParent, &wszData[6], FALSE);

169
            SendMessageW(details.hReg, TVM_EXPAND, TVE_EXPAND, (LPARAM)tvis.hParent);
170 171 172 173 174 175
            tvis.hParent = parent;
        }
        else if(addings && !memcmp(wszName, wszTypeLib, sizeof(WCHAR[8])))
        {
            lenData = sizeof(WCHAR[MAX_LOAD_STRING]);

176
            RegQueryValueW(hCurKey, NULL, wszData, (LONG *)&lenData);
177 178
            RegCloseKey(hCurKey);

179
            RegOpenKeyW(HKEY_CLASSES_ROOT, wszTypeLib, &hCurKey);
180 181

            lenName = sizeof(WCHAR[MAX_LOAD_STRING]);
182
            RegQueryValueW(hCurKey, NULL, wszName, (LONG *)&lenName);
183 184 185

            tvis.hParent = TVI_ROOT;
            wsprintfW(wszTree, wszFormat2, wszTypeLib, wszName);
186
            tvis.hParent = TreeView_InsertItemW(details.hReg, &tvis);
187 188 189 190 191 192

            RegCloseKey(hCurKey);

            memmove(&wszData[8], wszData, sizeof(WCHAR[lenData]));
            memcpy(wszData, wszTypeLib, sizeof(WCHAR[8]));
            wszData[7] = '\\';
193
            RegOpenKeyW(HKEY_CLASSES_ROOT, wszData, &hCurKey);
194 195 196

            CreateRegRec(hCurKey, tvis.hParent, &wszData[8], FALSE);

197
            SendMessageW(details.hReg, TVM_EXPAND, TVE_EXPAND, (LPARAM)tvis.hParent);
198 199 200 201 202 203
            tvis.hParent = parent;
        }
        RegCloseKey(hCurKey);
    }
}

204
static void CreateReg(WCHAR *buffer)
205 206 207 208 209
{
    HKEY hKey;
    DWORD lenBuffer=-1, lastLenBuffer, lenTree;
    WCHAR *path;
    WCHAR wszTree[MAX_LOAD_STRING];
210
    TVINSERTSTRUCTW tvis;
211 212
    HTREEITEM addPlace = TVI_ROOT;

213 214 215
    U(tvis).item.mask = TVIF_TEXT;
    U(tvis).item.cchTextMax = MAX_LOAD_STRING;
    U(tvis).item.pszText = wszTree;
216
    tvis.hInsertAfter = TVI_LAST;
217 218 219 220 221 222 223 224 225 226 227
    tvis.hParent = TVI_ROOT;

    path = buffer;
    while(TRUE)
    {
        while(*path != '\\' && *path != '\0') path += 1;

        if(*path == '\\')
        {
            *path = '\0';

228
            if(RegOpenKeyW(HKEY_CLASSES_ROOT, buffer, &hKey) != ERROR_SUCCESS)
229 230 231
                return;

            lastLenBuffer = lenBuffer+1;
232
            lenBuffer = lstrlenW(buffer);
233 234 235 236 237
            *path = '\\';
            path += 1;

            lenTree = sizeof(WCHAR[MAX_LOAD_STRING]);

238
            if(RegQueryValueW(hKey, NULL, wszTree, (LONG *)&lenTree) == ERROR_SUCCESS)
239 240 241 242 243 244 245 246 247 248 249 250 251 252
            {
                memmove(&wszTree[lenBuffer-lastLenBuffer+3], wszTree,
                        sizeof(WCHAR[lenTree]));
                memcpy(wszTree, &buffer[lastLenBuffer],
                        sizeof(WCHAR[lenBuffer-lastLenBuffer]));

                if(lenTree == 1) wszTree[lenBuffer-lastLenBuffer] = '\0';
                else
                {
                    wszTree[lenBuffer-lastLenBuffer] = ' ';
                    wszTree[lenBuffer-lastLenBuffer+1] = '=';
                    wszTree[lenBuffer-lastLenBuffer+2] = ' ';
                }

253
                addPlace = TreeView_InsertItemW(details.hReg, &tvis);
254 255 256 257 258 259 260 261
            }

            tvis.hParent = addPlace;
            RegCloseKey(hKey);
        }
        else break;
    }

262
    if(RegOpenKeyW(HKEY_CLASSES_ROOT, buffer, &hKey) != ERROR_SUCCESS) return;
263

264
    CreateRegRec(hKey, addPlace, &buffer[lenBuffer+1], TRUE);
265 266 267

    RegCloseKey(hKey);

268 269
    SendMessageW(details.hReg, TVM_EXPAND, TVE_EXPAND, (LPARAM)addPlace);
    SendMessageW(details.hReg, TVM_ENSUREVISIBLE, 0, (LPARAM)addPlace);
270
}
271 272 273

void RefreshDetails(HTREEITEM item)
{
274
    TVITEMW tvi;
275 276 277 278 279
    WCHAR wszBuf[MAX_LOAD_STRING];
    WCHAR wszStaticText[MAX_LOAD_STRING];
    const WCHAR wszFormat[] = { '%','s','\n','%','s','\0' };
    BOOL show;

280
    memset(&tvi, 0, sizeof(TVITEMW));
281 282 283 284 285
    memset(&wszStaticText, 0, sizeof(WCHAR[MAX_LOAD_STRING]));
    tvi.mask = TVIF_TEXT;
    tvi.hItem = item;
    tvi.pszText = wszBuf;
    tvi.cchTextMax = MAX_LOAD_STRING;
286
    SendMessageW(globals.hTree, TVM_GETITEMW, 0, (LPARAM)&tvi);
287 288 289

    if(tvi.lParam)
        wsprintfW(wszStaticText, wszFormat, tvi.pszText, ((ITEM_INFO *)tvi.lParam)->clsid);
290
    else lstrcpyW(wszStaticText, tvi.pszText);
291

292
    SetWindowTextW(details.hStatic, wszStaticText);
293

294
    SendMessageW(details.hTab, TCM_SETCURSEL, 0, 0);
295 296 297

    if(tvi.lParam && ((ITEM_INFO *)tvi.lParam)->cFlag & SHOWALL)
    {
298
        if(SendMessageW(details.hTab, TCM_GETITEMCOUNT, 0, 0) == 1)
299
        {
300 301
            TCITEMW tci;
            memset(&tci, 0, sizeof(TCITEMW));
302 303
            tci.mask = TCIF_TEXT;
            tci.pszText = wszBuf;
304
            tci.cchTextMax = sizeof(wszBuf)/sizeof(wszBuf[0]);
305

306
            LoadStringW(globals.hMainInst, IDS_TAB_IMPL,
307
                    wszBuf, sizeof(wszBuf)/sizeof(wszBuf[0]));
308
            SendMessageW(details.hTab, TCM_INSERTITEMW, 1, (LPARAM)&tci);
309

310
            LoadStringW(globals.hMainInst, IDS_TAB_ACTIV,
311
                    wszBuf, sizeof(wszBuf)/sizeof(wszBuf[0]));
312
            SendMessageW(details.hTab, TCM_INSERTITEMW, 2, (LPARAM)&tci);
313 314 315 316
        }
    }
    else
    {
317 318
        SendMessageW(details.hTab, TCM_DELETEITEM, 2, 0);
        SendMessageW(details.hTab, TCM_DELETEITEM, 1, 0);
319 320 321 322 323 324
    }

    show = CreateRegPath(item, wszBuf, MAX_LOAD_STRING);
    ShowWindow(details.hTab, show ? SW_SHOW : SW_HIDE);

    /* FIXME Next line deals with TreeView_EnsureVisible bug */
325 326 327
    SendMessageW(details.hReg, TVM_ENSUREVISIBLE, 0,
            SendMessageW(details.hReg, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)TVI_ROOT));
    SendMessageW(details.hReg, TVM_DELETEITEM, 0, (LPARAM)TVI_ROOT);
328
    if(show) CreateReg(wszBuf);
329 330
}

331
static void CreateTabCtrl(HWND hWnd)
332
{
333
    TCITEMW tci;
334 335
    WCHAR buffer[MAX_LOAD_STRING];

336
    memset(&tci, 0, sizeof(TCITEMW));
337 338
    tci.mask = TCIF_TEXT;
    tci.pszText = buffer;
339
    tci.cchTextMax = sizeof(buffer)/sizeof(buffer[0]);
340

341
    details.hTab = CreateWindowW(WC_TABCONTROLW, NULL, WS_CHILD|WS_VISIBLE,
342 343 344
            0, 0, 0, 0, hWnd, (HMENU)TAB_WINDOW, globals.hMainInst, NULL);
    ShowWindow(details.hTab, SW_HIDE);

345 346
    LoadStringW(globals.hMainInst, IDS_TAB_REG, buffer, sizeof(buffer)/sizeof(buffer[0]));
    SendMessageW(details.hTab, TCM_INSERTITEMW, 0, (LPARAM)&tci);
347

348
    details.hReg = CreateWindowExW(WS_EX_CLIENTEDGE, WC_TREEVIEWW, NULL,
349 350 351 352
            WS_CHILD|WS_VISIBLE|TVS_HASLINES,
            0, 0, 0, 0, details.hTab, NULL, globals.hMainInst, NULL);
}

353
static LRESULT CALLBACK DetailsProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
354 355 356 357 358 359 360 361 362
{
    int sel;

    switch(uMsg)
    {
        case WM_CREATE:
            {
                const WCHAR wszStatic[] = { 'S','t','a','t','i','c','\0' };

363
                details.hStatic = CreateWindowW(wszStatic, NULL, WS_CHILD|WS_VISIBLE,
364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
                        0, 0, 0, 0, hWnd, NULL, globals.hMainInst, NULL);
                CreateTabCtrl(hWnd);
            }
            break;
        case WM_SIZE:
            MoveWindow(details.hStatic, 0, 0, LOWORD(lParam), 40, TRUE);
            MoveWindow(details.hTab, 3, 40, LOWORD(lParam)-6, HIWORD(lParam)-43, TRUE);
            MoveWindow(details.hReg, 10, 34, LOWORD(lParam)-26,
                    HIWORD(lParam)-87, TRUE);
            break;
        case WM_NOTIFY:
            if((int)wParam != TAB_WINDOW) break;
            switch(((LPNMHDR)lParam)->code)
            {
                case TCN_SELCHANGE:
                    ShowWindow(details.hReg, SW_HIDE);
380
                    sel = SendMessageW(details.hTab, TCM_GETCURSEL, 0, 0);
381 382 383 384 385 386

                    if(sel==0) ShowWindow(details.hReg, SW_SHOW);
                    break;
            }
            break;
        default:
387
            return DefWindowProcW(hWnd, uMsg, wParam, lParam);
388 389 390 391 392 393
    }
    return 0;
}

HWND CreateDetailsWindow(HINSTANCE hInst)
{
394
    WNDCLASSW wcd;
395
    const WCHAR wszDetailsClass[] = { 'D','E','T','A','I','L','S','\0' };
396 397

    memset(&wcd, 0, sizeof(WNDCLASSW));
398 399 400 401
    wcd.lpfnWndProc = DetailsProc;
    wcd.lpszClassName = wszDetailsClass;
    wcd.hbrBackground = (HBRUSH)COLOR_WINDOW;

402
    if(!RegisterClassW(&wcd)) return NULL;
403

404
    globals.hDetails = CreateWindowExW(WS_EX_CLIENTEDGE, wszDetailsClass, NULL,
405 406 407 408
            WS_CHILD|WS_VISIBLE, 0, 0, 0, 0, globals.hPaneWnd, NULL, hInst, NULL);

    return globals.hDetails;
}