BROWSE.CPP

/************************************************************************* 
**
** This is a part of the Microsoft Source Code Samples.
**
** Copyright 1992 - 1998 Microsoft Corporation. All rights reserved.
**
** This source code is only intended as a supplement to Microsoft Development
** Tools and/or WinHelp documentation. See these sources for detailed
** information regarding the Microsoft samples programs.
**
** Type Library Browser
**
** browseex.cpp
**
** Written by Microsoft Product Support Services, Windows Developer Support
**
*************************************************************************/

#include <windows.h>
#include <windowsx.h>
#ifdef WIN16
#include <ole2.h>
#include <compobj.h>
#include <dispatch.h>
#include <variant.h>
#include <olenls.h>
#include <commdlg.h>
#endif
#include "resource.h"
#include "browse.h"
#include "invhelp.h"

CBrowseApp BrowseApp; // Application

int APIENTRY WinMain (HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASS wc;
HRESULT hr;

#ifdef WIN16
// It is recommended that all 16 bit OLE applications set
// their message queue size to 96. This improves the capacity
// and performance of OLE's LRPC mechanism.
int cMsg = 96; // Recommend msg queue size for OLE
while (cMsg && !SetMessageQueue(cMsg)) // take largest size we can get.
cMsg -= 8;
if (!cMsg)
return -1; // ERROR: we got no message queue
#endif

// Register class for the dialog that is the main window.
wc.style = 0;
wc.lpfnWndProc = DefDlgProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = DLGWINDOWEXTRA;
wc.hInstance = hinst;
wc.hIcon = LoadIcon(hinst, MAKEINTRESOURCE(ID_ICON));
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = HBRUSH(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = TEXT("DlgClass");
RegisterClass(&wc);

hr = OleInitialize(NULL);
if FAILED(hr)
{
MessageBox(NULL, TEXT("Could not Intialize OLE"), TEXT("Error"), MB_ICONEXCLAMATION|MB_OK);
return 0;
}
DialogBox(hinst, MAKEINTRESOURCE(IDD_MAINDIALOG), NULL, (DLGPROC)MainDialogFunc);
OleUninitialize();

return 0;
}


BOOL CALLBACK MainDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
HRESULT hr;

switch (msg)
{
case WM_INITDIALOG:
BrowseApp.Init(hwndDlg);
return FALSE;

case WM_COMMAND:
switch(GET_WM_COMMAND_ID(wParam,lParam))
{
case IDM_EXIT:
case IDCANCEL:
BrowseApp.Cleanup();
EndDialog(hwndDlg, IDOK);
CoFreeUnusedLibraries();
return TRUE;

case IDM_FILEOPEN:
hr = BrowseApp.BrowseTypeLibrary();
if (FAILED(hr))
MessageBox(hwndDlg, TEXT("Failed to browse type library"), TEXT("Error"), MB_ICONEXCLAMATION|MB_OK);
return TRUE;

case IDC_TYPEINFOSLIST:
switch (GET_WM_COMMAND_CMD(wParam, lParam))
{
case LBN_SELCHANGE:
hr = BrowseApp.ChangeTypeInfosSelection();
if (FAILED(hr))
MessageBox(hwndDlg, TEXT("Failed to get TypeInfo information"), TEXT("Error"), MB_ICONEXCLAMATION|MB_OK);
return TRUE;
}
break;

case IDC_ELEMENTSLIST:
switch (GET_WM_COMMAND_CMD(wParam, lParam))
{
case LBN_SELCHANGE:
hr = BrowseApp.ChangeElementsSelection();
if (FAILED(hr))
MessageBox(hwndDlg, TEXT("Failed to get Element information"), TEXT("Error"), MB_ICONEXCLAMATION|MB_OK);
return TRUE;
}
break;

case IDC_PARAMETERSLIST:
switch (GET_WM_COMMAND_CMD(wParam, lParam))
{
case LBN_SELCHANGE:
hr = BrowseApp.ChangeParametersSelection();
if (FAILED(hr))
MessageBox(hwndDlg, TEXT("Failed to get Parameter information"), TEXT("Error"), MB_ICONEXCLAMATION|MB_OK);
return TRUE;
}
break;

case IDC_ELEM_OPEN_HELPFILE:
BrowseApp.OpenElementHelpFile();
return TRUE;

}
break;
}
return FALSE;
}

/*
* CBrowseApp::BrowseTypeLibrary
*
* Purpose:
* Prompts user for type library. Fills the TypeInfo list with the TypeInfos of
* the type library.
*
*/
HRESULT CBrowseApp::BrowseTypeLibrary()
{
OPENFILENAME ofn;
TCHAR szFileName[128];
BOOL bRes;
VARIANT vRet;
HRESULT hr;
HCURSOR hcursorOld;
LPDISPATCH pdispBrowseHelper = NULL;
LPDISPATCH pdispTypeLibrary = NULL;
LPDISPATCH pdispTypeInfos = NULL;
TCHAR szTemp[100];

// Prompt user for type library
szFileName[0] = '\0';
_fmemset(&ofn, 0, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = m_hwndMain;
ofn.lpstrFile = szFileName;
ofn.nMaxFile = sizeof(szFileName);
ofn.hInstance = m_hinst;
ofn.lpstrFilter = TEXT("Type Libraries *.tlb,*.olb\0*.tlb;*.olb\0All Files *.*\0*.*\0\0");
ofn.nFilterIndex = 1;
ofn.Flags= OFN_FILEMUSTEXIST;
bRes = GetOpenFileName(&ofn);
if (!bRes)
return S_FALSE;

// Empty lists and clear fields.
EmptyList(GetDlgItem(m_hwndMain, IDC_TYPEINFOSLIST));
EmptyList(GetDlgItem(m_hwndMain, IDC_ELEMENTSLIST));
EmptyList(GetDlgItem(m_hwndMain, IDC_PARAMETERSLIST));
ClearTypeLibStaticFields();
ClearTypeInfoStaticFields();
ClearElementStaticFields();
ClearParamStaticFields();
EnableWindow(GetDlgItem(m_hwndMain, IDC_ELEM_OPEN_HELPFILE), FALSE);

hcursorOld = SetCursor(LoadCursor(NULL, IDC_WAIT));
// Create BrowseHelper object
hr = CreateObject(OLESTR("BrowseHelper.Browser"), &pdispBrowseHelper);
if (FAILED(hr))
{
MessageBox(m_hwndMain,
TEXT("Failed to create BrowseHelper object. Build and register the BROWSEH sample"),
TEXT("Error"), MB_ICONEXCLAMATION|MB_OK);
goto error;
}

// Invoke IBrowseHelper.BrowseTypeLibrary(szFileName). Returns ITypeLibrary.
hr = Invoke(pdispBrowseHelper, DISPATCH_METHOD, &vRet, NULL, NULL,
OLESTR("BrowseTypeLibrary"), TEXT("s"), (LPOLESTR)TO_OLE_STRING(szFileName));
if (FAILED(hr))
goto error;
pdispTypeLibrary = V_DISPATCH(&vRet);

// Invoke ITypeLibrary.Name. Returns BSTR.
hr = Invoke(pdispTypeLibrary, DISPATCH_PROPERTYGET, &vRet, NULL, NULL,
OLESTR("Name"), TEXT(""));
if (FAILED(hr))
goto error;
if (NULL != V_BSTR(&vRet))
SetDlgItemText(m_hwndMain, IDC_TYPELIB_NAME, FROM_OLE_STRING(V_BSTR(&vRet)));
VariantClear(&vRet);

// Invoke ITypeLibrary.HelpFile. Returns BSTR.
hr = Invoke(pdispTypeLibrary, DISPATCH_PROPERTYGET, &vRet, NULL, NULL,
OLESTR("HelpFile"), TEXT(""));
if (FAILED(hr))
goto error;
if (NULL != V_BSTR(&vRet))
SetDlgItemText(m_hwndMain, IDC_TYPELIB_HELPFILE, FROM_OLE_STRING(V_BSTR(&vRet)));
if (NULL == V_BSTR(&vRet))
m_szHelpFile[0] = '\0';
else lstrcpy(m_szHelpFile, FROM_OLE_STRING(V_BSTR(&vRet)));
VariantClear(&vRet);

// Invoke ITypeLibrary.Documentation. Returns BSTR.
hr = Invoke(pdispTypeLibrary, DISPATCH_PROPERTYGET, &vRet, NULL, NULL,
OLESTR("Documentation"), TEXT(""));
if (FAILED(hr))
goto error;
if (V_BSTR(&vRet) != NULL) //NULL is a valid value for a BSTR
SetDlgItemText(m_hwndMain, IDC_TYPELIB_DOC, FROM_OLE_STRING(V_BSTR(&vRet)));
VariantClear(&vRet);

// Invoke ITypeLibrary.LocaleID. Returns VT_I4.
hr = Invoke(pdispTypeLibrary, DISPATCH_PROPERTYGET, &vRet, NULL, NULL,
OLESTR("LocaleID"), TEXT(""));
if (FAILED(hr))
goto error;
wsprintf(szTemp, TEXT("0x%lx"), V_I4(&vRet));
SetDlgItemText(m_hwndMain, IDC_TYPELIB_LCID, szTemp);

// Invoke ITypeLibrary.MajorVersion. Returns VT_I2.
hr = Invoke(pdispTypeLibrary, DISPATCH_PROPERTYGET, &vRet, NULL, NULL,
OLESTR("MajorVersion"), TEXT(""));
if (FAILED(hr))
goto error;
wsprintf(szTemp, TEXT("%d"), V_I2(&vRet));
// Invoke ITypeLibrary.MinorVersion. Returns VT_I2.
hr = Invoke(pdispTypeLibrary, DISPATCH_PROPERTYGET, &vRet, NULL, NULL,
OLESTR("MinorVersion"), TEXT(""));
if (FAILED(hr))
goto error;
wsprintf(szTemp, TEXT("%s.%d"), (LPSTR)szTemp, V_I2(&vRet));
SetDlgItemText(m_hwndMain, IDC_TYPELIB_VERSION, szTemp);

// Invoke ITypeLibrary.TypeInfos. Returns ICollection of ITypeInfo.
hr = Invoke(pdispTypeLibrary, DISPATCH_PROPERTYGET, &vRet, NULL, NULL,
OLESTR("TypeInfos"), TEXT(""));
if (FAILED(hr))
goto error;
pdispTypeInfos = V_DISPATCH(&vRet);

// Load TypeInfo list with the names of the type infos.
hr = LoadList(pdispTypeInfos, IDC_TYPEINFOSLIST);
if (FAILED(hr))
goto error;

pdispBrowseHelper->Release();
pdispTypeLibrary->Release();
pdispTypeInfos->Release();
SetCursor(hcursorOld);
return NOERROR;

error:
if (pdispBrowseHelper) pdispBrowseHelper->Release();
if (pdispTypeLibrary) pdispTypeLibrary->Release();
if (pdispTypeInfos) pdispTypeLibrary->Release();
VariantClear(&vRet);
SetCursor(hcursorOld);
return hr;
}

/*
* CBrowseApp::ChangeTypeInfosSelection
*
* Purpose:
* Called when user changes selection in TypeInfos list box. Information
* about the the selected TypeInfo is dispayed. Elements of the TypeInfo
* are placed in the Elements list box.
*
*/
HRESULT CBrowseApp::ChangeTypeInfosSelection()
{
int nCurSel;
VARIANT vRet;
HRESULT hr;
HCURSOR hcursorOld;
LPDISPATCH pdispTypeInfo;
TYPEKIND typekind;
TCHAR szTemp[100];
LPDISPATCH pdispElements = NULL;
LPDISPATCH pdispMembers = NULL;
LPDISPATCH pdispFunctions = NULL;
LPDISPATCH pdispProperties = NULL;
LPDISPATCH pdispMethods = NULL;
LPDISPATCH pdispInterfaces = NULL;
LPDISPATCH pdispTypeDesc = NULL;

// Get current selection in TypeInfos list.
nCurSel = (int)SendDlgItemMessage(m_hwndMain, IDC_TYPEINFOSLIST, LB_GETCURSEL, 0, 0L);
if (nCurSel == LB_ERR)
return NOERROR;
// Get IDispatch* of selected TypeInfo.
pdispTypeInfo = (LPDISPATCH) SendDlgItemMessage(m_hwndMain, IDC_TYPEINFOSLIST, LB_GETITEMDATA,
(WPARAM)nCurSel, 0L);

// Empty Elements & Parameters lists.
EmptyList(GetDlgItem(m_hwndMain, IDC_ELEMENTSLIST));
EmptyList(GetDlgItem(m_hwndMain, IDC_PARAMETERSLIST));
ClearElementStaticFields();
ClearParamStaticFields();

ClearTypeInfoStaticFields();

hcursorOld = SetCursor(LoadCursor(NULL, IDC_WAIT));
// Invoke ITypeInformation.HelpContext. Returns VT_I4.
hr = Invoke(pdispTypeInfo, DISPATCH_PROPERTYGET, &vRet, NULL, NULL,
OLESTR("HelpContext"), TEXT(""));
if (FAILED(hr))
goto error;
wsprintf(szTemp, TEXT("%ld"), V_I4(&vRet));
SetDlgItemText(m_hwndMain, IDC_TYPEINFO_HELPCTX, szTemp);

// Invoke ITypeInformation.Documentation. Returns BSTR.
hr = Invoke(pdispTypeInfo, DISPATCH_PROPERTYGET, &vRet, NULL, NULL,
OLESTR("Documentation"), TEXT(""));
if (FAILED(hr))
goto error;
if (V_BSTR(&vRet) != NULL) //NULL is a valid value for a BSTR
SetDlgItemText(m_hwndMain, IDC_TYPEINFO_DOC, FROM_OLE_STRING(V_BSTR(&vRet)));
VariantClear(&vRet);

// Invoke ITypeInformation.TypeInfoKind. Returns TYPEKIND.
hr = Invoke(pdispTypeInfo, DISPATCH_PROPERTYGET, &vRet, NULL, NULL,
OLESTR("TypeInfoKind"), TEXT(""));
if (FAILED(hr))
goto error;
typekind = (TYPEKIND)V_I2(&vRet);

switch (typekind)
{
case TKIND_ENUM:
SetDlgItemText(m_hwndMain, IDC_TYPEINFO_TYPE, TEXT("TKIND_ENUM"));
// Invoke IEnum.Elements. Returns ICollection of IConstant.
hr = Invoke(pdispTypeInfo, DISPATCH_PROPERTYGET, &vRet, NULL, NULL,
OLESTR("Elements"), TEXT(""));
if (FAILED(hr))
goto error;
pdispElements = V_DISPATCH(&vRet);
// Put the Enumerator constants in the Elements list.
hr = LoadList(pdispElements, IDC_ELEMENTSLIST);
if (FAILED(hr))
goto error;
pdispElements->Release();
break;

case TKIND_RECORD:
SetDlgItemText(m_hwndMain, IDC_TYPEINFO_TYPE, TEXT("TKIND_RECORD"));
// Invoke IStruct.Members. Returns ICollection of IProperty.
hr = Invoke(pdispTypeInfo, DISPATCH_PROPERTYGET, &vRet, NULL, NULL,
OLESTR("Members"), TEXT(""));
if (FAILED(hr))
goto error;
pdispMembers = V_DISPATCH(&vRet);
// Put the Structure memebers in the Elements list.
hr = LoadList(pdispMembers, IDC_ELEMENTSLIST);
if (FAILED(hr))
goto error;
pdispMembers->Release();
break;

case TKIND_MODULE:
SetDlgItemText(m_hwndMain, IDC_TYPEINFO_TYPE, TEXT("TKIND_MODULE"));
// Invoke IModule.Functions. Returns ICollection of IFunction.
hr = Invoke(pdispTypeInfo, DISPATCH_PROPERTYGET, &vRet, NULL, NULL,
OLESTR("Functions"), TEXT(""));
if (FAILED(hr))
goto error;
pdispFunctions = V_DISPATCH(&vRet);
// Put the Module functions in the Elements list.
hr = LoadList(pdispFunctions, IDC_ELEMENTSLIST);
if (FAILED(hr))
goto error;
pdispFunctions->Release();
break;

case TKIND_INTERFACE:
SetDlgItemText(m_hwndMain, IDC_TYPEINFO_TYPE, TEXT("TKIND_INTERFACE"));
// Invoke IInterface.Functions. Returns ICollection of IFunction.
hr = Invoke(pdispTypeInfo, DISPATCH_PROPERTYGET, &vRet, NULL, NULL,
OLESTR("Functions"), TEXT(""));
if (FAILED(hr))
goto error;
pdispFunctions = V_DISPATCH(&vRet);
// Put the Interface functions in the Elements list.
hr = LoadList(pdispFunctions, IDC_ELEMENTSLIST);
if (FAILED(hr))
goto error;
pdispFunctions->Release();
break;

case TKIND_DISPATCH:
SetDlgItemText(m_hwndMain, IDC_TYPEINFO_TYPE, TEXT("TKIND_DISPATCH"));
// Invoke Dispinterface.Properties. Returns ICollection of IProperty.
hr = Invoke(pdispTypeInfo, DISPATCH_PROPERTYGET, &vRet, NULL, NULL,
OLESTR("Properties"), TEXT(""));
if (FAILED(hr))
goto error;
pdispProperties = V_DISPATCH(&vRet);
// Invoke IDispinterface.Methods. Returns ICollection of IFunction.
hr = Invoke(pdispTypeInfo, DISPATCH_PROPERTYGET, &vRet, NULL, NULL,
OLESTR("Methods"), TEXT(""));
if (FAILED(hr))
goto error;
pdispMethods = V_DISPATCH(&vRet);
// Put the Dispinterface properties and methods in the Elements list.
hr = LoadList(pdispProperties, IDC_ELEMENTSLIST);
if (FAILED(hr))
goto error;
pdispProperties->Release();
hr = LoadList(pdispMethods, IDC_ELEMENTSLIST);
if (FAILED(hr))
goto error;
pdispMethods->Release();
break;

case TKIND_COCLASS:
SetDlgItemText(m_hwndMain, IDC_TYPEINFO_TYPE, TEXT("TKIND_COCLASS"));
// Invoke ICoClass.Interfaces. Returns ICollection of IInterface & IDispinterface.
hr = Invoke(pdispTypeInfo, DISPATCH_PROPERTYGET, &vRet, NULL, NULL,
OLESTR("Interfaces"), TEXT(""));
if (FAILED(hr))
goto error;
pdispInterfaces = V_DISPATCH(&vRet);
// Put the CoClass interfaces and dispinterfaces in the Elements list.
hr = LoadList(pdispInterfaces, IDC_ELEMENTSLIST);
if (FAILED(hr))
goto error;
pdispInterfaces->Release();
break;

case TKIND_ALIAS:
// An alias does not have elements. Display the base type.
SetDlgItemText(m_hwndMain, IDC_TYPEINFO_TYPE, TEXT("TKIND_ALIAS"));
// Invoke IAlias.BaseType. Returns ITypeDesc.
hr = Invoke(pdispTypeInfo, DISPATCH_PROPERTYGET, &vRet, NULL, NULL,
OLESTR("BaseType"), TEXT(""));
if (FAILED(hr))
goto error;
pdispTypeDesc = V_DISPATCH(&vRet);
szTemp[0] = '\0'; // Must initialize to empty string before calling TypeToString.
hr = TypeToString(pdispTypeDesc, szTemp);
if (FAILED(hr))
goto error;
SetDlgItemText(m_hwndMain, IDC_TYPEINFO_ALIASTYPE, szTemp);
pdispTypeDesc->Release();
break;

case TKIND_UNION:
SetDlgItemText(m_hwndMain, IDC_TYPEINFO_TYPE, TEXT("TKIND_UNION"));
// Invoke IUnion.Members. Returns ICollection of IProperty.
hr = Invoke(pdispTypeInfo, DISPATCH_PROPERTYGET, &vRet, NULL, NULL,
OLESTR("Members"), TEXT(""));
if (FAILED(hr))
goto error;
pdispMembers = V_DISPATCH(&vRet);
// Put the Union members in the Elements list.
hr = LoadList(pdispMembers, IDC_ELEMENTSLIST);
if (FAILED(hr))
goto error;
pdispMembers->Release();
break;
}
SetCursor(hcursorOld);
return NOERROR;
error:
if (pdispElements) pdispElements->Release();
if (pdispMembers) pdispMembers->Release();
if (pdispFunctions) pdispFunctions->Release();
if (pdispProperties) pdispProperties->Release();
if (pdispMethods) pdispElements->Release();
if (pdispInterfaces) pdispInterfaces->Release();
if (pdispTypeDesc) pdispTypeDesc->Release();
VariantClear(&vRet);
SetCursor(hcursorOld);
return hr;
}

/*
* CBrowseApp::ChangeElementsSelection
*
* Purpose:
* Called when user changes selection in Elements list box. Information
* about the the selected Element is dispayed. If the element is a function,
* the parameters are placed in the the Parameters list box.
*
*/
HRESULT CBrowseApp::ChangeElementsSelection()
{
int nCurSel;
VARIANT vRet;
HRESULT hr;
int nKind;
TYPEKIND typekind;
LPDISPATCH pdispElement;
LPDISPATCH pdispParameters = NULL;
LPDISPATCH pdispTypeDesc = NULL;
TCHAR szTemp[100];

// Disable the help file button.
EnableWindow(GetDlgItem(m_hwndMain, IDC_ELEM_OPEN_HELPFILE), FALSE);

// Get current selection in Elements list.
nCurSel = (int)SendDlgItemMessage(m_hwndMain, IDC_ELEMENTSLIST, LB_GETCURSEL, 0, 0L);
if (nCurSel == LB_ERR)
return NOERROR;
// Get IDispatch* of selected Element.
pdispElement = (LPDISPATCH) SendDlgItemMessage(m_hwndMain, IDC_ELEMENTSLIST, LB_GETITEMDATA,
(WPARAM)nCurSel, 0L);

// Empty Parameters lists.
EmptyList(GetDlgItem(m_hwndMain, IDC_PARAMETERSLIST));
ClearParamStaticFields();

ClearElementStaticFields();

// Invoke IFunction/IConstant/IProperty/IInterface/IDispinterface.HelpContext. Returns VT_I4.
hr = Invoke(pdispElement, DISPATCH_PROPERTYGET, &vRet, NULL, NULL,
OLESTR("HelpContext"), TEXT(""));
if (FAILED(hr))
goto error;
wsprintf(szTemp, TEXT("%ld"), V_I4(&vRet));
SetDlgItemText(m_hwndMain, IDC_ELEM_HELPCTX, szTemp);
m_lElemHelpCtx = V_I4(&vRet);

// Invoke IFunction/IConstant/IProperty/IInterface/IDispinterface.Documentation. Returns BSTR.
hr = Invoke(pdispElement, DISPATCH_PROPERTYGET, &vRet, NULL, NULL,
OLESTR("Documentation"), TEXT(""));
if (FAILED(hr))
goto error;
if (V_BSTR(&vRet) != NULL) //NULL is a valid value for a BSTR
SetDlgItemText(m_hwndMain, IDC_ELEM_DOC, FROM_OLE_STRING(V_BSTR(&vRet)));
VariantClear(&vRet);

// Invoke IFunction/IConstant/IProperty.MemberID. Returns VT_I4.
hr = Invoke(pdispElement, DISPATCH_PROPERTYGET, &vRet, NULL, NULL,
OLESTR("MemberID"), TEXT(""));
if (FAILED(hr))
{
// This maybe a interface/dispinterface element of a coclass
hr = Invoke(pdispElement, DISPATCH_PROPERTYGET, &vRet, NULL, NULL,
OLESTR("TypeInfoKind"), TEXT(""));
if (FAILED(hr))
goto error;
typekind = (TYPEKIND)V_I2(&vRet);
if (typekind == TKIND_INTERFACE)
SetDlgItemText(m_hwndMain, IDC_ELEM_TYPE, TEXT("TKIND_INTERFACE"));
else if (typekind == TKIND_DISPATCH)
SetDlgItemText(m_hwndMain, IDC_ELEM_TYPE, TEXT("TKIND_DISPATCH"));
else SetDlgItemText(m_hwndMain, IDC_ELEM_TYPE, TEXT("Unknown element"));
return NOERROR;
}
wsprintf(szTemp, TEXT("0x%lx"), V_I4(&vRet));
SetDlgItemText(m_hwndMain, IDC_ELEM_MEMID, szTemp);

// Invoke IFunction/IConstant/IProperty.Kind property. Returns OBJKIND.
hr = Invoke(pdispElement, DISPATCH_PROPERTYGET, &vRet, NULL, NULL,
OLESTR("Kind"), TEXT(""));
if (FAILED(hr))
goto error;
nKind = V_I2(&vRet);

switch (nKind)
{
case TYPE_FUNCTION: //Function
// Invoke IFunction.Parameters. Returns ICollection of IParameter..
hr = Invoke(pdispElement, DISPATCH_PROPERTYGET, &vRet, NULL, NULL,
OLESTR("Parameters"), TEXT(""));
if (FAILED(hr))
goto error;
pdispParameters = V_DISPATCH(&vRet);
hr = LoadList(pdispParameters, IDC_PARAMETERSLIST);
if FAILED(hr)
goto error;
pdispParameters->Release(); pdispParameters = NULL;

// Invoke IFunction.CallConvention. Returns CALLCONV.
hr = Invoke(pdispElement, DISPATCH_PROPERTYGET, &vRet, NULL, NULL,
OLESTR("CallConvention"), TEXT(""));
if (FAILED(hr))
goto error;
CallConvToString(V_I2(&vRet), szTemp);
SetDlgItemText(m_hwndMain, IDC_ELEM_CALLCONV, szTemp);

// Invoke IFunction.FuncKind. Returns FUNCKIND.
hr = Invoke(pdispElement, DISPATCH_PROPERTYGET, &vRet, NULL, NULL,
OLESTR("FuncKind"), TEXT(""));
if (FAILED(hr))
goto error;
FuncKindToString(V_I2(&vRet), szTemp);
SetDlgItemText(m_hwndMain, IDC_ELEM_FUNCKIND, szTemp);

// Invoke IFunction.InvocationKind. Returns INVOKEKIND.
hr = Invoke(pdispElement, DISPATCH_PROPERTYGET, &vRet, NULL, NULL,
OLESTR("InvocationKind"), TEXT(""));
if (FAILED(hr))
goto error;
InvokeKindToString(V_I2(&vRet), szTemp);
SetDlgItemText(m_hwndMain, IDC_ELEM_INVOKEKIND, szTemp);

// Invoke IFunction.ReturnType. Returns ITypeDesc.
hr = Invoke(pdispElement, DISPATCH_PROPERTYGET, &vRet, NULL, NULL,
OLESTR("ReturnType"), TEXT(""));
if (FAILED(hr))
goto error;
break;

case TYPE_CONSTANT:
// Invoke IConstant.Value. Returns VARIANT.
hr = Invoke(pdispElement, DISPATCH_PROPERTYGET, &vRet, NULL, NULL,
OLESTR("Value"), TEXT(""));
if (FAILED(hr))
goto error;
VariantToString(vRet, szTemp);
SetDlgItemText(m_hwndMain, IDC_ELEM_CONST_VALUE, szTemp);
// Fall through to default.

default:
// Invoke IConstant/IProperty.Type. Returns ITypeDesc.
hr = Invoke(pdispElement, DISPATCH_PROPERTYGET, &vRet, NULL, NULL,
OLESTR("Type"), TEXT(""));
if (FAILED(hr))
goto error;
break;
}
// Get string that describes type and display it.
pdispTypeDesc = V_DISPATCH(&vRet);
szTemp[0] = '\0'; // Must initialize to empty string before calling TypeToString.
hr = TypeToString(pdispTypeDesc, szTemp);
if (FAILED(hr))
goto error;
SetDlgItemText(m_hwndMain, IDC_ELEM_TYPE, szTemp);
pdispTypeDesc->Release();

// Enable the helpfile button if a helpfile and help context is specified.
if (m_lElemHelpCtx && m_szHelpFile[0])
EnableWindow(GetDlgItem(m_hwndMain, IDC_ELEM_OPEN_HELPFILE), TRUE);
return NOERROR;
error:
if (pdispParameters) pdispParameters->Release();
VariantClear(&vRet);
return hr;
}

/*
* CBrowseApp::ChangeParametersSelection
*
* Purpose:
* Called when user changes selection in Parameters list box. Information
* about the the selected Parameter is dispayed.
*
*/
HRESULT CBrowseApp::ChangeParametersSelection()
{
int nCurSel;
VARIANT vRet;
HRESULT hr;
LPDISPATCH pdispParameter;
LPDISPATCH pdispTypeDesc = NULL;
TCHAR szTemp[100];

// Get current selection in Parameters list.
nCurSel = (int)SendDlgItemMessage(m_hwndMain, IDC_PARAMETERSLIST, LB_GETCURSEL, 0, 0L);
if (nCurSel == LB_ERR)
return NOERROR;
// Get IDispatch* of selected Parameter.
pdispParameter = (LPDISPATCH) SendDlgItemMessage(m_hwndMain, IDC_PARAMETERSLIST, LB_GETITEMDATA,
(WPARAM)nCurSel, 0L);

ClearParamStaticFields();

// Invoke IParameter.IDLFlags. Returns VT_I2.
hr = Invoke(pdispParameter, DISPATCH_PROPERTYGET, &vRet, NULL, NULL,
OLESTR("IDLFlags"), TEXT(""));
if (FAILED(hr))
goto error;
IDLFlagsToString(V_I2(&vRet), szTemp);
SetDlgItemText(m_hwndMain, IDC_PARAM_INOUT, szTemp);

// Invoke IParameter.Type. Returns ITypeDesc.
hr = Invoke(pdispParameter, DISPATCH_PROPERTYGET, &vRet, NULL, NULL,
OLESTR("Type"), TEXT(""));
if (FAILED(hr))
goto error;

// Get string that describes type and display it.
pdispTypeDesc = V_DISPATCH(&vRet);
szTemp[0] = '\0'; // Must initialize to empty string before calling TypeToString.
hr = TypeToString(pdispTypeDesc, szTemp);
if (FAILED(hr))
goto error;
SetDlgItemText(m_hwndMain, IDC_PARAM_TYPE, szTemp);
pdispTypeDesc->Release();
return NOERROR;
error:
if (pdispTypeDesc) pdispTypeDesc->Release();
VariantClear(&vRet);
return hr;
}

/*
* CBrowseApp::OpenElementHelpFile
*
* Purpose:
* Opens the helpfile for the element.
*
*/
void CBrowseApp::OpenElementHelpFile()
{
BOOL b;

b = WinHelp(m_hwndMain, m_szHelpFile, HELP_CONTEXT, m_lElemHelpCtx);
if (!b)
MessageBox(m_hwndMain, TEXT("Failed to open help file"), TEXT("Error"),
MB_ICONEXCLAMATION|MB_OK);
}

void CBrowseApp::EmptyList(HWND hwndList)
{
int nItems, i;
LPDISPATCH pdispItem;

nItems = (int)SendMessage(hwndList, LB_GETCOUNT, 0, 0L);
for (i=0; i<nItems; i++)
{
pdispItem = (LPDISPATCH)SendMessage(hwndList, LB_GETITEMDATA, (WPARAM)i, 0L);
if (pdispItem)
pdispItem->Release();
}
SendMessage(hwndList, LB_RESETCONTENT, 0, 0L);
}

/*
* CBrowseApp::LoadList
*
* Parameters:
* pdispItems IDispatch* of collection of items to be put into the list.
* nListID Identifies the list to be filled.
*
* Purpose:
* Loads the list with the items in the collection.

* 
*/
HRESULT CBrowseApp::LoadList(LPDISPATCH pdispItems, int nListID)
{
VARIANT vRet, v;
HRESULT hr;
LPUNKNOWN punkEnum;
IEnumVARIANT FAR* penum = NULL;
LPDISPATCH pdispItem = NULL;
int nIndex;

// Get _NewEnum property. Returns enumerator's IUnknown.
hr = Invoke(pdispItems, DISPATCH_PROPERTYGET, &vRet, NULL, NULL,
OLESTR("_NewEnum"), TEXT(""));
if (FAILED(hr))
goto error;
punkEnum = V_UNKNOWN(&vRet);
hr = punkEnum->QueryInterface(IID_IEnumVARIANT, (LPVOID FAR*)&penum);
if (FAILED(hr))
goto error;
punkEnum->Release();

VariantInit(&v);
// Enumerate the Items.
while (S_OK == penum->Next(1, &v, NULL))
{
pdispItem = V_DISPATCH(&v);
pdispItem->AddRef();
VariantClear(&v);

// Get Name of Item.
hr = Invoke(pdispItem, DISPATCH_PROPERTYGET, &vRet, NULL, NULL,
OLESTR("Name"), TEXT(""));
if (FAILED(hr))
goto error;
// Add name to ItemsList.
nIndex = (int)SendDlgItemMessage(m_hwndMain, nListID, LB_ADDSTRING,
0, (LPARAM)(LPTSTR)FROM_OLE_STRING(V_BSTR(&vRet)));
VariantClear(&vRet);
// Save IDispatch* of Item in the list.
SendDlgItemMessage(m_hwndMain, nListID, LB_SETITEMDATA,
nIndex, (LPARAM)pdispItem);
}
penum->Release();
return NOERROR;

error:
if (penum) penum->Release();
if (pdispItem) pdispItem->Release();
return hr;
}

void CBrowseApp::Init(HWND hwndMain)
{
HFONT hfontDlg;
LOGFONT lfont;
int nID;

m_hwndMain = hwndMain;
m_hfont = NULL;
#ifdef WIN16
m_hinst = (HINSTANCE)GetWindowWord(hwndMain, GWW_HINSTANCE);
#else
m_hinst = (HINSTANCE)GetWindowLong(hwndMain, GWL_HINSTANCE);
#endif
EnableWindow(GetDlgItem(m_hwndMain, IDC_ELEM_OPEN_HELPFILE), FALSE);

// Change to the font of the fields to a non-bold font.
hfontDlg = (HFONT)SendMessage(m_hwndMain, WM_GETFONT, NULL, NULL);
if (!hfontDlg)
return;
GetObject(hfontDlg, sizeof(LOGFONT), (LPVOID)&lfont);
lfont.lfWeight = FW_NORMAL;
if (m_hfont = CreateFontIndirect(&lfont))
for (nID=IDC_TYPELIB_FIRST; nID<=IDC_PARAM_LAST; nID++)
SendDlgItemMessage(m_hwndMain, nID, WM_SETFONT, (WPARAM)m_hfont, 0L);

}

void CBrowseApp::Cleanup()
{
EmptyList(GetDlgItem(m_hwndMain, IDC_TYPEINFOSLIST));
EmptyList(GetDlgItem(m_hwndMain, IDC_ELEMENTSLIST));
EmptyList(GetDlgItem(m_hwndMain, IDC_PARAMETERSLIST));
ClearTypeLibStaticFields();
ClearTypeInfoStaticFields();
ClearElementStaticFields();
ClearParamStaticFields();
if (m_hfont)
DeleteObject(m_hfont);
}

void CBrowseApp::ClearTypeLibStaticFields()
{
int nID;

for (nID=IDC_TYPELIB_FIRST; nID<=IDC_TYPELIB_LAST; nID++)
SetDlgItemText(m_hwndMain, nID, TEXT(""));
}
void CBrowseApp::ClearTypeInfoStaticFields()
{
int nID;

for (nID=IDC_TYPEINFO_FIRST; nID<=IDC_TYPEINFO_LAST; nID++)
SetDlgItemText(m_hwndMain, nID, TEXT(""));
}
void CBrowseApp::ClearElementStaticFields()
{
int nID;

for (nID=IDC_ELEM_FIRST; nID<=IDC_ELEM_LAST; nID++)
SetDlgItemText(m_hwndMain, nID, TEXT(""));
}
void CBrowseApp::ClearParamStaticFields()
{
int nID;

for (nID=IDC_PARAM_FIRST; nID<=IDC_PARAM_LAST; nID++)
SetDlgItemText(m_hwndMain, nID, TEXT(""));
}

#define CASE_VT(vt) \
case vt: \
lstrcat(pszTypeName, TEXT(#vt)); \
break;
HRESULT CBrowseApp::TypeToString(LPDISPATCH pdispTypeDesc, LPTSTR pszTypeName)
{
VARIANT vRet;
VARTYPE vartype;
HRESULT hr;
LPDISPATCH pdispTypeDesc2;

// Get Type property
hr = Invoke(pdispTypeDesc, DISPATCH_PROPERTYGET, &vRet, NULL, NULL,
OLESTR("Type"), TEXT(""));
if (FAILED(hr))
goto error;
vartype = V_I2(&vRet);

if (vartype & 0x2000) // If SafeArray
lstrcat(pszTypeName, TEXT("SAFEARRAY("));

switch (vartype & ~0x7000)
{
CASE_VT(VT_EMPTY)
CASE_VT(VT_NULL)
CASE_VT(VT_I2)
CASE_VT(VT_I4)
CASE_VT(VT_R4)
CASE_VT(VT_R8)
CASE_VT(VT_CY)
CASE_VT(VT_DATE)
CASE_VT(VT_BSTR)
CASE_VT(VT_DISPATCH)
CASE_VT(VT_ERROR)
CASE_VT(VT_BOOL)
CASE_VT(VT_VARIANT)
CASE_VT(VT_UNKNOWN)

CASE_VT(VT_I1)
CASE_VT(VT_UI1)
CASE_VT(VT_UI2)
CASE_VT(VT_UI4)
CASE_VT(VT_I8)
CASE_VT(VT_UI8)
CASE_VT(VT_INT)
CASE_VT(VT_UINT)
CASE_VT(VT_VOID)
CASE_VT(VT_HRESULT)
CASE_VT(VT_SAFEARRAY)
CASE_VT(VT_CARRAY)
CASE_VT(VT_LPSTR)
CASE_VT(VT_LPWSTR)

CASE_VT(VT_FILETIME)
CASE_VT(VT_BLOB)
CASE_VT(VT_STREAM)
CASE_VT(VT_STORAGE)
CASE_VT(VT_STREAMED_OBJECT)
CASE_VT(VT_STORED_OBJECT)
CASE_VT(VT_BLOB_OBJECT)
CASE_VT(VT_CF)
CASE_VT(VT_CLSID)

case VT_PTR:
// Get ITypeDesc.PointerDesc property. Returns ITypeDesc.
hr = Invoke(pdispTypeDesc, DISPATCH_PROPERTYGET, &vRet, NULL, NULL,
OLESTR("PointerDesc"), TEXT(""));
if (FAILED(hr))
goto error;
pdispTypeDesc2 = V_DISPATCH(&vRet);
TypeToString(pdispTypeDesc2, pszTypeName);
lstrcat(pszTypeName, TEXT(" *"));
pdispTypeDesc2->Release();
break;

case VT_USERDEFINED:
// Get ITypeDesc.UserDefinedDesc property. Returns ITypeInformation
hr = Invoke(pdispTypeDesc, DISPATCH_PROPERTYGET, &vRet, NULL, NULL,
OLESTR("UserDefinedDesc"), TEXT(""));
if (FAILED(hr))
goto error;
pdispTypeDesc2 = V_DISPATCH(&vRet);
// Get ITypeInformation.Name property. Returns BSTR.
hr = Invoke(pdispTypeDesc2, DISPATCH_PROPERTYGET, &vRet, NULL, NULL,
OLESTR("Name"), TEXT(""));
if (FAILED(hr))
goto error;
lstrcat(pszTypeName, FROM_OLE_STRING(V_BSTR(&vRet)));
VariantClear(&vRet);
pdispTypeDesc2->Release();
break;
}

if (vartype & 0x2000) // If SafeArray
lstrcat(pszTypeName, TEXT(")"));

return NOERROR;
error:
return ERROR;
}

void CBrowseApp::IDLFlagsToString(int n, LPTSTR psz)
{
psz[0] = '\0';
if (n & IDLFLAG_FIN)
{
lstrcpy(psz, TEXT("IN"));
if (n & IDLFLAG_FOUT)
lstrcat(psz, TEXT("|OUT"));
}
else if (n & IDLFLAG_FOUT)
lstrcpy(psz, TEXT("OUT"));
}

#define CASE_INVOKE(invokekind) \
case invokekind: \
lstrcpy(psz, TEXT(#invokekind)); \
break;
void CBrowseApp::CallConvToString(int n, LPTSTR psz)
{
CALLCONV c = (CALLCONV)n;
switch (c)
{
CASE_INVOKE(CC_CDECL)
CASE_INVOKE(CC_PASCAL)
CASE_INVOKE(CC_MACPASCAL)
CASE_INVOKE(CC_STDCALL)
CASE_INVOKE(CC_SYSCALL)
default:
lstrcpy(psz, TEXT("Unknown"));
}
}

#define CASE_FUNC(funckind) \
case funckind: \
lstrcpy(psz, TEXT(#funckind)); \
break;
void CBrowseApp::FuncKindToString(int n, LPTSTR psz)
{
FUNCKIND f = (FUNCKIND)n;
switch (f)
{
CASE_FUNC(FUNC_VIRTUAL)
CASE_FUNC(FUNC_PUREVIRTUAL)
CASE_FUNC(FUNC_NONVIRTUAL)
CASE_FUNC(FUNC_STATIC)
CASE_FUNC(FUNC_DISPATCH)
default:
lstrcpy(psz, TEXT("Unknown"));
}
}

#define CASE_INVOKE(invokekind) \
case invokekind: \
lstrcpy(psz, TEXT(#invokekind)); \
break;
void CBrowseApp::InvokeKindToString(int n, LPTSTR psz)
{
INVOKEKIND i = (INVOKEKIND)n;
switch (i)
{
CASE_INVOKE(INVOKE_FUNC)
CASE_INVOKE(INVOKE_PROPERTYGET)
CASE_INVOKE(INVOKE_PROPERTYPUT)
CASE_INVOKE(DISPATCH_PROPERTYPUTREF)
default:
lstrcpy(psz, TEXT("Unknown"));
}
}
void CBrowseApp::VariantToString(VARIANT v, LPTSTR psz)
{
HRESULT hr;
VARIANT vTemp;

VariantInit(&vTemp);
hr = VariantChangeType(&vTemp, &v, 0, VT_BSTR);
if (FAILED(hr))
lstrcpy(psz, TEXT("Cannot Display Value"));
else lstrcpy(psz, FROM_OLE_STRING(V_BSTR(&vTemp)));
VariantClear(&vTemp);
}


/*
* Quick & Dirty ANSI/Unicode conversion routines. These routines use a static
* buffer of fixed size to hold the converted string. Consequently these
* routines are limited to strings of size STRCONVERT_MAXLEN. Also the same
* buffer is reused when the routine is called a second time. So make sure
* that the converted string is used before the conversion routine is called
* again
*/
#ifdef WIN32

#ifndef UNICODE
char* ConvertToAnsi(OLECHAR FAR* szW)
{
static char achA[STRCONVERT_MAXLEN];

WideCharToMultiByte(CP_ACP, 0, szW, -1, achA, STRCONVERT_MAXLEN, NULL, NULL);
return achA;
}

OLECHAR* ConvertToUnicode(char FAR* szA)
{
static OLECHAR achW[STRCONVERT_MAXLEN];

MultiByteToWideChar(CP_ACP, 0, szA, -1, achW, STRCONVERT_MAXLEN);
return achW;
}
#endif

#endif