// FoxtlibCtl.cpp : Implementation of the CFoxtlibCtrl OLE control class. #include "stdafx.h" #include "foxtlib.h" #include "FoxtlibCtl.h" #include "FoxtlibPpg.h" #include "pro_ext.h" #include "malloc.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define MAXPARMS 20 //max # of names for SetFuncAndParamNames (1 + # of parms) #define VALUE_N_I(val) (val.ev_type =='I' ? val.ev_long : (long)val.ev_real) IMPLEMENT_DYNCREATE(CFoxtlibCtrl, COleControl) ///////////////////////////////////////////////////////////////////////////// // Message map BEGIN_MESSAGE_MAP(CFoxtlibCtrl, COleControl) //{{AFX_MSG_MAP(CFoxtlibCtrl) // NOTE - ClassWizard will add and remove message map entries // DO NOT EDIT what you see in these blocks of generated code ! //}}AFX_MSG_MAP ON_OLEVERB(AFX_IDS_VERB_EDIT, OnEdit) ON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // Dispatch map BEGIN_DISPATCH_MAP(CFoxtlibCtrl, COleControl) //{{AFX_DISPATCH_MAP(CFoxtlibCtrl) DISP_FUNCTION(CFoxtlibCtrl, "TLLoadTypeLib", TLLoadTypeLib, VT_I4, VTS_BSTR) DISP_FUNCTION(CFoxtlibCtrl, "TLRelease", TLRelease, VT_I4, VTS_I4) DISP_FUNCTION(CFoxtlibCtrl, "TLGetTypeInfoCount", TLGetTypeInfoCount, VT_I4, VTS_I4) DISP_FUNCTION(CFoxtlibCtrl, "TLGetTypeAttr", TLGetTypeAttr, VT_I4, VTS_I4 VTS_BSTR) DISP_FUNCTION(CFoxtlibCtrl, "TLGetTypeInfo", TLGetTypeInfo, VT_I4, VTS_I4 VTS_I4) DISP_FUNCTION(CFoxtlibCtrl, "TLGetDocumentation", TLGetDocumentation, VT_I4, VTS_I4 VTS_BSTR VTS_I4 VTS_I4) DISP_FUNCTION(CFoxtlibCtrl, "TIGetNames", TIGetNames, VT_I4, VTS_I4 VTS_BSTR VTS_I4) DISP_FUNCTION(CFoxtlibCtrl, "TIGetFuncDesc", TIGetFuncDesc, VT_I4, VTS_I4 VTS_BSTR VTS_I4 VTS_BSTR) DISP_FUNCTION(CFoxtlibCtrl, "TLWCreateTypeLib", TLWCreateTypeLib, VT_I4, VTS_BSTR VTS_PI4) DISP_FUNCTION(CFoxtlibCtrl, "TIGetVarDesc", TIGetVarDesc, VT_I4, VTS_I4 VTS_BSTR VTS_I4) DISP_FUNCTION(CFoxtlibCtrl, "TLWSaveAllChanges", TLWSaveAllChanges, VT_I4, VTS_I4) DISP_FUNCTION(CFoxtlibCtrl, "TIWCreateTypeInfo", TIWCreateTypeInfo, VT_I4, VTS_I4 VTS_I4 VTS_PI4 VTS_BSTR VTS_BSTR VTS_PI4) DISP_FUNCTION(CFoxtlibCtrl, "TLIWWriteDocumentation", TLIWWriteDocumentation, VT_I4, VTS_I4 VTS_BSTR VTS_BSTR VTS_I4 VTS_BSTR VTS_I4) DISP_FUNCTION(CFoxtlibCtrl, "TILayout", TILayout, VT_I4, VTS_I4) DISP_FUNCTION(CFoxtlibCtrl, "TIRelease", TIRelease, VT_I4, VTS_I4) DISP_FUNCTION(CFoxtlibCtrl, "TIAddFuncDesc", TIAddFuncDesc, VT_I4, VTS_I4 VTS_I4 VTS_BSTR VTS_BSTR VTS_BSTR VTS_I4) //}}AFX_DISPATCH_MAP END_DISPATCH_MAP() ///////////////////////////////////////////////////////////////////////////// // Event map BEGIN_EVENT_MAP(CFoxtlibCtrl, COleControl) //{{AFX_EVENT_MAP(CFoxtlibCtrl) // NOTE - ClassWizard will add and remove event map entries // DO NOT EDIT what you see in these blocks of generated code ! //}}AFX_EVENT_MAP END_EVENT_MAP() ///////////////////////////////////////////////////////////////////////////// // Property pages // TODO: Add more property pages as needed. Remember to increase the count! BEGIN_PROPPAGEIDS(CFoxtlibCtrl, 1) PROPPAGEID(CFoxtlibPropPage::guid) END_PROPPAGEIDS(CFoxtlibCtrl) ///////////////////////////////////////////////////////////////////////////// // Initialize class factory and guid IMPLEMENT_OLECREATE_EX(CFoxtlibCtrl, "FOXTLIB.FoxtlibCtrl.1", 0x22852ee3, 0xb01b, 0x11cf, 0xb8, 0x26, 0, 0xa0, 0xc9, 0x5, 0x5d, 0x9e) ///////////////////////////////////////////////////////////////////////////// // Type library ID and version IMPLEMENT_OLETYPELIB(CFoxtlibCtrl, _tlid, _wVerMajor, _wVerMinor) ///////////////////////////////////////////////////////////////////////////// // Interface IDs const IID BASED_CODE IID_DFoxtlib = { 0x22852ee9, 0xb01b, 0x11cf, { 0xb8, 0x26, 0, 0xa0, 0xc9, 0x5, 0x5d, 0x9e } }; const IID BASED_CODE IID_DFoxtlibEvents = { 0x22852eea, 0xb01b, 0x11cf, { 0xb8, 0x26, 0, 0xa0, 0xc9, 0x5, 0x5d, 0x9e } }; ///////////////////////////////////////////////////////////////////////////// // Control type information static const DWORD BASED_CODE _dwFoxtlibOleMisc = OLEMISC_INVISIBLEATRUNTIME | OLEMISC_SETCLIENTSITEFIRST | OLEMISC_INSIDEOUT | OLEMISC_CANTLINKINSIDE | OLEMISC_RECOMPOSEONRESIZE; IMPLEMENT_OLECTLTYPE(CFoxtlibCtrl, IDS_FOXTLIB, _dwFoxtlibOleMisc) ///////////////////////////////////////////////////////////////////////////// // CFoxtlibCtrl::CFoxtlibCtrlFactory::UpdateRegistry - // Adds or removes system registry entries for CFoxtlibCtrl BOOL CFoxtlibCtrl::CFoxtlibCtrlFactory::UpdateRegistry(BOOL bRegister) { // TODO: Verify that your control follows apartment-model threading rules. // Refer to MFC TechNote 64 for more information. // If your control does not conform to the apartment-model rules, then // you must modify the code below, changing the 6th parameter from // afxRegInsertable | afxRegApartmentThreading to afxRegInsertable. if (bRegister) return AfxOleRegisterControlClass( AfxGetInstanceHandle(), m_clsid, m_lpszProgID, IDS_FOXTLIB, IDB_FOXTLIB, afxRegInsertable | afxRegApartmentThreading, _dwFoxtlibOleMisc, _tlid, _wVerMajor, _wVerMinor); else return AfxOleUnregisterClass(m_clsid, m_lpszProgID); } ///////////////////////////////////////////////////////////////////////////// // CFoxtlibCtrl::CFoxtlibCtrl - Constructor CFoxtlibCtrl::CFoxtlibCtrl() { InitializeIIDs(&IID_DFoxtlib, &IID_DFoxtlibEvents); if (!_OCXAPI(AfxGetInstanceHandle(),DLL_PROCESS_ATTACH)) { ::MessageBox(0,"This OCX can only be hosted by Visual Foxpro","",0); //Here you can do whatever you want when the host isn't VFP: // you might want to reject loading or you might want to set a property //saying that the host isn't VFP and the control will use other means // to achieve it's purpose. } } ///////////////////////////////////////////////////////////////////////////// // CFoxtlibCtrl::~CFoxtlibCtrl - Destructor CFoxtlibCtrl::~CFoxtlibCtrl() { _OCXAPI(AfxGetInstanceHandle(),DLL_PROCESS_DETACH); } ///////////////////////////////////////////////////////////////////////////// // CFoxtlibCtrl::OnDraw - Drawing function void CFoxtlibCtrl::OnDraw( CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid) { // TODO: Replace the following code with your own drawing code. pdc->FillRect(rcBounds, CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH))); pdc->Ellipse(rcBounds); } ///////////////////////////////////////////////////////////////////////////// // CFoxtlibCtrl::DoPropExchange - Persistence support void CFoxtlibCtrl::DoPropExchange(CPropExchange* pPX) { ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor)); COleControl::DoPropExchange(pPX); // TODO: Call PX_ functions for each persistent custom property. } ///////////////////////////////////////////////////////////////////////////// // CFoxtlibCtrl::OnResetState - Reset control to default state void CFoxtlibCtrl::OnResetState() { COleControl::OnResetState(); // Resets defaults found in DoPropExchange // TODO: Reset any other control state here. } ///// #include "winnls.h" void OLEFreeString(void **ppsz) { HRESULT hr; IMalloc *pIMalloc; if (NULL != ppsz && NULL != *ppsz) { hr = CoGetMalloc(MEMCTX_TASK, &pIMalloc); if (FAILED(hr)) return; pIMalloc->Free(*ppsz); pIMalloc->Release(); *ppsz = NULL; } return; } HRESULT OLECopyAnsiToOle(const TEXT *pszA, OLECHAR *pszW, int cbW) { ULONG cchW; HRESULT hr; hr = NOERROR; cchW = cbW / sizeof(OLECHAR); // do this here in case cbW == 1 which is invalid if (!pszW || !cchW) { hr = ResultFromScode(E_INVALIDARG); } else { *pszW = '\0'; if (pszA && *pszA) { #if WIN32 if (MultiByteToWideChar(CP_ACP, 0, (LPSTR)pszA, -1, pszW, cchW) == 0) { *pszW = '\0'; hr = ResultFromScode(E_FAIL); } #elif MAC_OS // NO MAC UNICODE YET strncpy(pszW, (char *) pszA, cchW); #endif } } return (hr); } HRESULT OLEConvertStringAlloc(ULONG ulSize, void **ppv) { HRESULT hr; IMalloc *pIMalloc; // Reject zero-length strings, because a valid, but empty, ptr. would get // allocated, which might confuse the caller. if ((ulSize == 0) || (ppv == NULL)) { return (ResultFromScode(E_INVALIDARG)); } *ppv = NULL; hr = CoGetMalloc(MEMCTX_TASK, &pIMalloc); if (!SUCCEEDED(hr)) return (hr); *ppv = pIMalloc->Alloc(ulSize); pIMalloc->Release(); if (*ppv != NULL) memset(*ppv, 0, ulSize); return ((*ppv == NULL) ? ResultFromScode(E_OUTOFMEMORY) : ResultFromScode(NOERROR)); } HRESULT OLEAnsiToOleString(const TEXT *pszA, OLECHAR **ppszW) { ULONG cch, // character count cb; // byte count HRESULT hr; if (!ppszW) return (ResultFromScode(E_INVALIDARG)); *ppszW = NULL; hr = NOERROR; if (pszA) { #if WIN32 cch = MultiByteToWideChar(CP_ACP, 0, (LPSTR)pszA, -1, NULL, 0); #elif MAC_OS // NO MAC UNICODE YET cch = strlen((char *) pszA) + 1; #endif cb = cch * sizeof(OLECHAR); } if (SUCCEEDED(hr = OLEConvertStringAlloc(cb, (void **)ppszW))) { hr = OLECopyAnsiToOle(pszA, *ppszW, cb); if (FAILED(hr)) OLEFreeString((void **)ppszW); // This will set *ppszW = NULL. } return (hr); } HRESULT OLECopyOleToAnsi(OLECHAR *pszW, TEXT *pszA, int cbA) { HRESULT hr = NOERROR; if (!pszA || !cbA) { hr = ResultFromScode(E_INVALIDARG); } else { *pszA = '\0'; if (pszW && *pszW) { #if WIN32 if (WideCharToMultiByte(CP_ACP, 0, pszW, -1, (LPSTR)pszA, cbA, NULL, NULL) == 0) { *pszA = '\0'; hr = ResultFromScode(E_FAIL); } #elif MAC_OS // NO MAC UNICODE YET strncpy((char *) pszA, pszW, cbA); #endif } } return (hr); } HRESULT OLEOleToAnsiString(OLECHAR *pszW, TEXT **ppszA) { ULONG cch, // character count cb; // byte count HRESULT hr; if (!ppszA) return (ResultFromScode(E_INVALIDARG)); *ppszA = NULL; hr = NOERROR; if (pszW) { #if WIN32 cch = WideCharToMultiByte(CP_ACP, 0, pszW, -1, NULL, 0, NULL, NULL); #elif MAC_OS // NO MAC UNICODE YET cch = strlen(pszW) + 1; #endif cb = cch; if (SUCCEEDED(hr = OLEConvertStringAlloc(cb, (void **)ppszA))) { hr = OLECopyOleToAnsi(pszW, *ppszA, cb); if (FAILED(hr)) OLEFreeString((void **)ppszA); // This will set *ppszA = NULL. } } return (hr); } void StoreBstr(Locator *ploc,int index, BSTR *lpBstr) { char *szBuff; Value val; OLEOleToAnsiString(*lpBstr,&szBuff); SysFreeString(*lpBstr); val.ev_type = 'C'; ploc->l_sub1 = index; if (szBuff) { val.ev_length = strlen(szBuff); val.ev_handle = _AllocHand(val.ev_length); _HLock(val.ev_handle); _MemMove(_HandToPtr(val.ev_handle),szBuff,val.ev_length); _Store(ploc,&val); _HUnLock(val.ev_handle); _FreeHand(val.ev_handle); } else { val.ev_length = val.ev_handle = 0; _Store(ploc,&val); } } //Wrapper to work around a buffer allocation problem NTI MyNameTableIndex(char *name) { char szBuff[256]; strcpy(szBuff,name); return _NameTableIndex(szBuff); } ///////////////////////////////////////////////////////////////////////////// // CFoxtlibCtrl message handlers long CFoxtlibCtrl::TLLoadTypeLib(LPCTSTR szFileName) { Value val; _Evaluate(&val,"recno()+5"); _Execute("jj=eval('recno()')"); OLECHAR *OFileName; HRESULT hr; ITypeLib * lptlib; OLEAnsiToOleString((TEXT *)szFileName,&OFileName); hr = ::LoadTypeLib(OFileName, &lptlib); OLEFreeString((void **)&OFileName); if (SUCCEEDED(hr)) return (long)lptlib; return 0; } long CFoxtlibCtrl::TLRelease(long pTypeInfo) { int nResult; __try { nResult = ((ITypeLib *)pTypeInfo)->Release(); } __except (EXCEPTION_EXECUTE_HANDLER) { nResult = 0; } return nResult; } long CFoxtlibCtrl::TLGetTypeInfoCount(long pTypeInfo) { int nResult; __try { nResult = ((ITypeLib *)pTypeInfo)->GetTypeInfoCount(); } __except (EXCEPTION_EXECUTE_HANDLER) { nResult = 0; } return nResult; } long CFoxtlibCtrl::TLGetTypeAttr(long pTypeInfo, LPCTSTR szArrName) { int nResult = 1; TYPEATTR *lpTypeAttr; Locator loc; Value val; OLECHAR szGuid[128]; char *szBuff; __try { if (_FindVar(MyNameTableIndex((char *)szArrName),-1,&loc)) { ((ITypeInfo *)pTypeInfo)->GetTypeAttr(&lpTypeAttr); if (_ALen(loc.l_NTI, AL_ELEMENTS) < 16) { throw(631); //"Array argument not of proper size."); } //1 = Guid StringFromGUID2(lpTypeAttr->guid,(LPOLESTR )&szGuid,sizeof(szGuid)); OLEOleToAnsiString(szGuid,&szBuff); val.ev_type = 'C'; val.ev_length = strlen(szBuff); val.ev_handle = _AllocHand(val.ev_length); _HLock(val.ev_handle); _MemMove((char *)_HandToPtr(val.ev_handle),szBuff,val.ev_length); OLEFreeString((void **)&szBuff); _HUnLock(val.ev_handle); loc.l_sub1 = 1; _Store(&loc,&val); _FreeHand(val.ev_handle); //2 = LCID loc.l_sub1 = 2; val.ev_type = 'I'; val.ev_long = lpTypeAttr->lcid; _Store(&loc,&val); //3 dwReserved loc.l_sub1 = 3; val.ev_type = 'I'; val.ev_long = lpTypeAttr->dwReserved; _Store(&loc,&val); //4 Constructor loc.l_sub1 = 4; val.ev_type = 'I'; val.ev_long = lpTypeAttr->memidConstructor; _Store(&loc,&val); //5 Destructor loc.l_sub1 = 5; val.ev_type = 'I'; val.ev_long = lpTypeAttr->memidDestructor; _Store(&loc,&val); //6 lpstrSchema reserved loc.l_sub1 = 6; val.ev_type = 'I'; val.ev_long = (int)lpTypeAttr->lpstrSchema; _Store(&loc,&val); //7 size Instance loc.l_sub1 = 7; val.ev_type = 'I'; val.ev_long = lpTypeAttr->cbSizeInstance; _Store(&loc,&val); //8 TypeKind loc.l_sub1 = 8; val.ev_type = 'I'; val.ev_long = lpTypeAttr->typekind; _Store(&loc,&val); //9 cFuncs loc.l_sub1 = 9; val.ev_type = 'I'; val.ev_long = lpTypeAttr->cFuncs; _Store(&loc,&val); //10 cVars loc.l_sub1 = 10; val.ev_type = 'I'; val.ev_long = lpTypeAttr->cVars; _Store(&loc,&val); //11 cImplTypes loc.l_sub1 = 11; val.ev_type = 'I'; val.ev_long = lpTypeAttr->cImplTypes; _Store(&loc,&val); //12 cbSizeVft loc.l_sub1 = 12; val.ev_type = 'I'; val.ev_long = lpTypeAttr->cbSizeVft; _Store(&loc,&val); //13 cbAlignment loc.l_sub1 = 13; val.ev_type = 'I'; val.ev_long = lpTypeAttr->cbAlignment; _Store(&loc,&val); //14 wTypeFlags loc.l_sub1 = 14; val.ev_type = 'I'; val.ev_long = lpTypeAttr->wTypeFlags; _Store(&loc,&val); //15 wMajorVerNum loc.l_sub1 = 15; val.ev_type = 'I'; val.ev_long = lpTypeAttr->wMajorVerNum; _Store(&loc,&val); //16 wMinorVerNum loc.l_sub1 = 16; val.ev_type = 'I'; val.ev_long = lpTypeAttr->wMinorVerNum; _Store(&loc,&val); ((ITypeInfo *)pTypeInfo)->ReleaseTypeAttr(lpTypeAttr); } } __except (EXCEPTION_EXECUTE_HANDLER) { nResult = 0; } return nResult; } long CFoxtlibCtrl::TLGetTypeInfo(long pTypeInfo,long nIndex) { ITypeInfo * lpTypeInfo; int nResult; __try { nResult = ((ITypeLib *)pTypeInfo)->GetTypeInfo(nIndex,&lpTypeInfo); if (SUCCEEDED(nResult)) nResult = (int) lpTypeInfo; } __except (EXCEPTION_EXECUTE_HANDLER) { nResult = 0; } return nResult; } // =GetDocumentation(m.ITypeInfo,@ta,m.j) long CFoxtlibCtrl::TLGetDocumentation(long pTypeInfo, LPCTSTR szArrName, long nIndex,long nKind) { //Kind = 0 for TypeLib, 1 for TypeInfo int nResult = 1; BSTR bstrName; BSTR bstrDocString; unsigned long dwHelpContext; BSTR bstrHelpFile; Locator loc; Value val; __try { if (_FindVar(MyNameTableIndex((char *)szArrName),-1,&loc)) { if (nKind) { ((ITypeInfo *)pTypeInfo)->GetDocumentation(nIndex ,&bstrName,&bstrDocString, &dwHelpContext,&bstrHelpFile); } else { ((ITypeLib *)pTypeInfo)->GetDocumentation(nIndex ,&bstrName,&bstrDocString, &dwHelpContext,&bstrHelpFile); } if (_ALen(loc.l_NTI, AL_ELEMENTS) < 4) { throw(631); //"Array argument not of proper size."); } StoreBstr(&loc,1,&bstrName); StoreBstr(&loc,2,&bstrDocString); StoreBstr(&loc,3,&bstrHelpFile); loc.l_sub1 = 4; val.ev_type = 'I'; val.ev_long = dwHelpContext; _Store(&loc,&val); } } __except (EXCEPTION_EXECUTE_HANDLER) { nResult = 0; } return nResult; } long CFoxtlibCtrl::TIGetNames(long pTypeInfo, LPCTSTR szArrName, long nMemId) { int nResult = 1; Locator loc; __try { if (_FindVar(MyNameTableIndex((char *)szArrName),-1,&loc)) { BSTR rgbstrNames[MAXPARMS]; int cNames = 0; ((ITypeInfo *)pTypeInfo)->GetNames(nMemId,rgbstrNames,MAXPARMS,(UINT *)&cNames); if (cNames) { if (_ALen(loc.l_NTI, AL_ELEMENTS) < cNames) { throw(631); //"Array argument not of proper size."); } for (int i=1 ; i <= cNames ; i++) { //index through Fox array StoreBstr(&loc, i, &rgbstrNames[i-1]); } } nResult = cNames; } } __except (EXCEPTION_EXECUTE_HANDLER) { nResult = 0; } return nResult; } long CFoxtlibCtrl::TIGetFuncDesc(long pTypeInfo, LPCTSTR szArrName, long nIndex, LPCTSTR szParmsArr) { int nResult = 1; Locator loc,ploc; Value val; __try { if (_FindVar(MyNameTableIndex((char *)szArrName),-1,&loc)) { FUNCDESC * lpFuncDesc; if (_ALen(loc.l_NTI, AL_ELEMENTS) < 5) { throw(631); //"Array argument not of proper size."); } ((ITypeInfo *)pTypeInfo)->GetFuncDesc(nIndex,&lpFuncDesc); //1 = memid loc.l_sub1 = 1; val.ev_type = 'I'; val.ev_long = lpFuncDesc->memid; _Store(&loc,&val); if (_FindVar(MyNameTableIndex((char *)szParmsArr),-1,&ploc)) { int nelem = lpFuncDesc->cParams + lpFuncDesc->cParamsOpt; if (_ALen(loc.l_NTI, AL_ELEMENTS) < nelem) { throw(631); //"Array argument not of proper size."); } ploc.l_sub1 = 1; val.ev_type = 'I'; val.ev_long = (long) lpFuncDesc->elemdescFunc.tdesc.vt; _Store(&ploc,&val); for (int i = 0 ; i < nelem ; i++) { ploc.l_sub1 = 2 + i; //start parms at xbase array element #2 val.ev_type = 'I'; val.ev_long = (long)lpFuncDesc->lprgelemdescParam[i].tdesc.vt; _Store(&ploc,&val); } } //2 = FUNCKIND loc.l_sub1 = 2; val.ev_type = 'I'; val.ev_long = lpFuncDesc->funckind; _Store(&loc,&val); //3 = INVOKEKIND loc.l_sub1 = 3; val.ev_type = 'I'; val.ev_long = lpFuncDesc->invkind; _Store(&loc,&val); //4 = CALLCONV loc.l_sub1 = 4; val.ev_type = 'I'; val.ev_long = lpFuncDesc->callconv; _Store(&loc,&val); //5 = cParams loc.l_sub1 = 5; val.ev_type = 'I'; val.ev_long = lpFuncDesc->cParams; _Store(&loc,&val); //6 = cParamsOpt loc.l_sub1 = 6; val.ev_type = 'I'; val.ev_long = lpFuncDesc->cParamsOpt; _Store(&loc,&val); //7 = oVft; loc.l_sub1 = 7; val.ev_type = 'I'; val.ev_long = lpFuncDesc->oVft; _Store(&loc,&val); //8 = cScodes loc.l_sub1 = 8; val.ev_type = 'I'; val.ev_long = lpFuncDesc->cScodes; _Store(&loc,&val); //9 = wFuncFlags loc.l_sub1 = 9; val.ev_type = 'I'; val.ev_long = lpFuncDesc->wFuncFlags; _Store(&loc,&val); ((ITypeInfo *)pTypeInfo)->ReleaseFuncDesc(lpFuncDesc); } } __except (EXCEPTION_EXECUTE_HANDLER) { nResult = 0; } return nResult; } long ProcDesc(TYPEDESC *td) { long lVal = 0; switch(td->vt) { case VT_PTR: case VT_SAFEARRAY: lVal = ProcDesc(td->lptdesc); break; case VT_CARRAY: break; case VT_USERDEFINED: lVal= td->hreftype; break; default: break; } return lVal; } long CFoxtlibCtrl::TIGetVarDesc(long pTypeInfo, LPCTSTR szArrName, long nIndex) { int nResult = 1; Locator loc; Value val; __try { if (_FindVar(MyNameTableIndex((char *)szArrName),-1,&loc)) { VARDESC * lpVarDesc; if (_ALen(loc.l_NTI, AL_ELEMENTS) < 5) { throw(631); //"Array argument not of proper size."); } ((ITypeInfo *)pTypeInfo)->GetVarDesc(nIndex,&lpVarDesc); //1 = memid loc.l_sub1 = 1; val.ev_type = 'I'; val.ev_long = lpVarDesc->memid; _Store(&loc,&val); //2 = wVarFlags loc.l_sub1 = 2; val.ev_type = 'I'; val.ev_long = (long) lpVarDesc->wVarFlags; _Store(&loc,&val); //3 = Var kind loc.l_sub1 = 3; val.ev_type = 'I'; val.ev_long = (long) lpVarDesc->varkind; _Store(&loc,&val); //4 = Var type loc.l_sub1 = 4; val.ev_type = 'I'; val.ev_long = (long) lpVarDesc->elemdescVar.tdesc.vt; _Store(&loc,&val); //5 = wIDLFlags loc.l_sub1 = 5; val.ev_type = 'I'; val.ev_long = (long) lpVarDesc->elemdescVar.idldesc.wIDLFlags; _Store(&loc,&val); //6 = dwReserved loc.l_sub1 = 6; val.ev_type = 'I'; val.ev_long = (long) lpVarDesc->elemdescVar.idldesc.dwReserved; _Store(&loc,&val); //7,8 = mixture loc.l_sub1 = 7; val.ev_type = 'I'; switch(lpVarDesc->varkind) { case VAR_CONST: switch(lpVarDesc->lpvarValue->vt) { case VT_I4: val.ev_long = (long) lpVarDesc->lpvarValue->lVal; break; case VT_BOOL: val.ev_long = (long) lpVarDesc->lpvarValue->boolVal; break; // case VT_BSTR: //bugbug StoreBstr(&loc,7,&lpVarDesc->lpvarValue->bstrVal); // break; } break; case VAR_PERINSTANCE: val.ev_long = (long) lpVarDesc->oInst; break; default: val.ev_long = lpVarDesc->elemdescVar.tdesc.lptdesc->vt; _Store(&loc,&val); loc.l_sub1 = 8; val.ev_type = 'I'; val.ev_long = ProcDesc(&lpVarDesc->elemdescVar.tdesc); break; } _Store(&loc,&val); ((ITypeInfo *)pTypeInfo)->ReleaseVarDesc(lpVarDesc); } } __except (EXCEPTION_EXECUTE_HANDLER) { nResult = 0; } return nResult; } //********************************************* //********************************************* //********************************************* //Create Typelib stuff //********************************************* //********************************************* //********************************************* long CFoxtlibCtrl::TLWCreateTypeLib(LPCTSTR szTLBName,long *res) { HRESULT hr; LPCREATETYPELIB lpCreateTypeLib; OLECHAR *wTLBName; __try { *res = 0; OLEAnsiToOleString(szTLBName,&wTLBName); if ((hr = CreateTypeLib(SYS_WIN32,wTLBName,&lpCreateTypeLib)) == S_OK) { *res = (long)lpCreateTypeLib; } OLEFreeString((void **)&wTLBName); } __except (EXCEPTION_EXECUTE_HANDLER) { hr = E_FAIL; } return hr; } long CFoxtlibCtrl::TLWSaveAllChanges(long lpCreateTypeLib) //returns 0 on success { HRESULT hr = E_FAIL; __try { hr = ((ICreateTypeLib *)lpCreateTypeLib)->SaveAllChanges(); ((ICreateTypeLib *)lpCreateTypeLib)->Release(); } __except (EXCEPTION_EXECUTE_HANDLER) { hr = E_FAIL; } return hr; } /*HRESULT ICreateTypeInfo::AddRefTypeInfo(lptinfo, lphreftype) ITypeInfo FAR* lptinfo HREFTYPE FAR* lphreftype The second parameter returns a pointer to the handle of the added type information. If AddRefTypeInfo has been called previously for the same type information, the index that was returned by the previous call is returned in lphreftype. If the referenced type description is in the type library being created, its type information can be obtained by calling IUnknown::QueryInterface(IID_ITypeInfo, ...) on the ICreateTypeInfo interface of that type description. */ HRESULT AddImplType(LPCREATETYPEINFO lpCreateTypeInfo, REFIID riid,LPTYPEINFO lpTypeInfo) { HRESULT hresult = E_FAIL; char szFile[MAX_PATH]; OLECHAR *pOle; LPTYPELIB pITypeLib; LPTYPEINFO lpIDispatchTypeInfo; HREFTYPE hreftype; if ((hresult = lpCreateTypeInfo->AddRefTypeInfo(lpTypeInfo, &hreftype)) == NOERROR) { hresult = lpCreateTypeInfo->AddImplType(0, hreftype); } lpTypeInfo->Release(); return hresult; if ((riid == IID_IDispatch || riid == IID_IUnknown ) && GetSystemDirectory(szFile,sizeof(szFile)) > 0) { strcat(szFile, "\\stdole32.tlb"); } else { ASSERT(0); return 1; } if ((hresult = OLEAnsiToOleString(szFile, &pOle)) == NOERROR) { if ((hresult = LoadTypeLib(pOle, &pITypeLib)) == NOERROR) { hresult = pITypeLib->GetTypeInfoOfGuid(riid, &lpIDispatchTypeInfo); pITypeLib->Release(); } OLEFreeString((void **)&pOle); if (hresult == NOERROR) { if ((hresult = lpCreateTypeInfo->AddRefTypeInfo(lpIDispatchTypeInfo, &hreftype)) == NOERROR) { hresult = lpCreateTypeInfo->AddImplType(0, hreftype); } lpIDispatchTypeInfo->Release(); } } return hresult; } long CFoxtlibCtrl::TIWCreateTypeInfo(long lpCreateTypeLib, long TypeKind,long * res, LPCTSTR szArrName,LPCTSTR szTypeInfoName,long *lpTypeInfo) { LPCREATETYPEINFO lpCreateTypeInfo; int nResult = 1; Locator loc; Value val; HRESULT hr; OLECHAR *pOle; char szBuff[500]; GUID myguid; __try { if (_FindVar(MyNameTableIndex((char *)szArrName),-1,&loc)) { if (_ALen(loc.l_NTI, AL_ELEMENTS) < 16) { throw(631); //"Array argument not of proper size."); } OLEAnsiToOleString(szTypeInfoName,&pOle); hr = ((ICreateTypeLib *)lpCreateTypeLib)->CreateTypeInfo(pOle,(TYPEKIND)TypeKind, (ICreateTypeInfo **)&lpCreateTypeInfo); OLEFreeString((void **)&pOle); if (hr == TYPE_E_NAMECONFLICT) return hr; ASSERT(lpCreateTypeInfo); *res = (long) lpCreateTypeInfo; /* The second parameter returns a pointer to the handle of the added type information. If AddRefTypeInfo has been called previously for the same type information, the index that was returned by the previous call is returned in lphreftype. If the referenced type description is in the type library being created, its type information can be obtained by calling IUnknown::QueryInterface(IID_ITypeInfo, ...) on the ICreateTypeInfo interface of that type description. */ if (TKIND_DISPATCH == TypeKind) { LPDISPATCH lDisp; ((ICreateTypeInfo *)lpCreateTypeInfo)->QueryInterface(IID_ITypeInfo,(void **)&lDisp); *lpTypeInfo = (long)lDisp; } //17 = Guid loc.l_sub1 = 17; _Load(&loc,&val); ASSERT(val.ev_type == 'C'); _HLock(val.ev_handle); _MemMove(szBuff,(char *)_HandToPtr(val.ev_handle),val.ev_length); szBuff[val.ev_length] = '\0'; _HUnLock(val.ev_handle); _FreeHand(val.ev_handle); OLEAnsiToOleString(szBuff,&pOle); CLSIDFromString(pOle,&myguid); OLEFreeString((void **)&pOle); ((ICreateTypeInfo *)lpCreateTypeInfo)->SetGuid(myguid); //13 cbAlignment loc.l_sub1 = 13; _Load(&loc,&val); ASSERT(val.ev_type == 'I' || val.ev_type == 'N'); ((ICreateTypeInfo *)lpCreateTypeInfo)->SetAlignment((unsigned short)VALUE_N_I(val)); //14 wTypeFlags loc.l_sub1 = 14; _Load(&loc,&val); ASSERT(val.ev_type == 'I' || val.ev_type == 'N'); ((ICreateTypeInfo *)lpCreateTypeInfo)->SetTypeFlags(VALUE_N_I(val)); if (TypeKind == TKIND_COCLASS) { // if (VALUE_N_I(val) & TYPEFLAG_FCANCREATE) { AddImplType((ICreateTypeInfo *)lpCreateTypeInfo,IID_IDispatch,(LPTYPEINFO)*lpTypeInfo); } //15 wMajorVerNum loc.l_sub1 = 15; _Load(&loc,&val); ASSERT(val.ev_type == 'I' || val.ev_type == 'N'); int wMajorVerNum =(int)VALUE_N_I(val); //16 wMinorVerNum loc.l_sub1 = 16; _Load(&loc,&val); ASSERT(val.ev_type == 'I' || val.ev_type == 'N'); ((ICreateTypeInfo *)lpCreateTypeInfo)->SetVersion(wMajorVerNum,(unsigned short)VALUE_N_I(val)); /* //2 = LCID loc.l_sub1 = 2; ((ICreateTypeInfo *)lpTypeInfo)->SetGuid(myguid); val.ev_long = lpTypeAttr->lcid; //3 dwReserved loc.l_sub1 = 3; val.ev_type = 'I'; val.ev_long = lpTypeAttr->dwReserved; _Store(&loc,&val); //4 Constructor loc.l_sub1 = 4; val.ev_type = 'I'; val.ev_long = lpTypeAttr->memidConstructor; _Store(&loc,&val); //5 Destructor loc.l_sub1 = 5; val.ev_type = 'I'; val.ev_long = lpTypeAttr->memidDestructor; _Store(&loc,&val); //6 lpstrSchema reserved loc.l_sub1 = 6; val.ev_type = 'I'; val.ev_long = (int)lpTypeAttr->lpstrSchema; _Store(&loc,&val); //7 size Instance loc.l_sub1 = 7; val.ev_type = 'I'; val.ev_long = lpTypeAttr->cbSizeInstance; _Store(&loc,&val); //8 TypeKind loc.l_sub1 = 8; val.ev_type = 'I'; val.ev_long = lpTypeAttr->typekind; _Store(&loc,&val); //9 cFuncs loc.l_sub1 = 9; val.ev_type = 'I'; val.ev_long = lpTypeAttr->cFuncs; _Store(&loc,&val); //10 cVars loc.l_sub1 = 10; val.ev_type = 'I'; val.ev_long = lpTypeAttr->cVars; _Store(&loc,&val); //11 cImplTypes loc.l_sub1 = 11; val.ev_type = 'I'; val.ev_long = lpTypeAttr->cImplTypes; _Store(&loc,&val); //12 cbSizeVft loc.l_sub1 = 12; val.ev_type = 'I'; val.ev_long = lpTypeAttr->cbSizeVft; _Store(&loc,&val); */ } } __except (EXCEPTION_EXECUTE_HANDLER) { nResult = 0; } return nResult; } //This func has 2 modes: //If name is not empty, then pInterface is LPCREATETYPELIB // else pInterface is LPCREATETYPEINFO long CFoxtlibCtrl::TLIWWriteDocumentation(long pInterface, LPCTSTR Name, LPCTSTR DocString, long HelpContext, LPCTSTR HelpFile, long nIndex) { HRESULT hr = E_FAIL; OLECHAR *pOle; __try { if (*Name) { if (*Name == '@') { OLEAnsiToOleString(DocString,&pOle); ((LPCREATETYPEINFO)pInterface)->SetFuncDocString(nIndex,pOle); OLEFreeString((void **)&pOle); ((LPCREATETYPEINFO)pInterface)->SetFuncHelpContext(nIndex,HelpContext); } else { OLEAnsiToOleString(Name,&pOle); ((LPCREATETYPELIB)pInterface)->SetName(pOle); OLEFreeString((void **)&pOle); OLEAnsiToOleString(DocString,&pOle); ((LPCREATETYPELIB)pInterface)->SetDocString(pOle); OLEFreeString((void **)&pOle); ((LPCREATETYPELIB)pInterface)->SetHelpContext(HelpContext); } } else { OLEAnsiToOleString(DocString,&pOle); ((LPCREATETYPEINFO)pInterface)->SetDocString(pOle); OLEFreeString((void **)&pOle); } } __except (EXCEPTION_EXECUTE_HANDLER) { hr = E_FAIL; } return hr; } long CFoxtlibCtrl::TILayout(long lpCreateTypeInfo) // must be called to finish up writing a typeinfo { HRESULT hr; __try { hr = ((LPCREATETYPEINFO)lpCreateTypeInfo)->LayOut(); } __except (EXCEPTION_EXECUTE_HANDLER) { hr = E_FAIL; } return hr; } long CFoxtlibCtrl::TIRelease(long lpTypeInfo) { HRESULT hr; __try { hr = ((LPTYPEINFO)lpTypeInfo)->Release(); } __except (EXCEPTION_EXECUTE_HANDLER) { hr = E_FAIL; } return hr; } long CFoxtlibCtrl::TIAddFuncDesc(long lpCreateTypeInfo, long nIndex, LPCTSTR szArrName, LPCTSTR szParmsArr, LPCTSTR szNamesArr,long nNames) { HRESULT hr; int i; FUNCDESC FuncDesc; ELEMDESC edesc[1]; Locator loc,locNames,locParms; Value val; int nParams; char szBuff[255]; OLECHAR * pOleArr[MAXPARMS]; __try { if (_FindVar(MyNameTableIndex((char *)szArrName),-1,&loc)) { if (_ALen(loc.l_NTI, AL_ELEMENTS) < 16) { throw(631); //"Array argument not of proper size."); } memset(&FuncDesc,0,sizeof(FuncDesc)); //1 = Memid loc.l_sub1 = 1; _Load(&loc,&val); ASSERT(val.ev_type == 'I' || val.ev_type == 'N'); FuncDesc.memid = (int)VALUE_N_I(val); //2 = FUNCKIND loc.l_sub1 = 2; _Load(&loc,&val); ASSERT(val.ev_type == 'I' || val.ev_type == 'N'); FuncDesc.funckind = (FUNCKIND)VALUE_N_I(val); //3 = INVOKEKIND loc.l_sub1 = 3; _Load(&loc,&val); ASSERT(val.ev_type == 'I' || val.ev_type == 'N'); FuncDesc.invkind = (INVOKEKIND)VALUE_N_I(val); //4 = CALLCONV loc.l_sub1 = 4; _Load(&loc,&val); ASSERT(val.ev_type == 'I' || val.ev_type == 'N'); FuncDesc.callconv = (CALLCONV)VALUE_N_I(val); //5 = cParams loc.l_sub1 = 5; _Load(&loc,&val); ASSERT(val.ev_type == 'I' || val.ev_type == 'N'); FuncDesc.cParams = (short) VALUE_N_I(val); //6 = cParamsOpt loc.l_sub1 = 6; _Load(&loc,&val); ASSERT(val.ev_type == 'I' || val.ev_type == 'N'); FuncDesc.cParamsOpt = (short)VALUE_N_I(val); nParams = FuncDesc.cParams + FuncDesc.cParamsOpt; //8 = cScodes loc.l_sub1 = 8; _Load(&loc,&val); ASSERT(val.ev_type == 'I' || val.ev_type == 'N'); FuncDesc.cScodes = (SHORT)VALUE_N_I(val); //9 = wFuncFlags loc.l_sub1 = 9; _Load(&loc,&val); FuncDesc.wFuncFlags = (WORD) VALUE_N_I(val); if (!_FindVar(MyNameTableIndex((char *)szParmsArr),-1,&locParms)) { throw 631; } //get the type of the return value locParms.l_sub1 = 1; _Load(&locParms,&val); ASSERT(val.ev_type == 'I' || val.ev_type == 'N'); switch (FuncDesc.invkind) { case INVOKE_PROPERTYGET: // return type FuncDesc.elemdescFunc.tdesc.vt = (VARTYPE) VALUE_N_I(val); break; case INVOKE_FUNC: case INVOKE_PROPERTYPUT: // 'Parameter info' edesc[0].tdesc.vt = (VARTYPE) VALUE_N_I(val); FuncDesc.lprgelemdescParam = (ELEMDESC *)edesc; // return type FuncDesc.elemdescFunc.tdesc.vt = VT_VOID; break; case INVOKE_PROPERTYPUTREF: break; default: ASSERT(0); } if (nParams) { FuncDesc.lprgelemdescParam = (LPELEMDESC)_alloca((FuncDesc.cParams +1)* sizeof(ELEMDESC)); memset(FuncDesc.lprgelemdescParam,0,FuncDesc.cParams * sizeof(FuncDesc)); for (int i =0 ; i< nParams ; i++) { locParms.l_sub1 = i + 2; _Load(&locParms,&val); ASSERT(val.ev_type == 'I' || val.ev_type == 'N'); FuncDesc.lprgelemdescParam[i].tdesc.vt = (VARTYPE)VALUE_N_I(val); } } hr = ((LPCREATETYPEINFO)lpCreateTypeInfo)->AddFuncDesc(nIndex,&FuncDesc); if (!_FindVar(MyNameTableIndex((char *)szNamesArr),-1,&locNames)) { throw(631); } if (_ALen(locNames.l_NTI, AL_ELEMENTS) < MAXPARMS) { throw(631); //"Array argument not of proper size."); } for (i = 0 ; i < nNames ; i++) { locNames.l_sub1 = i+1; _Load(&locNames,&val); ASSERT(val.ev_type == 'C'); _HLock(val.ev_handle); _MemMove(szBuff,_HandToPtr(val.ev_handle),val.ev_length); _HUnLock(val.ev_handle); _FreeHand(val.ev_handle); szBuff[val.ev_length] = '\0'; OLEAnsiToOleString(szBuff,&pOleArr[i]); } hr = ((LPCREATETYPEINFO)lpCreateTypeInfo)->SetFuncAndParamNames(nIndex,pOleArr,nNames); for (i = 0 ; i < nNames ; i++) { OLEFreeString((void **)&pOleArr[i]); } /* if (_FindVar(MyNameTableIndex((char *)szParmsArr),-1,&ploc)) { int nelem = lpFuncDesc->cParams + lpFuncDesc->cParamsOpt; if (_ALen(loc.l_NTI, AL_ELEMENTS) < nelem) { throw(631); //"Array argument not of proper size."); } ploc.l_sub1 = 1; val.ev_type = 'I'; val.ev_long = (long) lpFuncDesc->elemdescFunc.tdesc.vt; _Store(&ploc,&val); for (int i = 0 ; i < nelem ; i++) { ploc.l_sub1 = 2 + i; //start parms at xbase array element #2 val.ev_type = 'I'; val.ev_long = (long)lpFuncDesc->lprgelemdescParam[i].tdesc.vt; _Store(&ploc,&val); } } //7 = oVft; loc.l_sub1 = 7; val.ev_type = 'I'; val.ev_long = lpFuncDesc->oVft; _Store(&loc,&val); //8 = cScodes loc.l_sub1 = 8; val.ev_type = 'I'; val.ev_long = lpFuncDesc->cScodes; _Store(&loc,&val); //9 = wFuncFlags loc.l_sub1 = 9; val.ev_type = 'I'; val.ev_long = lpFuncDesc->wFuncFlags; _Store(&loc,&val); ((ITypeInfo *)pTypeInfo)->ReleaseFuncDesc(lpFuncDesc); */ } } __except (EXCEPTION_EXECUTE_HANDLER) { hr = E_FAIL; } return hr; }