VC2017下开发ATL程序注意事项
VC2017下開發(fā)ATL程序注意事項(xiàng)
kagula
2019-4-29
閱讀對(duì)象
? ? ? 早期做過ATL 項(xiàng)目開發(fā)的C++程序員.
?環(huán)境
? ? ?Windows10 Pro, Visual studio 2017/Visual studio 2019, IE11, C++ ATL x86項(xiàng)目.? ? ?
正文
? ? VC2017相對(duì)于VC2013對(duì)ATL開發(fā)不是很方便, 因?yàn)椴恢С譃锳TL Simple Object自動(dòng)添加function.
不過手動(dòng)添加member function也挺簡單的, 只要三個(gè)步驟就OK了.
? 本文應(yīng)該也適用于從VC2013過渡到VC2019的C++ ATL程序員.
假設(shè)你已經(jīng)通過VC2017的wizard添加了名為ZT410的ATL Simple Object.?
第一步:? 在idl文件中定義外部接口
interface IZT410 : IDispatch {HRESULT print([in]BSTR templateName, [in]VARIANT* arrContent, [out, retval]long *result);HRESULT sayHello([in]BSTR msg, [out,retval]BSTR *result); };通過wizard建立ZT410后,? ?wizard還會(huì)為你自動(dòng)生成IZT410(接口)代碼.
我為這個(gè)接口添加了print和sayHello方法, 用來演示ATL參數(shù)如何傳遞.
?
第二步: ZT410 Class中添加方法定義
打開ZT410.h找到CZT410 class的聲明, 在public后面添加print和sayHello的方法聲明
public:STDMETHODIMP print(BSTR templateName, VARIANT* arrContent, long *result);STDMETHODIMP sayHello(BSTR msg, BSTR *result);?
第三步(最后一步)
打開ZT410.cpp,? 在里面添加這兩個(gè)member function的實(shí)現(xiàn)
STDMETHODIMP CZT410::print(BSTR templateName, VARIANT* arrContent, long *result)?
STDMETHODIMP CZT410::sayHello(BSTR msg, BSTR *result) {using namespace std;wstring head = L"收到來自JavaScript的信息=>";wstring content = head + OLE2W(msg);*result = W2BSTR(content.c_str());return S_OK; }print的實(shí)現(xiàn)比較復(fù)雜,? 暫時(shí)不貼出來.
現(xiàn)在我們可以測試了
C#單元測試
新建C#單元測試項(xiàng)目, Unit Test Project(.Net Framework),?
Add Reference -> COM -> Type Libraries
you can see snippet below
[TestMethod]public void TestMethod1(){NingboHuashuPrinterLib.ZT410 printer = new NingboHuashuPrinterLib.ZT410();String[] arrContent = { "head", "中文測試", "tail" };int nResult = printer.print("abc", arrContent);System.Diagnostics.Trace.WriteLine(nResult);}IE11中JavaScript測試
<BODY><object classid ="clsid:9bc84eed-d69e-4ef6-8e4e-9d0d615ca08c" id="printer" name="printer"></object><script language ="JavaScript" type="text/javascript">function testSayHelloMethod(){var myArray = ["head","中文測試","tail"];var a = printer.print("AAA", myArray);alert(a);}</script><input type=button value ="測試我們的第一個(gè)ATL對(duì)象的方法" onclick="testSayHelloMethod()" /></BODY>上面的class id指的是coclass ZT410的uuid.
補(bǔ)充
通過JavaScript向ATL傳遞字符串?dāng)?shù)組, 可不是件簡單的事,? 下面貼出C++ ATL代碼, 免得同學(xué)們東找西找.
依賴的頭
#include <list> #include <vector> #include <string> #include <sstream>using namespace std;依賴的函數(shù)
std::string ws2s(const std::wstring& ws) {std::string curLocale = setlocale(LC_ALL, NULL); // curLocale = "C";setlocale(LC_ALL, "chs");const wchar_t* _Source = ws.c_str();size_t _Dsize = 2 * ws.size() + 1;char *_Dest = new char[_Dsize];memset(_Dest, 0, _Dsize);wcstombs(_Dest, _Source, _Dsize);std::string result = _Dest;delete[]_Dest;setlocale(LC_ALL, curLocale.c_str());return result; }CComPtr<IDispatch> VariantToDispatch(__in const CComVariant& var) {if (var.vt == VT_DISPATCH){return var.pdispVal;}return nullptr; }bool VariantToInt(CComVariant varIn, int &nOut) {VARTYPE vtype5;vtype5 = VT_INT;if (varIn.ChangeType(vtype5) == S_OK){nOut = varIn.intVal;return true;}return false; }bool VariantToArray(__in const CComVariant& var, __out vector<CComVariant>& vecVars) {// convert variant to dispatch objectCComPtr<IDispatch> pDispatch = VariantToDispatch(var);if (!pDispatch)return false;// get DISPID of length parameter from array objectLPOLESTR sLengthName = L"length";DISPID dispidLength = 0;HRESULT hr = pDispatch->GetIDsOfNames(IID_NULL, &sLengthName, 1, LOCALE_USER_DEFAULT, &dispidLength);if (FAILED(hr))return false;// get the number of elements using the DISPID of length parameterCComVariant varLength;DISPPARAMS dispParams = { 0 };hr = pDispatch->Invoke(dispidLength, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &dispParams, &varLength, NULL, NULL);if (FAILED(hr))return false;int nLength = 0; // length of the arraybool bGotInt = VariantToInt(varLength, nLength);if (!bGotInt)return false;// get items of arrayfor (int i = 0; i < nLength; ++i){// get DISPID of item[i] from array objectwstring strIndex = std::to_wstring(i);DISPID dispidIndex = 0;LPOLESTR pIndex = reinterpret_cast<LPOLESTR>(const_cast<WCHAR *>(strIndex.data()));hr = pDispatch->GetIDsOfNames(IID_NULL, &pIndex, 1, LOCALE_USER_DEFAULT, &dispidIndex);if (FAILED(hr))continue;CComVariant varItem;hr = pDispatch->Invoke(dispidIndex, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &dispParams, &varItem, NULL, NULL);if (FAILED(hr))continue;vecVars.push_back(varItem);}return true; }現(xiàn)在我們調(diào)用上面的函數(shù),實(shí)現(xiàn)對(duì)字符串?dāng)?shù)組的讀取
STDMETHODIMP CZT410::print(BSTR templateName, VARIANT* arrContent, long *result) {//string strTemplateName;[templateName, &strTemplateName]() {}();//list<string> listContent;[arrContent, &listContent]() {if (arrContent->vt == (VT_ARRAY | VT_BSTR)){//CSharp caller branch.//retrieve array sizelong *larr;long i;long lbound, ubound;::SafeArrayGetUBound(arrContent->parray, 1, &ubound);//inarr->parray就是safearray,第二個(gè)參數(shù)是第幾維度::SafeArrayGetLBound(arrContent->parray, 1, &lbound);const long arrSize = ubound - lbound + 1;#ifdef _DEBUGchar buffer[64] = { 0 };snprintf(buffer, sizeof(buffer), "%d %d", arrSize, arrContent->vt);MessageBoxA(NULL, buffer, NULL, 0); #endif//使用SafeArrayAccessData方法, 取出字符串元素, C#中測試通過BSTR HUGEP *pData;SafeArrayAccessData(arrContent->parray, (void HUGEP* FAR*)&pData);for (long i = lbound; i <= ubound; i++){BSTR pBSTR = pData[i];wstring wsTemp = pBSTR;listContent.push_back(ws2s(wsTemp));}SafeArrayUnaccessData(arrContent->parray);}else if (arrContent->vt == VT_DISPATCH){//JS caller branch.CComVariant ccv;vector<CComVariant> vecVars;ccv.Attach(arrContent);VariantToArray(ccv, vecVars);ccv.Detach(arrContent);for (vector<CComVariant>::iterator iter = vecVars.begin(); iter < vecVars.end(); iter++){if (iter->vt == VT_BSTR){std::wstring wsTemp = (LPCTSTR)iter->bstrVal;listContent.push_back(ws2s(wsTemp));}}//for}//if//不知道為什么使用SafeArrayGetElement方法取不出字符串元素.}();#ifdef _DEBUGstringstream ss;for (list<string>::iterator iter = listContent.begin(); iter != listContent.end(); iter++){ss << iter->c_str() << " ";} #endif//對(duì)listContent中的字符串進(jìn)行處理.//...ignore...//返回listContent中字符串的個(gè)數(shù).*result = listContent.size();return S_OK; }注意事項(xiàng)
? ?上面的ws2s的實(shí)現(xiàn)已經(jīng)過時(shí),? ?有時(shí)間修改為C++11的實(shí)現(xiàn)方式.
總結(jié)
以上是生活随笔為你收集整理的VC2017下开发ATL程序注意事项的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: flexnet许可证服务器_ANSYS
- 下一篇: Protobuf 介绍与实战9:将消息编