// 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" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif 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) //}}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(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(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); } } ///////////////////////////////////////////////////////////////////////////// // CFoxtlibCtrl message handlers long CFoxtlibCtrl::TLLoadTypeLib(LPCTSTR szFileName) { 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(_NameTableIndex((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; __try { if (_FindVar(_NameTableIndex((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) < 3) { throw(631); //"Array argument not of proper size."); } StoreBstr(&loc,1,&bstrName); StoreBstr(&loc,2,&bstrDocString); StoreBstr(&loc,3,&bstrHelpFile); } } __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(_NameTableIndex((char *)szArrName),-1,&loc)) { BSTR rgbstrNames[20]; int cNames = 0; ((ITypeInfo *)pTypeInfo)->GetNames(nMemId,rgbstrNames,20,(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(_NameTableIndex((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(_NameTableIndex((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; }