aardio 文档
aardio 范例: 通过 C++ 调用 IAutoComplete 接口
//通过 C++ 调用 IAutoComplete 接口
/*
aardio 支持很多不同的接口,
例如下面就演示了使用 aardio 调用 C++ 的接口函数。
再用一句代码就将 C++/MFC 实现的 IDispatch 对象转换为了 aardio 对象。
使用 VC6 编译生成的 DLL 非常小只有 24 KB。
这是因为 VC6 的运行库是所有 Windows 系统自带的运行库,
可以动态连接系统库,从而可以生成更小的 DLL 文件。
*/
//用法请参考标准库 com.autoComplete 的源码。
import console.init;
import vc6;
var vc = vc6( "~/lib/com/autoComplete/.res/" )
/*
输入 C++ 源码,自动存为 autoComplete.cpp
- C++ 头文件的顺序不能错,afxwin.h,afxdisp.h 一定要最先导入
- 之后再导入 initguid.h ,然后再是 shlguid.h 等以最先初始化 GUID
- 然后再是导入其他头文件
- 仍然报错缺少的 CLSID_AutoComplete,IID_IAutoComplete 用 DEFINE_GUID 手动定义
这么做的好处是只要一个文件,生成极小的 DLL。
*/
vc.autoComplete = /******
#include <afxwin.h>
#include <afxdisp.h>
#include <initguid.h>
#include <shlguid.h>
#include <shldisp.h>
#include <shlobj.h>
DEFINE_GUID(CLSID_AutoComplete,0x00bb2763,0x6a77,0x11d0,0xa5,0x35,0x00,0xc0,0x4f,0xd7,0xd0,0x62);
DEFINE_GUID(IID_IAutoComplete,0x00bb2762,0x6a77,0x11d0,0xa5,0x35,0x00,0xc0,0x4f,0xd7,0xd0,0x62);
DEFINE_GUID(IID_IAutoComplete2,0xeac04bc0,0x3791,0x11d2,0xbb,0x95,0x00,0x60,0x97,0x7b,0x46,0x4c);
#include <vector>
#include <string>
class CEnumString : public IEnumString
{
private:
LONG m_cRef;
std::vector<std::wstring> m_strings;
size_t m_nCurrent;
public:
CEnumString() : m_cRef(1), m_nCurrent(0) {}
virtual ~CEnumString() {}
// IUnknown methods
STDMETHOD(QueryInterface)(REFIID riid, void **ppvObject)
{
if (riid == IID_IUnknown || riid == IID_IEnumString)
{
*ppvObject = static_cast<IEnumString*>(this);
AddRef();
return S_OK;
}
*ppvObject = NULL;
return E_NOINTERFACE;
}
STDMETHOD_(ULONG, AddRef)()
{
return InterlockedIncrement(&m_cRef);
}
STDMETHOD_(ULONG, Release)()
{
LONG cRef = InterlockedDecrement(&m_cRef);
if (cRef == 0)
delete this;
return cRef;
}
// IEnumString methods
STDMETHOD(Next)(ULONG celt, LPOLESTR *rgelt, ULONG *pceltFetched)
{
ULONG cFetched = 0;
while (m_nCurrent < m_strings.size() && cFetched < celt)
{
size_t len = (m_strings[m_nCurrent].length() + 1) * sizeof(WCHAR);
rgelt[cFetched] = (LPOLESTR)CoTaskMemAlloc(len);
if (rgelt[cFetched])
{
wcscpy(rgelt[cFetched], m_strings[m_nCurrent].c_str());
cFetched++;
m_nCurrent++;
}
else
{
return E_OUTOFMEMORY;
}
}
if (pceltFetched)
*pceltFetched = cFetched;
return (cFetched == celt) ? S_OK : S_FALSE;
}
STDMETHOD(Skip)(ULONG celt)
{
m_nCurrent += celt;
return (m_nCurrent <= m_strings.size()) ? S_OK : S_FALSE;
}
STDMETHOD(Reset)()
{
m_nCurrent = 0;
return S_OK;
}
STDMETHOD(Clone)(IEnumString **ppenum)
{
CEnumString *pNew = new CEnumString();
if (!pNew)
return E_OUTOFMEMORY;
pNew->m_strings = m_strings;
pNew->m_nCurrent = m_nCurrent;
*ppenum = pNew;
return S_OK;
}
void SetStrings(const std::vector<std::wstring>& strings)
{
m_strings = strings;
m_nCurrent = 0;
}
};
class CAutoCompleteObject : public CCmdTarget
{
DECLARE_DYNCREATE(CAutoCompleteObject)
public:
CAutoCompleteObject();
virtual ~CAutoCompleteObject();
protected:
HWND m_hwndEdit;
IAutoComplete2* m_pAutoComplete; // 改为原生指针
CEnumString* m_pEnumString;
bool m_bInitialized;
DWORD m_dwOptions;
public:
BOOL Initialize(HWND hwndEdit, DWORD dwOptions,LPCWSTR formatString);
afx_msg void SetStrings(const VARIANT& items);
afx_msg void SetOption(DWORD dwOptions);
afx_msg void Enable(BOOL bEnable);
afx_msg void Delete();
DECLARE_DISPATCH_MAP()
DECLARE_INTERFACE_MAP()
};
IMPLEMENT_DYNCREATE(CAutoCompleteObject, CCmdTarget)
CAutoCompleteObject::CAutoCompleteObject()
: m_hwndEdit(NULL), m_pAutoComplete(NULL), m_pEnumString(NULL), m_bInitialized(false), m_dwOptions(0)
{
EnableAutomation();
AfxOleLockApp();
}
CAutoCompleteObject::~CAutoCompleteObject()
{
Delete();
AfxOleUnlockApp();
}
BOOL CAutoCompleteObject::Initialize(HWND hwndEdit, DWORD dwOptions,LPCWSTR formatString)
{
if (!IsWindow(hwndEdit))
return FALSE;
m_hwndEdit = hwndEdit;
m_dwOptions = dwOptions;
HRESULT hr = CoCreateInstance(CLSID_AutoComplete, NULL, CLSCTX_INPROC_SERVER,
IID_IAutoComplete2, (void**)&m_pAutoComplete);
if (FAILED(hr))
return FALSE;
m_pEnumString = new CEnumString();
if (!m_pEnumString)
{
m_pAutoComplete->Release(); // 手动释放
m_pAutoComplete = NULL;
return FALSE;
}
hr = m_pAutoComplete->Init(m_hwndEdit, m_pEnumString, NULL, formatString);
if (FAILED(hr))
{
m_pEnumString->Release();
m_pEnumString = NULL;
m_pAutoComplete->Release(); // 手动释放
m_pAutoComplete = NULL;
return FALSE;
}
m_pAutoComplete->SetOptions(m_dwOptions);
m_pAutoComplete->Enable(TRUE);
m_bInitialized = true;
return TRUE;
}
void CAutoCompleteObject::SetStrings(const VARIANT& items)
{
if (!m_bInitialized || !m_pEnumString)
return;
std::vector<std::wstring> stringList;
if ((items.vt & VT_ARRAY) && (items.vt & VT_BSTR)) // VT_ARRAY | VT_BSTR
{
SAFEARRAY* psa = items.parray;
LONG lBound, uBound;
SafeArrayGetLBound(psa, 1, &lBound);
SafeArrayGetUBound(psa, 1, &uBound);
VARTYPE vtElement;
SafeArrayGetVartype(psa, &vtElement);
if (vtElement == VT_BSTR)
{
for (LONG i = lBound; i <= uBound; i++)
{
BSTR bstr;
SafeArrayGetElement(psa, &i, &bstr);
if (bstr)
{
stringList.push_back(std::wstring(bstr, SysStringLen(bstr)));
SysFreeString(bstr);
}
}
}
else if (vtElement == VT_VARIANT)
{
for (LONG i = lBound; i <= uBound; i++)
{
VARIANT var;
VariantInit(&var);
SafeArrayGetElement(psa, &i, &var);
// 尝试转换为字符串
VARIANT varStr;
VariantInit(&varStr);
if (SUCCEEDED(VariantChangeType(&varStr, &var, 0, VT_BSTR)))
{
stringList.push_back(std::wstring(varStr.bstrVal, SysStringLen(varStr.bstrVal)));
VariantClear(&varStr);
}
VariantClear(&var);
}
}
}
m_pEnumString->SetStrings(stringList);
if (m_pAutoComplete)
{
m_pEnumString->Reset();
}
}
void CAutoCompleteObject::SetOption(DWORD dwOptions)
{
if (!m_bInitialized || !m_pAutoComplete)
return;
m_dwOptions = dwOptions;
m_pAutoComplete->SetOptions(m_dwOptions);
}
void CAutoCompleteObject::Enable(BOOL bEnable)
{
if (!m_bInitialized || !m_pAutoComplete)
return;
m_pAutoComplete->Enable(bEnable);
}
void CAutoCompleteObject::Delete()
{
if (m_pAutoComplete)
{
m_pAutoComplete->Enable(FALSE);
m_pAutoComplete->Release(); // 手动释放
m_pAutoComplete = NULL;
}
if (m_pEnumString)
{
m_pEnumString->Release();
m_pEnumString = NULL;
}
m_bInitialized = false;
}
BEGIN_DISPATCH_MAP(CAutoCompleteObject, CCmdTarget)
DISP_FUNCTION(CAutoCompleteObject, "setStrings", SetStrings, VT_EMPTY, VTS_VARIANT)
DISP_FUNCTION(CAutoCompleteObject, "setOption", SetOption, VT_EMPTY, VTS_I4)
DISP_FUNCTION(CAutoCompleteObject, "enable", Enable, VT_EMPTY, VTS_BOOL)
DISP_FUNCTION(CAutoCompleteObject, "delete", Delete, VT_EMPTY, VTS_NONE)
END_DISPATCH_MAP()
BEGIN_INTERFACE_MAP(CAutoCompleteObject, CCmdTarget)
INTERFACE_PART(CAutoCompleteObject, IID_IDispatch, Dispatch)
END_INTERFACE_MAP()
extern "C" __declspec(dllexport) LPDISPATCH __cdecl CreateIDispatchObject(HWND hwndEdit, DWORD dwOptions/*,LPCWSTR formatString*/)
{
if (!IsWindow(hwndEdit))
return NULL;
CAutoCompleteObject* pObj = new CAutoCompleteObject();
if (!pObj){
return NULL;
}
if (!pObj->Initialize(hwndEdit, dwOptions,NULL))
{
delete pObj;
return NULL;
}
LPDISPATCH pDispatch = pObj->GetIDispatch(FALSE);
return pDispatch;
}
class CAutoCompleteApp : public CWinApp
{
public:
virtual BOOL InitInstance()
{
CWinApp::InitInstance();
// 在 aardio 里不需要这句
// if (FAILED(CoInitialize(NULL))) return FALSE;
return TRUE;
}
virtual int ExitInstance()
{
//在 aardio 里不需要这句
//CoUninitialize();
return CWinApp::ExitInstance();
}
};
CAutoCompleteApp theApp;
******/
//编译生成DLL
vc.exec(
'cl autoComplete.cpp'
,'/W3' /*警告等级*/
,'/MD' /*使用多线程动态运行库*/
,'/O2 /Ot /EHsc' /*代码优化选项*/
,'/D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "_AFXDLL" ' /*定义常数和宏*/
,'/I"./INCLUDE"'/*指定头文件目录*/
,'kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib shlwapi.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib' /*导入库*/
,'/link /SUBSYSTEM:WINDOWS /MACHINE:X86' /*后面是链接参数 */
,'/out:autoComplete.dll'/*输出文件名*/
,'/dll' /*输出DLL*/
,'/LIBPATH:".\LIB" /LIBPATH:".\LIB2"' /*指定库目录*/
)
Markdown 格式