oleview: Added more fields to TypeLib Viewer tree.
[wine/gsoc_dplay.git] / programs / oleview / typelib.c
blob9eab7c444f14729d676f8c7ecf9961cd2379897c
1 /*
2 * OleView (typelib.c)
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
21 #include "main.h"
23 #include "wine/debug.h"
25 WINE_DEFAULT_DEBUG_CHANNEL(oleview);
27 TYPELIB typelib;
28 static const WCHAR wszTypeLib[] = { 'T','Y','P','E','L','I','B','\0' };
30 static const WCHAR wszFailed[] = { '<','f','a','i','l','e','d','>','\0' };
31 static const WCHAR wszSpace[] = { ' ','\0' };
32 static const WCHAR wszAsterix[] = { '*','\0' };
34 static const WCHAR wszVT_BOOL[]
35 = { 'V','A','R','I','A','N','T','_','B','O','O','L','\0' };
36 static const WCHAR wszVT_UI1[]
37 = { 'u','n','s','i','g','n','e','d',' ','c','h','a','r','\0' };
38 static const WCHAR wszVT_UI2[]
39 = { 'u','n','s','i','g','n','e','d',' ','s','h','o','r','t','\0' };
40 static const WCHAR wszVT_UI4[]
41 = { 'u','n','s','i','g','n','e','d',' ','l','o','n','g','\0' };
42 static const WCHAR wszVT_UI8[] = { 'u','i','n','t','6','4','\0' };
43 static const WCHAR wszVT_UINT[]
44 = { 'u','n','s','i','g','n','e','d',' ','i','n','t','\0' };
45 static const WCHAR wszVT_I1[] = { 'c','h','a','r','\0' };
46 static const WCHAR wszVT_I2[] = { 's','h','o','r','t','\0' };
47 static const WCHAR wszVT_I4[] = { 'l','o','n','g','\0' };
48 static const WCHAR wszVT_I8[] = { 'i','n','t','6','4','\0' };
49 static const WCHAR wszVT_R4[] = { 's','i','n','g','l','e','\0' };
50 static const WCHAR wszVT_INT[] = { 'i','n','t','\0' };
51 static const WCHAR wszVT_BSTR[] = { 'B','S','T','R','\0' };
52 static const WCHAR wszVT_CY[] = { 'C','U','R','R','E','N','C','Y','\0' };
53 static const WCHAR wszVT_VARIANT[] = { 'V','A','R','I','A','N','T','\0' };
54 static const WCHAR wszVT_VOID[] = { 'v','o','i','d','\0' };
55 static const WCHAR wszVT_ERROR[] = { 'S','C','O','D','E','\0' };
56 static const WCHAR wszVT_LPSTR[] = { 'L','P','S','T','R','\0' };
57 static const WCHAR wszVT_LPWSTR[] = { 'L','P','W','S','T','R','\0' };
59 void AddToStrW(WCHAR *wszDest, const WCHAR *wszSource)
61 lstrcpyW(&wszDest[lstrlenW(wszDest)], wszSource);
64 void CreateTypeInfo(WCHAR *wszAddTo, WCHAR *wszAddAfter, TYPEDESC tdesc, ITypeInfo *pTypeInfo)
66 int i;
67 BSTR bstrData;
68 HRESULT hRes;
69 ITypeInfo *pRefTypeInfo;
70 WCHAR wszBuf[MAX_LOAD_STRING];
71 WCHAR wszFormat[] = { '[','%','l','u',']','\0' };
73 switch(tdesc.vt&VT_TYPEMASK)
75 #define VTADDTOSTR(x) case x:\
76 AddToStrW(wszAddTo, wsz##x);\
77 break
78 VTADDTOSTR(VT_BOOL);
79 VTADDTOSTR(VT_UI1);
80 VTADDTOSTR(VT_UI2);
81 VTADDTOSTR(VT_UI4);
82 VTADDTOSTR(VT_UI8);
83 VTADDTOSTR(VT_UINT);
84 VTADDTOSTR(VT_I1);
85 VTADDTOSTR(VT_I2);
86 VTADDTOSTR(VT_I4);
87 VTADDTOSTR(VT_I8);
88 VTADDTOSTR(VT_R4);
89 VTADDTOSTR(VT_INT);
90 VTADDTOSTR(VT_BSTR);
91 VTADDTOSTR(VT_CY);
92 VTADDTOSTR(VT_VARIANT);
93 VTADDTOSTR(VT_VOID);
94 VTADDTOSTR(VT_ERROR);
95 VTADDTOSTR(VT_LPSTR);
96 VTADDTOSTR(VT_LPWSTR);
97 case VT_CARRAY:
98 for(i=0; i<U(tdesc).lpadesc->cDims; i++)
100 wsprintfW(wszBuf, wszFormat, U(tdesc).lpadesc->rgbounds[i].cElements);
101 AddToStrW(wszAddAfter, wszBuf);
103 CreateTypeInfo(wszAddTo, wszAddAfter, U(tdesc).lpadesc->tdescElem, pTypeInfo);
104 break;
105 case VT_PTR:
106 CreateTypeInfo(wszAddTo, wszAddAfter, *U(tdesc).lptdesc, pTypeInfo);
107 AddToStrW(wszAddTo, wszAsterix);
108 break;
109 case VT_USERDEFINED:
110 hRes = ITypeInfo_GetRefTypeInfo(pTypeInfo,
111 U(tdesc).hreftype, &pRefTypeInfo);
112 if(SUCCEEDED(hRes))
114 ITypeInfo_GetDocumentation(pRefTypeInfo, MEMBERID_NIL,
115 &bstrData, NULL, NULL, NULL);
116 AddToStrW(wszAddTo, bstrData);
117 SysFreeString(bstrData);
118 ITypeInfo_Release(pRefTypeInfo);
120 else AddToStrW(wszAddTo, wszFailed);
121 break;
122 default:
123 WINE_FIXME("tdesc.vt&VT_TYPEMASK == %d not supported\n",
124 tdesc.vt&VT_TYPEMASK);
128 int EnumVars(ITypeInfo *pTypeInfo, int cVars, HTREEITEM hParent)
130 int i;
131 TVINSERTSTRUCT tvis;
132 VARDESC *pVarDesc;
133 BSTR bstrName;
134 WCHAR wszText[MAX_LOAD_STRING];
135 WCHAR wszAfter[MAX_LOAD_STRING];
137 U(tvis).item.mask = TVIF_TEXT;
138 U(tvis).item.cchTextMax = MAX_LOAD_STRING;
139 U(tvis).item.pszText = wszText;
140 tvis.hInsertAfter = (HTREEITEM)TVI_LAST;
141 tvis.hParent = hParent;
143 for(i=0; i<cVars; i++)
145 if(FAILED(ITypeInfo_GetVarDesc(pTypeInfo, i, &pVarDesc))) continue;
146 if(FAILED(ITypeInfo_GetDocumentation(pTypeInfo, pVarDesc->memid, &bstrName,
147 NULL, NULL, NULL))) continue;
149 memset(wszText, 0, sizeof(wszText));
150 memset(wszAfter, 0, sizeof(wszAfter));
151 CreateTypeInfo(wszText, wszAfter, pVarDesc->elemdescVar.tdesc, pTypeInfo);
152 AddToStrW(wszText, wszSpace);
153 AddToStrW(wszText, bstrName);
154 AddToStrW(wszText, wszAfter);
156 SendMessage(typelib.hTree, TVM_INSERTITEM, 0, (LPARAM)&tvis);
157 SysFreeString(bstrName);
158 ITypeInfo_ReleaseVarDesc(pTypeInfo, pVarDesc);
161 return 0;
164 int EnumFuncs(ITypeInfo *pTypeInfo, int cFuncs, HTREEITEM hParent)
166 int i;
167 TVINSERTSTRUCT tvis;
168 FUNCDESC *pFuncDesc;
169 BSTR bstrName;
171 U(tvis).item.mask = TVIF_TEXT;
172 tvis.hInsertAfter = (HTREEITEM)TVI_LAST;
173 tvis.hParent = hParent;
175 for(i=0; i<cFuncs; i++)
177 if(FAILED(ITypeInfo_GetFuncDesc(pTypeInfo, i, &pFuncDesc))) continue;
178 if(FAILED(ITypeInfo_GetDocumentation(pTypeInfo, pFuncDesc->memid, &bstrName,
179 NULL, NULL, NULL))) continue;
181 U(tvis).item.cchTextMax = SysStringLen(bstrName);
182 U(tvis).item.pszText = bstrName;
184 SendMessage(typelib.hTree, TVM_INSERTITEM, 0, (LPARAM)&tvis);
185 SysFreeString(bstrName);
186 ITypeInfo_ReleaseFuncDesc(pTypeInfo, pFuncDesc);
189 return 0;
192 int EnumImplTypes(ITypeInfo *pTypeInfo, int cImplTypes, HTREEITEM hParent)
194 int i;
195 TVINSERTSTRUCT tvis;
196 ITypeInfo *pRefTypeInfo;
197 HREFTYPE hRefType;
198 TYPEATTR *pTypeAttr;
199 BSTR bstrName;
200 WCHAR wszInheritedInterfaces[MAX_LOAD_STRING];
202 if(!cImplTypes) return 0;
204 LoadString(globals.hMainInst, IDS_INHERITINTERFACES, wszInheritedInterfaces,
205 sizeof(WCHAR[MAX_LOAD_STRING]));
207 U(tvis).item.mask = TVIF_TEXT;
208 U(tvis).item.cchTextMax = MAX_LOAD_STRING;
209 U(tvis).item.pszText = wszInheritedInterfaces;
210 tvis.hInsertAfter = (HTREEITEM)TVI_LAST;
211 tvis.hParent = hParent;
213 tvis.hParent = TreeView_InsertItem(typelib.hTree, &tvis);
215 for(i=0; i<cImplTypes; i++)
217 if(FAILED(ITypeInfo_GetRefTypeOfImplType(pTypeInfo, i, &hRefType))) continue;
218 if(FAILED(ITypeInfo_GetRefTypeInfo(pTypeInfo, hRefType, &pRefTypeInfo)))
219 continue;
220 if(FAILED(ITypeInfo_GetDocumentation(pRefTypeInfo, MEMBERID_NIL, &bstrName,
221 NULL, NULL, NULL))) continue;
222 if(FAILED(ITypeInfo_GetTypeAttr(pRefTypeInfo, &pTypeAttr))) continue;
224 U(tvis).item.cchTextMax = SysStringLen(bstrName);
225 U(tvis).item.pszText = bstrName;
227 hParent = TreeView_InsertItem(typelib.hTree, &tvis);
228 EnumVars(pRefTypeInfo, pTypeAttr->cVars, hParent);
229 EnumFuncs(pRefTypeInfo, pTypeAttr->cFuncs, hParent);
230 EnumImplTypes(pRefTypeInfo, pTypeAttr->cImplTypes, hParent);
232 SysFreeString(bstrName);
233 ITypeInfo_ReleaseTypeAttr(pRefTypeInfo, pTypeAttr);
234 ITypeInfo_Release(pRefTypeInfo);
237 return 0;
240 int PopulateTree(void)
242 TVINSERTSTRUCT tvis;
243 ITypeLib *pTypeLib;
244 ITypeInfo *pTypeInfo, *pRefTypeInfo;
245 HREFTYPE hRefType;
246 TYPEATTR *pTypeAttr;
247 INT count, i;
248 BSTR bstrName;
249 BSTR bstrData;
250 WCHAR wszText[MAX_LOAD_STRING];
251 WCHAR wszAfter[MAX_LOAD_STRING];
252 HRESULT hRes;
253 HTREEITEM hParent;
255 const WCHAR wszFormat[] = { '%','s',' ','(','%','s',')','\0' };
257 const WCHAR wszTKIND_ENUM[] = { 't','y','p','e','d','e','f',' ','e','n','u','m',' ','\0' };
258 const WCHAR wszTKIND_RECORD[]
259 = { 't','y','p','e','d','e','f',' ','s','t','r','u','c','t',' ','\0' };
260 const WCHAR wszTKIND_MODULE[] = { 'm','o','d','u','l','e',' ','\0' };
261 const WCHAR wszTKIND_INTERFACE[] = { 'i','n','t','e','r','f','a','c','e',' ','\0' };
262 const WCHAR wszTKIND_DISPATCH[]
263 = { 'd','i','s','p','i','n','t','e','r','f','a','c','e',' ','\0' };
264 const WCHAR wszTKIND_COCLASS[] = { 'c','o','c','l','a','s','s',' ','\0' };
265 const WCHAR wszTKIND_ALIAS[] = { 't','y','p','e','d','e','f',' ','\0' };
266 const WCHAR wszTKIND_UNION[]
267 = { 't','y','p','e','d','e','f',' ','u','n','i','o','n',' ','\0' };
269 U(tvis).item.mask = TVIF_TEXT;
270 U(tvis).item.cchTextMax = MAX_LOAD_STRING;
271 U(tvis).item.pszText = wszText;
272 tvis.hInsertAfter = (HTREEITEM)TVI_LAST;
273 tvis.hParent = TVI_ROOT;
275 if(FAILED((hRes = LoadTypeLib(typelib.wszFileName, &pTypeLib))))
277 WCHAR wszMessage[MAX_LOAD_STRING];
278 WCHAR wszError[MAX_LOAD_STRING];
280 LoadString(globals.hMainInst, IDS_ERROR_LOADTYPELIB,
281 wszError, sizeof(WCHAR[MAX_LOAD_STRING]));
282 wsprintfW(wszMessage, wszError, typelib.wszFileName, hRes);
283 MessageBox(globals.hMainWnd, wszMessage, NULL, MB_OK|MB_ICONEXCLAMATION);
284 return 1;
286 count = ITypeLib_GetTypeInfoCount(pTypeLib);
288 ITypeLib_GetDocumentation(pTypeLib, -1, &bstrName, &bstrData, NULL, NULL);
289 wsprintfW(wszText, wszFormat, bstrName, bstrData);
290 SysFreeString(bstrName);
291 SysFreeString(bstrData);
292 tvis.hParent = (HTREEITEM)SendMessage(typelib.hTree,
293 TVM_INSERTITEM, 0, (LPARAM)&tvis);
295 for(i=0; i<count; i++)
297 ITypeLib_GetTypeInfo(pTypeLib, i, &pTypeInfo);
299 ITypeInfo_GetDocumentation(pTypeInfo, MEMBERID_NIL, &bstrName, NULL, NULL, NULL);
300 ITypeInfo_GetTypeAttr(pTypeInfo, &pTypeAttr);
302 memset(wszText, 0, sizeof(wszText));
303 memset(wszAfter, 0, sizeof(wszAfter));
304 switch(pTypeAttr->typekind)
306 #define TKINDADDTOSTR(x) case x:\
307 AddToStrW(wszText, wsz##x);\
308 AddToStrW(wszText, bstrName);\
309 break
310 TKINDADDTOSTR(TKIND_ENUM);
311 TKINDADDTOSTR(TKIND_RECORD);
312 TKINDADDTOSTR(TKIND_MODULE);
313 TKINDADDTOSTR(TKIND_INTERFACE);
314 TKINDADDTOSTR(TKIND_COCLASS);
315 TKINDADDTOSTR(TKIND_UNION);
316 case TKIND_DISPATCH:
317 AddToStrW(wszText, wszTKIND_DISPATCH);
318 AddToStrW(wszText, bstrName);
319 if(SUCCEEDED(ITypeInfo_GetRefTypeOfImplType(pTypeInfo, -1, &hRefType)))
321 hParent = TreeView_InsertItem(typelib.hTree, &tvis);
322 EnumImplTypes(pTypeInfo, pTypeAttr->cImplTypes, hParent);
323 memset(wszText, 0, sizeof(wszText));
325 ITypeInfo_GetRefTypeInfo(pTypeInfo, hRefType, &pRefTypeInfo);
326 ITypeInfo_GetDocumentation(pRefTypeInfo, MEMBERID_NIL, &bstrName,
327 NULL, NULL, NULL);
328 AddToStrW(wszText, wszTKIND_INTERFACE);
329 AddToStrW(wszText, bstrName);
330 ITypeInfo_Release(pRefTypeInfo);
332 break;
333 case TKIND_ALIAS:
334 AddToStrW(wszText, wszTKIND_ALIAS);
335 CreateTypeInfo(wszText, wszAfter, pTypeAttr->tdescAlias, pTypeInfo);
336 AddToStrW(wszText, wszSpace);
337 AddToStrW(wszText, bstrName);
338 AddToStrW(wszText, wszAfter);
339 break;
340 default:
341 lstrcpyW(wszText, bstrName);
342 WINE_FIXME("pTypeAttr->typekind == %d\n not supported",
343 pTypeAttr->typekind);
345 hParent = TreeView_InsertItem(typelib.hTree, &tvis);
347 EnumVars(pTypeInfo, pTypeAttr->cVars, hParent);
348 EnumFuncs(pTypeInfo, pTypeAttr->cFuncs, hParent);
349 EnumImplTypes(pTypeInfo, pTypeAttr->cImplTypes, hParent);
351 ITypeInfo_ReleaseTypeAttr(pTypeInfo, pTypeAttr);
352 ITypeInfo_Release(pTypeInfo);
353 SysFreeString(bstrName);
355 SendMessage(typelib.hTree, TVM_EXPAND, TVE_EXPAND, (LPARAM)tvis.hParent);
357 ITypeLib_Release(pTypeLib);
358 return 0;
361 void TypeLibResizeChild(void)
363 RECT client, stat;
365 MoveWindow(typelib.hStatusBar, 0, 0, 0, 0, TRUE);
367 if(IsWindowVisible(typelib.hStatusBar))
368 GetClientRect(typelib.hStatusBar, &stat);
369 else stat.bottom = 0;
371 GetClientRect(globals.hTypeLibWnd, &client);
372 MoveWindow(typelib.hPaneWnd, 0, 0,
373 client.right, client.bottom-stat.bottom, TRUE);
376 void TypeLibMenuCommand(WPARAM wParam, HWND hWnd)
378 BOOL vis;
380 switch(wParam)
382 case IDM_STATUSBAR:
383 vis = IsWindowVisible(typelib.hStatusBar);
384 ShowWindow(typelib.hStatusBar, vis ? SW_HIDE : SW_SHOW);
385 CheckMenuItem(GetMenu(hWnd), LOWORD(wParam),
386 vis ? MF_UNCHECKED : MF_CHECKED);
387 TypeLibResizeChild();
388 break;
389 case IDM_CLOSE:
390 DestroyWindow(hWnd);
391 break;
395 void UpdateTypeLibStatusBar(int itemID)
397 WCHAR info[MAX_LOAD_STRING];
399 if(!LoadString(globals.hMainInst, itemID, info, sizeof(WCHAR[MAX_LOAD_STRING])))
400 LoadString(globals.hMainInst, IDS_READY, info, sizeof(WCHAR[MAX_LOAD_STRING]));
402 SendMessage(typelib.hStatusBar, SB_SETTEXT, 0, (LPARAM)info);
405 LRESULT CALLBACK TypeLibProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
407 switch(uMsg)
409 case WM_CREATE:
411 if(!CreatePanedWindow(hWnd, &typelib.hPaneWnd, globals.hMainInst))
412 DestroyWindow(hWnd);
413 typelib.hTree = CreateWindowEx(WS_EX_CLIENTEDGE, WC_TREEVIEW, NULL,
414 WS_CHILD|WS_VISIBLE|TVS_HASLINES|TVS_HASBUTTONS|TVS_LINESATROOT,
415 0, 0, 0, 0, typelib.hPaneWnd, NULL, globals.hMainInst, NULL);
416 typelib.hEdit = CreateWindowEx(WS_EX_CLIENTEDGE, WC_EDIT, NULL,
417 WS_CHILD|WS_VISIBLE|ES_MULTILINE|ES_READONLY|WS_HSCROLL|WS_VSCROLL,
418 0, 0, 0, 0, typelib.hPaneWnd, NULL, globals.hMainInst, NULL);
420 SetLeft(typelib.hPaneWnd, typelib.hTree);
421 SetRight(typelib.hPaneWnd, typelib.hEdit);
423 if(PopulateTree()) DestroyWindow(hWnd);
424 else SetFocus(typelib.hTree);
425 break;
427 case WM_COMMAND:
428 TypeLibMenuCommand(LOWORD(wParam), hWnd);
429 case WM_MENUSELECT:
430 UpdateTypeLibStatusBar(LOWORD(wParam));
431 break;
432 case WM_SETFOCUS:
433 SetFocus(typelib.hTree);
434 break;
435 case WM_SIZE:
436 if(wParam == SIZE_MINIMIZED) break;
437 TypeLibResizeChild();
438 break;
439 case WM_DESTROY:
440 break;
441 default:
442 return DefWindowProc(hWnd, uMsg, wParam, lParam);
444 return 0;
447 BOOL TypeLibRegisterClass(void)
449 WNDCLASS wcc;
451 memset(&wcc, 0, sizeof(WNDCLASS));
452 wcc.lpfnWndProc = TypeLibProc;
453 wcc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
454 wcc.lpszMenuName = MAKEINTRESOURCE(IDM_TYPELIB);
455 wcc.lpszClassName = wszTypeLib;
457 if(!RegisterClass(&wcc))
458 return FALSE;
460 return TRUE;
463 BOOL CreateTypeLibWindow(HINSTANCE hInst, WCHAR *wszFileName)
465 WCHAR wszTitle[MAX_LOAD_STRING];
466 LoadString(hInst, IDS_TYPELIBTITLE, wszTitle, sizeof(WCHAR[MAX_LOAD_STRING]));
468 if(wszFileName) lstrcpyW(typelib.wszFileName, wszFileName);
469 else
471 TVITEM tvi;
473 memset(&tvi, 0, sizeof(TVITEM));
474 tvi.hItem = TreeView_GetSelection(globals.hTree);
476 SendMessage(globals.hTree, TVM_GETITEM, 0, (LPARAM)&tvi);
477 lstrcpyW(typelib.wszFileName, ((ITEM_INFO*)tvi.lParam)->path);
480 globals.hTypeLibWnd = CreateWindow(wszTypeLib, wszTitle,
481 WS_OVERLAPPEDWINDOW|WS_VISIBLE,
482 CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, NULL, NULL, hInst, NULL);
483 if(!globals.hTypeLibWnd) return FALSE;
485 typelib.hStatusBar = CreateStatusWindow(WS_VISIBLE|WS_CHILD,
486 (LPWSTR)wszTitle, globals.hTypeLibWnd, 0);
488 TypeLibResizeChild();
489 return TRUE;