Cypress Enable
Converting from Cypress Enable to WinWrap® Basic is easy.
- Minimal impact to the host application.
- Minimal changes to scripts.
Compatibility Chart
IDispatch
is used to extend the WinWrap Basic execution.
Converting from Cypress Enable requires that you implement a class
derived from IDispatch. IDispatch::GetIDsOfNames is called when
WinWrap Basic parses the script to determine what names your
language extension adds. WinWrap Basic execution of a language
extension method occurs in IDispatch::Invoke. So
converting requires that you implement an IDispatch to interface
to your already existing functions. It is not even necessary to
create a real COM type. You can just implement the IDispatch
interface according to the rules, add an instance of the class to
WinWrap Basic with AddExtension and your done.
AddExtension has a complicated set of options, but what you would
need is very simple:
IDispatch* pext = new MyLanguageExtension(...);
basic->AddExtension(_T(""), pext); // add names directly to WinWrap Basic
pext->Release(); // WinWrap Basic holds onto a reference
Class implementation:
class MyLanguageExtension : public IDispatch
{
private:
LONG m_refs;
public:
MyLanguageExtension() : m_refs(1) { /*...*/ }
~MyLanguageExtension() { /*...*/ } // can't be virtual
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject)
{
if (riid == IID_IUnknown || riid == IID_IDispatch) { AddRef(); *ppvObject = this; return NOERROR; }
return E_NOINTERFACE;
}
virtual ULONG STDMETHODCALLTYPE AddRef() { return ++m_refs; }
virtual ULONG STDMETHODCALLTYPE Release() { if (--m_refs) return m_refs; delete this; return 0; }
virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount(UINT *pctinfo) { *pctinfo = 0; return NOERROR; }
virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) { return E_NOTIMPL; }
virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
{
rgDispId[0] = FindMyExtensionName(rgszNames[0]); // return DISPID_UNKNOWN if not an extension name
if (rgDispId[0] == DISPID_UNKNOWN) return E_FAIL;
for (UINT i = 1; i < cNames; ++i) rgDispId[i] = DISPID_UNKNOWN; // don't support parameter names
return NOERROR;
}
virtual HRESULT STDMETHODCALLTYPE Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
{
// ignore riid, lcid
// wFlags tell invoke to do a call, get, let or set
switch (dispIdMember)
{
case DISPID_MyMethod1:
DispatchFuncMyMethod1(pDispParams,pVarResult);
break;
}
if (pExcepInfo) memset(pExcepInfo,0,sizeof(EXCEPINFO));
if (puArgErr) *puArgErr = (UINT)-1;
if (!ErrorInCalledMethod()) return NOERROR;
// set pExcepInfo
return DISP_E_EXCEPTION;
}
};
All the methods implemented by IDispatch::GetIDsOfNames/Invoke
are accessible from the WinWrap Basic script using names like
"MyMethod1".
Sub Main
MyMethod1 "Hello"
End Sub
Now, this approach is certainly the easiest way to
convert, but without a COM type WinWrap Basic's IDE can't show any
auto completion information. Also, WinWrap Basic supports early
binding through an IDispatch's dual interface. It is much faster
than going through IDispatch::Invoke. So instead of calling
DispatchFuncMyMethod1 WinWrap Basic can call MyMethod1
with normal parameters. Visual Studio and ATL make writing type
libraries and dual interfaces pretty easy.
These pages cover all the different language capabilities that
your application might want to implement using ATL:
ATL Tutorial
There are 4 different ways to integrate the IDE into a C++
application:
MFC Tutorial
Several complete sample applications are here:
MFC Samples
Copyright Polar Engineering, Inc.