/***
*tibrowse.cpp
*
*  Copyright (C) 1992, Microsoft Corporation.  All Rights Reserved.
*  Information Contained Herein Is Proprietary and Confidential.
*
*Purpose:
*  Type Information Browser
*
*
*Implementation Notes:
*
*****************************************************************************/

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

#include "typbrows.h"

#include <initguid.h>

extern HWND hMainWnd;


ITypeLib  FAR *pTypeLib = NULL;
ITypeInfo FAR *pTypeInfoCur = NULL;
TYPEATTR  FAR *pTypeAttribs = NULL;

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



BOOL OpenTypeLib (TYPEINFOBLOCK *pTib)
{
	unsigned int utypeinfoCount, i;
	HRESULT hr ;
	

/* 
clear out globals and listboxes
*/
	Cleanup();

	SendDlgItemMessage(hMainWnd, IDC_TYPELIST, LB_RESETCONTENT, 0, 0L);
	SendDlgItemMessage(hMainWnd, IDC_MEMBERLIST, LB_RESETCONTENT, 0, 0L);
	SendDlgItemMessage(hMainWnd, IDC_PARAMLIST, LB_RESETCONTENT, 0, 0L);

/*
STEP 2
load the type library and find out how many type infos are in it
if bByName == TRUE, open it by name, otherwsie go to the registry and
do it by class ID
*/
    

/*
STEP 3
Get number of type infos
store in variable named	utypeinfoCount
*/

   

/*
For each type info in the library, get its name and add it to the type list
control in the dialog box.  The name comes in a BSTRING which we must free
*/

	BSTR bstrName;
		
	for(i = 0; i < utypeinfoCount; i++)
	{
	  pTypeLib->GetDocumentation(i, &bstrName, NULL, NULL, NULL);
	  SendDlgItemMessage (hMainWnd,IDC_TYPELIST,  LB_ADDSTRING, 0, (LPARAM)bstrName);
	  SysFreeString(bstrName);
	}               
	
	return TRUE;
}

/***
*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
*  pTypeInfoCur to refer to the typeinfo.
*
*Entry:
*  dwIndex =
*
*Exit:
*  return value = None
*
***********************************************************************/
void SetSelectedType(unsigned long dwIndex)
{
	HRESULT hr;
	BSTR bstrDoc, bstrHelpFile ;
	TCHAR FAR* psz;
	TCHAR szBuf[40];
	unsigned long dwHelpContext;
	TYPEKIND tkind;
    
/*
if there is a previous selection, release it.  And clear out the box.
*/
    
	if(pTypeInfoCur != NULL)
	{
	  pTypeInfoCur->ReleaseTypeAttr(pTypeAttribs);
	  pTypeInfoCur->Release();
	}

	SendDlgItemMessage(hMainWnd,IDC_MEMBERLIST, LB_RESETCONTENT, 0, 0L) ;

	if(pTypeLib == NULL)
	  return;

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

/*
STEP 4
Find the type of typeinfo this one is -- interface, class, etc.  Set
into dialog item edit control
*/



/*
STEP 4
Get the documentation string and help context from the type lib.
Place into their dialog items
*/


	wsprintf(szBuf, TEXT("%ld"), dwHelpContext);
	SetDlgItemText (hMainWnd,IDC_HELPCONTEXT, szBuf);

	psz = (bstrDoc != NULL) ? bstrDoc : TEXT("<none>");
	SetDlgItemText (hMainWnd,IDC_HELPSTRING, psz);
	
	psz = (bstrHelpFile != NULL) ? bstrHelpFile : TEXT("<none>") ;
	SetDlgItemText (hMainWnd, IDC_HELPFILE, psz) ;
	
	SysFreeString(bstrDoc);
	SysFreeString(bstrHelpFile) ;

/*
STEP 5
Get the specified type info and then get its attributes.
*/


/*
Get the GUID from the attributes and set it into its edit control
*/
	hr = StringFromCLSID(pTypeAttribs->guid, &psz);
	SetDlgItemText(hMainWnd, IDC_GUID, psz);
	MemFree(psz);

/*
Do the same for the version
*/
	wsprintf(szBuf, TEXT("%u.%02u"),
	  pTypeAttribs->wMajorVerNum, pTypeAttribs->wMinorVerNum);
	SetDlgItemText (hMainWnd,IDC_VERSION, szBuf);
	
/*
Go find the members and put them into their list.
*/

	FillMemberList(pTypeInfoCur, pTypeAttribs, IDC_MEMBERLIST);

	SendDlgItemMessage (hMainWnd, IDC_PARAMLIST, LB_RESETCONTENT, 0, 0L) ;
}

/***
*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.
	 */
	 
/*
STEP 6
For each function in the TYPEATTR, get its description in a FUNCDESC.  Use 
the member id from the funcdesc to get the function's name from the TypeInfo.
Place the name into the list box, then release the string and the funcdesc.
*/
	for(i = 0; i < pTypeattr->cFuncs; i++)
	{
	}
          
/*
For each variable in the TYPEATTR, get its description in a VARDESC.  Use
the member ID from the vardesc to get the variable's name from the TypeInfo.
Place the name into the list box, then release the string and the vardesc.
*/
      
	for(i = 0; i < pTypeattr->cVars; i++)
	{
	}
}

/***
*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;
	TCHAR out [128] ;
	
	SendDlgItemMessage (hMainWnd, IDC_PARAMLIST, LB_RESETCONTENT, 0, 0L) ;

	if(pTypeAttribs == NULL)
	  return;

/* 
if this is a function, fill the param list, otherwise just fill in the 
item info.
*/  

	if(dwIndex < pTypeAttribs->cFuncs)
	{
	  int i;
	  unsigned int cNames;
	  FUNCDESC FAR *pfuncdesc;
	  const unsigned int MAX_NAMES = 40;
	  BSTR rgNames[MAX_NAMES];  

    
/*
Get the funcdesc of the function.
*/
    
		pTypeInfoCur->GetFuncDesc((unsigned int) dwIndex, &pfuncdesc) ;
		memid = pfuncdesc->memid;
	  	UpdateMemberInfo(memid);      

/*
Get the type of the function, set name into edit control
*/
		GetFuncTypeName (pfuncdesc->invkind, out, sizeof(out));
		SetDlgItemText (hMainWnd, IDC_FUNCTYPE, out) ;

/*
if function takes no params, just set VOID into the edit control
*/


		if (pfuncdesc->cParams == 0) 
		{
			SendDlgItemMessage(hMainWnd, IDC_PARAMLIST, LB_ADDSTRING, 0, (LPARAM)(LPSTR)"[void]") ;
		}
		
/*
Use the memid of the funcdesc to get the list of names from the TypeInfo. 
Loop through them all to put them in the list box.  Free each when done,
and release the func desc.
*/
/*
Function isn't void.  Get the list of its parameter names.  The function 
name itself is the first name, so a name count > 1 means that the parameters
are named and that their names have been placed in the array after the func
name.  Loop through and put each name in the list box.
*/

		else 
		{
		
			pTypeInfoCur->GetNames(memid, rgNames, MAX_NAMES, &cNames) ;  
	  
			if (cNames > 1)
		  	{
	  			for(i = 1; i < cNames; i++)
	  			{
					SendDlgItemMessage(hMainWnd, IDC_PARAMLIST, LB_ADDSTRING, 0, (LPARAM)rgNames[i]);
					SysFreeString(rgNames[i]);
	  			}
	  		}
/*
Parameters aren't named.  Get their types from the FUNCDESC, get the 
name strings describing their types from our utility function.  Put
into list box. 
*/

			else
	  		{                 
	  			TCHAR type [128] ;
	  		
				for (i = 0 ; i < pfuncdesc->cParams; i++)
				{   
					VARTYPE vtype = ((pfuncdesc->lprgelemdescParam) + i)->tdesc.vt ;
					GetVarTypeName (vtype, out, sizeof(out)) ;
					wsprintf (type, TEXT("[%s]"), out) ;
					SendDlgItemMessage(hMainWnd, IDC_PARAMLIST, LB_ADDSTRING, 0, (LPARAM)type);
				}
	  		}
	  	}
	  	SysFreeString(rgNames[0]);   
	  
		pTypeInfoCur->ReleaseFuncDesc(pfuncdesc);
	}    
/*
Otherwise it's a variable, get its memid.  Get its type from the VARDESC,
get the name corresponding to this type from our utility function,
and put it in the list box
*/
	
	else
	{
	  	VARDESC FAR *pvardesc;
        TCHAR type [128] ;
        
	  	pTypeInfoCur->GetVarDesc(
		  (unsigned int)(dwIndex - pTypeAttribs->cFuncs), &pvardesc);
	  	memid = pvardesc->memid;
	  	UpdateMemberInfo(memid);
	  
	  	VARTYPE vtype = (pvardesc->elemdescVar).tdesc.vt ;
		GetVarTypeName (vtype, out, sizeof(out)) ;
		wsprintf (type, TEXT("[%s]"), out) ;
		SendDlgItemMessage(hMainWnd, IDC_PARAMLIST, LB_ADDSTRING, 0, (LPARAM)type);
	
	  	SetDlgItemText (hMainWnd, IDC_FUNCTYPE, (LPTSTR)TEXT("Variable")) ;

	  	pTypeInfoCur->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;
	TCHAR buf[40];
	unsigned long dwHelpContext;

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

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

/* 
update the help context displayed in the dialog 
*/
	wsprintf(buf, TEXT("%ld"), dwHelpContext);
	SetDlgItemText (hMainWnd,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)
{   

}

