logo WinWrap®

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:

ATL3 Tutorial

There are 4 different ways to integrate the IDE into a C++ application:

VC2010 Tutorial

Several complete sample applications are here:

VC6 Samples

Copyright Polar Engineering, Inc.