TIBROWSE.CPP

/***  
*tibrowse.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.
*
*Purpose:
* Type Information Browser
*
*
*Implementation Notes:
*
*****************************************************************************/

#if defined(_MAC)

#if defined(_PPCMAC)
#pragma data_seg("_FAR_DATA")
#pragma data_seg( )
#define MAXLONG 0x7fffffff
#define EventHandlerProcPtr AEEventHandlerUPP
#else //_PPCMAC
#define GetMenuItemText(mApple,menuItem,daName) GetItem(mApple,menuItem,daName)
#endif //_PPCMAC

#endif //_MAC

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "tibrowse.h"

#ifdef WIN32
#define SPRINTFswprintf
#else
#define SPRINTFsprintf
#endif

#if defined(UNICODE)
#define TCHARWCHAR
#define TSTR(str)L##str
#else
#define TCHARchar
#define TSTR(str)str
#ifndef LPTSTR
#define LPTSTR LPSTR
#endif
#endif

#ifdef _MAC
DECLARE_ROUTINE_DESC(UserItemUPP,DrawListbox);
#endif

#ifdef _MAC
DialogPtr g_pdlg = NULL;
ListHandle g_rghlist[IDC_PARAMLIST+1] = {NULL};
#else
HWND g_hwnd;
TCHAR g_szAppName[] = TSTR("TiBrowse");
#endif

ITypeLib FAR *g_ptlib = NULL;
ITypeInfo FAR *g_ptinfoCur = NULL;
TYPEATTR FAR *g_ptattrCur = NULL;

OLECHAR * g_rgszTKind[] = {
OLESTR("Enum"),/* TKIND_ENUM */
OLESTR("Struct"),/* TKIND_RECORD */
OLESTR("Module"),/* TKIND_MODULE */
OLESTR("Interface"),/* TKIND_INTERFACE */
OLESTR("Dispinterface"),/* TKIND_DISPATCH */
OLESTR("Coclass"),/* TKIND_COCLASS */
OLESTR("Typedef"),/* TKIND_ALIAS */
OLESTR("Union"),/* TKIND_UNION */
};


// Set the text of the control identified by the given control id
void
XSetDlgItemText(int ctlid, OLECHAR FAR* psz)
{
#ifdef _MAC
Rect rc;
Handle h;
short kind;
char buf[255];

strcpy(buf, psz);
GetDItem(g_pdlg, ctlid, &kind, &h, &rc);
SetIText(h, c2pstr(buf));
#else
#if defined(WIN32) && !defined(UNICODE)
char bufA[256];
WideCharToMultiByte(CP_ACP, NULL, psz, -1, bufA, 256, NULL, NULL);
SendDlgItemMessage(g_hwnd, ctlid, WM_SETTEXT, 0, (LPARAM)&bufA);
#else
SendDlgItemMessage(g_hwnd, ctlid, WM_SETTEXT, 0, (LPARAM)psz);
#endif
#endif
}

// Clear the listbox identified by the given control id
void
XClrDlgItemList(int ctlid)
{
#ifdef _MAC
LDelRow(0, 0, g_rghlist[ctlid]); // delete everything
#else
SendMessage(GetDlgItem(g_hwnd, ctlid), LB_RESETCONTENT, 0, 0L);
#endif
}

// Add the given string to the listbox identified by the given control id
void
XAddDlgItemList(int ctlid, OLECHAR FAR* psz)
{
#ifdef _MAC
int row;
Point pt;
ListHandle hlist;

hlist = g_rghlist[ctlid];
row = LAddRow(1, -1, hlist);
pt.v = row, pt.h = 0;
LSetCell(psz, strlen(psz), pt, hlist);
#else
#if defined(WIN32) && !defined(UNICODE)
char bufA[256];
WideCharToMultiByte(CP_ACP, NULL, psz, -1, bufA, 256, NULL, NULL);
SendDlgItemMessage(g_hwnd, ctlid, LB_ADDSTRING, 0, (LPARAM)&bufA);
#else
SendDlgItemMessage(g_hwnd, ctlid, LB_ADDSTRING, 0, (LPARAM)psz);
#endif
#endif
}

void Cleanup()
{
if(g_ptinfoCur != NULL){
if(g_ptattrCur != NULL)
g_ptinfoCur->ReleaseTypeAttr(g_ptattrCur);
g_ptinfoCur->Release();
g_ptinfoCur = NULL;
}
if(g_ptlib != NULL){
g_ptlib->Release();
g_ptlib = NULL;
}
}

void Uninit()
{
OleUninitialize();
#ifdef _MAC
#ifndef _PPCMAC
UninitOleManager();// clean up applet
#endif
#endif
}


void
OpenTypeLib(OLECHAR FAR *sztlib)
{
unsigned int utypeinfoCount, i;
BSTR bstrName;
TLIBATTR FAR* ptlibattr;

/* clear out globals */
Cleanup();

/* clear out listboxes */
XClrDlgItemList(IDC_TYPELIST);
XClrDlgItemList(IDC_MEMBERLIST);
XClrDlgItemList(IDC_PARAMLIST);

/* load the type library */
CHECKRESULT(LoadTypeLib(sztlib, &g_ptlib));

/* get library attributes for the fun of it */
CHECKRESULT(g_ptlib->GetLibAttr(&ptlibattr));

/* release library attributes */
g_ptlib->ReleaseTLibAttr(ptlibattr);

/* Now add each of the names to the type list */
utypeinfoCount = g_ptlib->GetTypeInfoCount();
for(i = 0; i < utypeinfoCount; i++){
CHECKRESULT(g_ptlib->GetDocumentation(i, &bstrName, NULL, NULL, NULL));
ASSERT(bstrName);
XAddDlgItemList(IDC_TYPELIST, bstrName);
SysFreeString(bstrName);
}
}

#ifdef WIN32
void
OpenTypeLib(char FAR *sztlib)
{
OLECHAR buf[MAX_PATH];

MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
sztlib, -1, buf, MAX_PATH);
OpenTypeLib(buf);
}
#endif


/***
*void SetSelectedType
*Purpose:
* When the user changes the selection of a type, this function updates the
* dialog by changing the member list and the help for the type. It also sets
* g_ptinfoCur to refer to the typeinfo.
*
*Entry:
* dwIndex =
*
*Exit:
* return value = None
*
***********************************************************************/
void
SetSelectedType(unsigned long dwIndex)
{
HRESULT hr;
BSTR bstrDoc;
OLECHAR FAR* psz;
OLECHAR szBuf[40];
unsigned long dwHelpContext;
TYPEKIND tkind;

if(g_ptinfoCur != NULL){
g_ptinfoCur->ReleaseTypeAttr(g_ptattrCur);
g_ptinfoCur->Release();
}

/* Clear out the member list */
XClrDlgItemList(IDC_MEMBERLIST);

if(g_ptlib == NULL)
return;

// Note: the index in the list box is conveniently the same as the
// one to pass to GetTypeInfo/GetTypeInfoType

// typeinfo type can be obtained without actually loading the typeinfo
CHECKRESULT(g_ptlib->GetTypeInfoType((unsigned int)dwIndex, &tkind));
XSetDlgItemText(IDC_TYPEKIND, g_rgszTKind[tkind]);

CHECKRESULT(g_ptlib->GetTypeInfo((unsigned int)dwIndex, &g_ptinfoCur));
CHECKRESULT(g_ptinfoCur->GetTypeAttr(&g_ptattrCur));

// GUID
hr = StringFromCLSID(g_ptattrCur->guid, &psz);
ASSERT(hr == NOERROR);
XSetDlgItemText(IDC_GUID, psz);
MemFree(psz);

// Version
SPRINTF(szBuf, OLESTR("%u.%02u"),
g_ptattrCur->wMajorVerNum, g_ptattrCur->wMinorVerNum);
XSetDlgItemText(IDC_VERSION, szBuf);

CHECKRESULT(
g_ptlib->GetDocumentation(
(unsigned int)dwIndex, NULL, &bstrDoc, &dwHelpContext, NULL));

// Help Context
SPRINTF(szBuf, OLESTR("%ld"), dwHelpContext);
XSetDlgItemText(IDC_HELPCONTEXT, szBuf);

// Documentation string
psz = (bstrDoc != NULL) ? bstrDoc : OLESTR("<none>");
XSetDlgItemText(IDC_HELPSTRING, psz);
SysFreeString(bstrDoc);

FillMemberList(g_ptinfoCur, g_ptattrCur, IDC_MEMBERLIST);

XClrDlgItemList(IDC_PARAMLIST);
}

/***
*void FillMemberList
*Purpose:
* Sets the current typeinfo to the typeinfo indexed by dwIndex, and
* then fills in the list box with the members of the type.
*
*Entry:
* ptinfo =
* ptypeattr =
*
*Exit:
* return value = None
*
***********************************************************************/
void
FillMemberList(
ITypeInfo FAR *ptinfo,
TYPEATTR FAR *ptypeattr,
int ctlid)
{
MEMBERID memid;
BSTR bstrName;
unsigned int i;
FUNCDESC FAR *pfuncdesc;
VARDESC FAR *pvardesc;

/* Now add all of the functions and all of the vars.
* This is somewhat roundabout.
* For each one, we need to get the funcdesc, or the vardesc.
* From that we get the MEMBERID, and finally can get to the name.
*/
for(i = 0; i < ptypeattr->cFuncs; i++){
CHECKRESULT(ptinfo->GetFuncDesc(i, &pfuncdesc));
memid = pfuncdesc->memid;
CHECKRESULT(ptinfo->GetDocumentation(memid, &bstrName, NULL, NULL, NULL));
ptinfo->ReleaseFuncDesc(pfuncdesc);
pfuncdesc = NULL;

ASSERT(bstrName);
XAddDlgItemList(ctlid, bstrName);
SysFreeString(bstrName);
}

for(i = 0; i < ptypeattr->cVars; i++)
{
CHECKRESULT(ptinfo->GetVarDesc(i, &pvardesc));
memid = pvardesc->memid;
CHECKRESULT(ptinfo->GetDocumentation(memid, &bstrName, NULL, NULL, NULL));
ptinfo->ReleaseVarDesc(pvardesc);
pvardesc = NULL;

ASSERT(bstrName);
XAddDlgItemList(ctlid, bstrName);
SysFreeString(bstrName);
}
}

/***
*void SetSelectedMember
*Purpose:
* When a member of a type is selected, update the help to be the help
* of the member, and if the member is a function update the parameter
* list to reflect that it is a function.
*
*Entry:
* dwIndex =
*
*Exit:
* return value = None
*
***********************************************************************/
void
SetSelectedMember(unsigned long dwIndex)
{
MEMBERID memid;

/* In any case, we'll need to clear out the parameter list. */
XClrDlgItemList(IDC_PARAMLIST);

if(g_ptattrCur == NULL)
return;

/* if this is a function, fill the param list, otherwise just fill
* in the item info.
*/
if(dwIndex < g_ptattrCur->cFuncs){
unsigned short i;
unsigned int cNames;
FUNCDESC FAR *pfuncdesc;
const unsigned int MAX_NAMES = 40;
BSTR rgNames[MAX_NAMES];

CHECKRESULT(g_ptinfoCur->GetFuncDesc((unsigned int) dwIndex, &pfuncdesc));
memid = pfuncdesc->memid;
UpdateMemberInfo(memid);

CHECKRESULT(g_ptinfoCur->GetNames(memid, rgNames, MAX_NAMES,&cNames));
for(i = 1; i < cNames; i++){
ASSERT(rgNames[i])
XAddDlgItemList(IDC_PARAMLIST, rgNames[i]);
SysFreeString(rgNames[i]);
}
ASSERT(rgNames[0]);
SysFreeString(rgNames[0]);
g_ptinfoCur->ReleaseFuncDesc(pfuncdesc);
}
else
{
VARDESC FAR *pvardesc;

CHECKRESULT(
g_ptinfoCur->GetVarDesc(
(unsigned int)(dwIndex - g_ptattrCur->cFuncs), &pvardesc));
memid = pvardesc->memid;
UpdateMemberInfo(memid);
g_ptinfoCur->ReleaseVarDesc(pvardesc);
}
}

/***
*void UpdateMemberInfo
*Purpose:
* sets fields on the dialog (such as help string and help context) from
* the type information.
*
*Entry:
* memid =
*
*Exit:
* return value = None
*
***********************************************************************/
void
UpdateMemberInfo(MEMBERID memid)
{
BSTR bstrDoc;
OLECHAR buf[40];
unsigned long dwHelpContext;

/* get the member information */
CHECKRESULT(g_ptinfoCur->GetDocumentation(
memid, NULL, &bstrDoc, &dwHelpContext, NULL));

/* update the help string displayed in the dialog */
XSetDlgItemText(IDC_HELPSTRING, (bstrDoc != NULL) ?
bstrDoc : OLESTR("<none>"));
SysFreeString(bstrDoc);

/* update the help context displayed in the dialog */
SPRINTF(buf, OLESTR("%ld"), dwHelpContext);
XSetDlgItemText(IDC_HELPCONTEXT, buf);
}

/***
*void SetSelectedParam
*Purpose:
* CONSIDER: Enhance to show parameter type information here.
*
*Entry:
* dwIndex =
*
*Exit:
* return value = None
*
***********************************************************************/
void
SetSelectedParam(unsigned long dwIndex)
{
}


HRESULT
GetFileName(BSTR FAR* pbstrFileName)
{
OLECHAR buf[1024];
BSTR bstrFileName;

#ifdef _MAC

int i;
Point pt;
long dirID;
char *p, *q;
SFReply sfr;
SFTypeList sftl;
short sRefNumReal;

SetPt(&pt, 100, 100);
//sftl[0] = 'OTLB';
sftl[0] = 0; // currently allow all file types
SFGetFile(pt, NULL, NULL, -1, sftl, NULL, &sfr);

if(!sfr.good)
return E_FAIL;

// translate sfr.vRefNum into a dirID
{
WDPBRec wdpbr;

wdpbr.ioWDIndex = 0;
wdpbr.ioVRefNum = sfr.vRefNum;
wdpbr.ioWDVRefNum = 0;
wdpbr.ioWDIndex = 0;
wdpbr.ioWDProcID = 0;
wdpbr.ioNamePtr = (StringPtr)buf;

if(PBGetWDInfoSync (&wdpbr) != noErr)
return E_FAIL;

sRefNumReal = wdpbr.ioWDVRefNum;
dirID = wdpbr.ioWDDirID;
}

{
Str255 stDir;
CInfoPBRec pb;
DirInfo *pdirinfo = (DirInfo*)&pb;
char rgchTemp[256]; // REVIEW: what should the size be?

pdirinfo->ioNamePtr = stDir;
pdirinfo->ioVRefNum = sRefNumReal;
pdirinfo->ioDrParID = dirID;
pdirinfo->ioFDirIndex = -1; // get info on a dir

buf[0] = '\0';

// loop until we hit the root dir
do{
pdirinfo->ioDrDirID = pdirinfo->ioDrParID;
if(PBGetCatInfoSync (&pb) != noErr)
return E_FAIL;
strncpy(rgchTemp, (char*)stDir, 64);
p2cstr((StringPtr)rgchTemp);
strcat(rgchTemp, ":");
strcat(rgchTemp, buf);
strcpy(buf, rgchTemp);
}while(pdirinfo->ioDrDirID != fsRtDirID);

}

q = (char*)sfr.fName;
i = (int)*q++;
p = &buf[strlen(buf)];
while(i-->0)
*p++ = *q++;
*p = '\0';

if((bstrFileName = SysAllocString(buf)) == NULL)
return E_OUTOFMEMORY;

#else

OPENFILENAME ofn;

memset(&ofn, 0, sizeof(OPENFILENAME));
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = g_hwnd;
ofn.lpstrFile = (LPTSTR) &buf;
ofn.nMaxFile = sizeof(buf);
*buf = OLESTR('\0');
ofn.lpstrFilter = TSTR("Type Libraries\0*.tlb\0\0");
ofn.nFilterIndex = 1;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_SHAREAWARE;
if(GetOpenFileName(&ofn) == 0){
// REVIEW: we can probably do something smarter with this error
DWORD dwerr = CommDlgExtendedError();
return E_FAIL;
}
#if defined(WIN32) && !defined(UNICODE)
OLECHAR szFileW[_MAX_PATH];
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
ofn.lpstrFile, -1, szFileW, _MAX_PATH);
if((bstrFileName = SysAllocString(szFileW)) == NULL)
return E_OUTOFMEMORY;
#else
if((bstrFileName = SysAllocString(ofn.lpstrFile)) == NULL)
return E_OUTOFMEMORY;
#endif

#endif

*pbstrFileName = bstrFileName;
return NOERROR;
}

void
AssertFail(char FAR* file, int line)
{
// Ansi Output for Assertion
#ifdef UNICODE
#define OUTPUTDEBUGSTRINGOutputDebugStringA
#define MESSAGEBOXMessageBoxA
#else
#define OUTPUTDEBUGSTRINGOutputDebugString
#define MESSAGEBOXMessageBox
#endif

char buf[128];

sprintf(buf, "Assertion failed: %s(%d)", file, line);

#ifdef _MAC
DebugStr(c2pstr(buf));
#else
OUTPUTDEBUGSTRING(buf);
if(MESSAGEBOX(NULL, buf,
"TiBrowse Assertion. OK to continue, CANCEL to quit.",
MB_OKCANCEL | MB_TASKMODAL) == IDCANCEL)
exit(1);
DebugBreak();
#endif
}

#ifdef _MAC /* { */

void Init(void);
void EventLoop(void);

void AdjustMenus(void);
void DoEvent(EventRecord *pevent);
void DoMenuCommand(long menuResult);
void Quit(void);
#ifndef _MSC_VER
#ifndef ConstStr255Param
#define ConstStr255Param StringPtr
#endif
#endif
void Fatal(ConstStr255Param);

Boolean
IsAppWindow(WindowPtr window)
{
return (window == NULL)
? false : ((WindowPeek)window)->windowKind == userKind;
}

Boolean
IsDAWindow(WindowPtr window)
{
return (window == NULL)
? false : (((WindowPeek)window)->windowKind < 0);
}

void
main()
{
Init();
// ShowWindow(g_pdlg); // REVIEW: necessarry?
EventLoop();
}

void
DoDialogEvent(EventRecord *pevent, short sItem)
{
Point pt;
GrafPtr pport;
ListHandle hlist;

switch(sItem){
case IDC_TYPELIST:
case IDC_MEMBERLIST:
case IDC_PARAMLIST:
if(pevent->what == mouseDown){
GetPort(&pport);
SetPort(g_pdlg);
GlobalToLocal(&pevent->where);
hlist = g_rghlist[sItem];
LClick(pevent->where, pevent->modifiers, hlist);
SetPt(&pt, 0, 0);
if(LGetSelect(true, &pt, hlist)){
switch(sItem){
case IDC_TYPELIST:
SetSelectedType(pt.v);
break;
case IDC_MEMBERLIST:
SetSelectedMember(pt.v);
break;
case IDC_PARAMLIST:
SetSelectedParam(pt.v);
break;
}
}
SetPort(pport);
}
break;
}
}

void
EventLoop()
{
short sItem;
DialogPtr pdlg;
EventRecordevent;
RgnHandle cursorRgn;

cursorRgn = NewRgn();
while(1){
if(WaitNextEvent(everyEvent, &event, MAXLONG, cursorRgn)){
if (FrontWindow() != NULL
&& event.what != diskEvt
&& (event.what != keyDown || (event.modifiers & cmdKey) == 0)
&& IsDialogEvent(&event))
{
if(DialogSelect(&event, &pdlg, &sItem)){
ASSERT(pdlg == g_pdlg);
DoDialogEvent(&event, sItem);
}
}else{
DoEvent(&event);
}
}
}
}

void
DoEvent(EventRecord *pevent)
{
char key;
short part;
WindowPtr window;

switch(pevent->what){
case mouseDown:
part = FindWindow(pevent->where, &window);
switch(part){
case inMenuBar:
AdjustMenus();
DoMenuCommand(MenuSelect(pevent->where));
break;

case inSysWindow:/* let the system handle the mouseDown */
SystemClick(pevent, window);
break;

case inContent:
if(window != FrontWindow()){
SelectWindow(window);
}
break;

case inDrag:
DragWindow(window, pevent->where, &qd.screenBits.bounds);
break;
}
break;

case keyDown:
case autoKey:/* check for menukey equivalents */
key = (char)(pevent->message & charCodeMask);
if(pevent->modifiers & cmdKey){/* Command key down */
if(pevent->what == keyDown){
/* enable/disable/check menu items properly */
AdjustMenus();
DoMenuCommand(MenuKey(key));
}
}
break;
}
}

void
Enable(MenuHandle hmenu, short sItem, Boolean fEnable)
{
if(fEnable)
EnableItem(hmenu, sItem);
else
DisableItem(hmenu, sItem);
}

void
AdjustMenus()
{
Boolean fIsDA;
MenuHandle hmenu;

fIsDA = IsDAWindow(FrontWindow());

/* we can allow desk accessories to be closed from the menu */
hmenu = GetMHandle(mFile);
Enable(hmenu, iClose, fIsDA);

hmenu = GetMHandle(mEdit);
Enable(hmenu, iUndo, fIsDA);
Enable(hmenu, iCut, fIsDA);
Enable(hmenu, iCopy, fIsDA);
Enable(hmenu, iPaste, fIsDA);
Enable(hmenu, iClear, fIsDA);
}

void
DoMenuCommand(long menuResult)
{
short menuID;/* the resource ID of the selected menu */
short menuItem;/* the item number of the selected menu */
Str255 daName;

menuID = HiWord(menuResult);
menuItem = LoWord(menuResult);

switch(menuID){
case mApple:
switch(menuItem){
case iAbout:/* bring up alert for About */
Alert(rAboutAlert, NULL);
break;
default:
GetMenuItemText(GetMHandle(mApple), menuItem, daName);
OpenDeskAcc(daName);
break;
}
break;

case mFile:
switch(menuItem){
case iOpen:
{
BSTR bstrFileName;
if(GetFileName(&bstrFileName) != NOERROR)
{
// REVIEW: shouldnt just bag out here
Fatal((ConstStr255Param)"\pUnable to open Type Library");
}
OpenTypeLib(bstrFileName);
}
break;

case iQuit:
Quit();
break;
}
break;

case mEdit:
SystemEdit(menuItem-1);
break;
}

HiliteMenu(0);
}

extern "C" {

#if defined(_MSC_VER)
void pascal
#else
pascal void
#endif
DrawListbox(DialogPtr pdlg, short sItem)
{
Rect rc;
Handle h;
short kind;
GrafPtr port;
ListHandle hlist;

ASSERT(sItem == IDC_TYPELIST
|| sItem == IDC_MEMBERLIST
|| sItem == IDC_PARAMLIST);

GetPort(&port);
SetPort(pdlg);
hlist = g_rghlist[sItem];
LUpdate(pdlg->visRgn, hlist);
GetDItem(pdlg, sItem, &kind, &h, &rc);
InsetRect(&rc, -1, -1);
FrameRect(&rc);
SetPort(port);
}

}


/***
*ListHandle CreateListBox(DialogPtr, int)
*Purpose:
* Create a listbox on the given dialog, associated with the given
* control id.
*
*Entry:
* pdlg =
* ctlid =
*
*Exit:
* return value = ListHandle
*
***********************************************************************/
ListHandle
CreateListbox(DialogPtr pdlg, int ctlid)
{
Handle h;
short kind;
Point ptCell;
ListHandle hlist;
Rect rcView, rcBounds;

INIT_ROUTINE_DESC(NewUserItemProc,DrawListbox);

GetDItem(pdlg, ctlid, &kind, &h, &rcView);
SetDItem(pdlg, ctlid, kind, (Handle) ROUTINE_DESC(DrawListbox), &rcView);

// make room for scroll bars
rcView.right -= 15;

// list is 1 wide
SetRect(&rcBounds, 0, 0, 1, 0);

SetPt(&ptCell, 0, 0);

hlist = LNew(
&rcView,
&rcBounds,
ptCell,
0, (WindowPtr)pdlg, true, false, false, true);

ASSERT(hlist != NULL);

(*hlist)->selFlags = lUseSense | lNoRect | lNoExtend | lOnlyOne;

return hlist;
}

/***
*DialogPtr CreateDialog(void)
*Purpose:
* Create the TiBrowse dialog
*
*Entry:
* None
*
*Exit:
* return value = DialogPtr
*
***********************************************************************/
DialogPtr
CreateDialog()
{
int i;
Point pt;
DialogPtr pdlg;
ListHandle hlist;
static short rgctl[] = {IDC_TYPELIST, IDC_MEMBERLIST, IDC_PARAMLIST};

if((pdlg = GetNewDialog(rDlg, NULL, (WindowPtr)-1)) == NULL)
return NULL;

for(i = 0; i < DIM(rgctl); ++i){
g_rghlist[rgctl[i]] = CreateListbox(pdlg, rgctl[i]);
}

SetPt(&pt, 0, 0);
for(i = 0; i < DIM(rgctl); ++i){
hlist = g_rghlist[rgctl[i]];
LSetSelect(true, pt, hlist);
LDoDraw(true, hlist);
}

return pdlg;
}


void
Init()
{
Handle menuBar;

MaxApplZone();

InitGraf((Ptr)&qd.thePort);
InitFonts();
InitWindows();
InitMenus();
TEInit();
InitDialogs(NULL);
InitCursor();
FlushEvents(everyEvent, 0);

#ifndef _PPCMAC
if (InitOleManager(0) != NOERROR)
Fatal((ConstStr255Param)"\pCould not initialize OLE Applet");
#endif

if(OleInitialize(NULL) != NOERROR)
Fatal((ConstStr255Param)"\pUnable to Initialize Ole");

if((menuBar = GetNewMBar(rMenuBar)) == NULL)
Fatal((ConstStr255Param)"\pUnable to load menu bar");
SetMenuBar(menuBar);
DisposHandle(menuBar);
AddResMenu(GetMHandle(mApple), 'DRVR');
DrawMenuBar();

if((g_pdlg = CreateDialog()) == NULL)
Fatal((ConstStr255Param)"\pUnable to create dialog");
}

void
Quit()
{
Cleanup();
Uninit();
ExitToShell();
}

/* display fatal error alert, and exit */
void
Fatal(ConstStr255Param msg)
{
SetCursor(&qd.arrow);
ParamText(msg, (ConstStr255Param)"\p", (ConstStr255Param)"\p", (ConstStr255Param)"\p");
Alert(rUserAlert, nil);
Quit();
}

#else /* }{ */

long FAR PASCAL EXPORT WndProc (HWND, UINT, WPARAM, LPARAM) ;

int PASCAL
WinMain(
HINSTANCE hinst,
HINSTANCE hinstPrev,
LPSTR lpszCmdLine,
int nCmdShow)
{
MSG msg;
WNDCLASS wndclass;

if(!hinstPrev){
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = DLGWINDOWEXTRA ;
wndclass.hInstance = hinst ;
wndclass.hIcon = LoadIcon (hinst, g_szAppName) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1) ;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = g_szAppName ;

RegisterClass (&wndclass) ;
}

if(OleInitialize(NULL) != NOERROR){
MessageBox(NULL, TSTR("unable to initialize Ole"),
g_szAppName, MB_OK);
return 0;
}

g_hwnd = CreateDialog(hinst, g_szAppName, 0, NULL);

if(*lpszCmdLine == '\0'){
BSTR bstrFileName;
if(GetFileName(&bstrFileName) != NOERROR){
Cleanup();
Uninit();
exit(-1);
}
OpenTypeLib(bstrFileName);
SysFreeString(bstrFileName);
}else{
OpenTypeLib(lpszCmdLine);
}

ShowWindow(g_hwnd, nCmdShow);

while(GetMessage (&msg, NULL, 0, 0)){
TranslateMessage (&msg);
DispatchMessage (&msg);
}
Cleanup();
Uninit();
return msg.wParam;
}

long FAR PASCAL EXPORT
WndProc(
HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
unsigned long dwIndex;

switch(message){
case WM_COMMAND:
/* We deal with the following events:
* The selection changes on the type list and we have
* to update the member list & type info.
* The selection changes on the member list and we have
* to update the param list & member info.
* Selection changes on a parameter and we have to
* update the param info.
*/
#ifdef WIN32
# define wParamX LOWORD(wParam)
# define notifyMsg HIWORD(wParam)
#else
# define wParamX wParam
# define notifyMsg HIWORD(lParam)
#endif
switch(wParamX){
case IDC_TYPELIST:
if(notifyMsg == LBN_SELCHANGE){
dwIndex = SendDlgItemMessage(hwnd, IDC_TYPELIST, LB_GETCURSEL, 0, 0L);
if(dwIndex != LB_ERR)
SetSelectedType(dwIndex);
}
break;
case IDC_MEMBERLIST:
if(notifyMsg == LBN_SELCHANGE){
dwIndex = SendDlgItemMessage(hwnd, IDC_MEMBERLIST, LB_GETCURSEL,0,0L);
if(dwIndex != LB_ERR)
SetSelectedMember(dwIndex);
}
break;
case IDC_PARAMLIST:
if(notifyMsg == LBN_SELCHANGE){
dwIndex = SendDlgItemMessage(hwnd, IDC_PARAMLIST, LB_GETCURSEL, 0,0L);
if(dwIndex != LB_ERR)
SetSelectedParam(dwIndex);
}
break;
}
return 0;

case WM_DESTROY:
PostQuitMessage(0);
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}

#endif /* } */

void
MethodError(HRESULT hresult)
{
/* CONSIDER: add code to figure out what specific error this is */
UNUSED(hresult);

#ifdef _MAC
Fatal((ConstStr255Param)"\pType Library");
#else
MessageBox(NULL, TSTR("Error returned from TYPELIB.DLL"),
g_szAppName, MB_OK);
exit(1);
#endif
}

/* free using the task allocator */
void
MemFree(void FAR* pv)
{
HRESULT hresult;
IMalloc FAR* pmalloc;

hresult = CoGetMalloc(MEMCTX_TASK, &pmalloc);

if(hresult != NOERROR){
#ifdef _MAC
Fatal((ConstStr255Param)"\pError accessing task allocator");
#else
MessageBox(NULL, TSTR("Error accessing task allocator"),
g_szAppName, MB_OK);
#endif
return;
}

pmalloc->Free(pv);
pmalloc->Release();
}