C++ ActiveX开发的问题讨论
最近在一個(gè)項(xiàng)目中需要開(kāi)發(fā)一個(gè)ocx插件,在開(kāi)發(fā)過(guò)程中發(fā)現(xiàn)了一些問(wèn)題,所以在此記錄一下。
我想討論的主要是函數(shù)的參數(shù)問(wèn)題,我分別使用c++,JavaScript,C#對(duì)ocx插件做了測(cè)試,發(fā)現(xiàn)不同的參數(shù)類型在這幾種語(yǔ)言中表現(xiàn)的差異很大。
(1)首先ocx我是使用C++開(kāi)發(fā)的,所以在同樣使用c++語(yǔ)言開(kāi)發(fā)的程序中調(diào)用,所有的參數(shù)類型都沒(méi)有問(wèn)題。
(2)所有指針類型如:long *,float *,BSTR*作為參數(shù)時(shí),在JavaScript中調(diào)用都會(huì)失敗,可能在JavaScript中就不能支持這種指針傳參方式。
在C#中是能夠正常調(diào)用的。指針類型在C#中會(huì)被轉(zhuǎn)換為ref type類型,指明這個(gè)參數(shù)的值是能夠被函數(shù)內(nèi)部所修改的。像以下的調(diào)用方式是成功的。
ActiveX中的函數(shù)原型:
LONG CSimpleActiveXCtrl::GetData(LONG v1, LONG* v2)
{
?? ?AFX_MANAGE_STATE(AfxGetStaticModuleState());
?? ?*v2 = 10;
?? ?return v1;
}
C#自動(dòng)生成的函數(shù)定義:
public virtual int GetData(int v1, ref int v2);
C#中調(diào)用:
?int a=12, b=0;
??????? int c=axSimpleActiveX1.GetData(a,ref b);
雖然在C#中能夠正常調(diào)用,但是在JavaScript沒(méi)辦法調(diào)用,說(shuō)明這種類型不是通用的,如果你想你開(kāi)發(fā)的控件是通用的,應(yīng)該禁止使用指針類型。
?
(3)數(shù)組參數(shù)
如果你需要傳遞一個(gè)數(shù)組,參數(shù)類型可以定義為Variant,但是對(duì)于數(shù)組的處理,在C#中和JavaScript中又是不一樣的。JavaScript傳入的數(shù)組,其vt類型是VT_DISPATCH,
而C#傳入的數(shù)組不是VT_DISPATCH類型,所以取值或賦值的方式又不同了。如果你只需要取得數(shù)組的值,那么只需要定義為Variant類型就可以了,如果你需要修改數(shù)組
的值,用于C#需要定義為Variant*類型,而對(duì)于JavaScript只需要定義為Variant類型就可以。所以說(shuō)在不同語(yǔ)言里面的表現(xiàn)很不一樣。很顯然Variant類型也沒(méi)辦法做到通用。
ActiveX中的定義:
1)取數(shù)組長(zhǎng)度:
long CSimpleActiveXCtrl::GetArrayLength(VARIANT &v1)
{
??? if (v1.vt == VT_DISPATCH)?? //JS數(shù)組
?? ?{
?? ??? ?IDispatch* pDisp = v1.pdispVal;
?? ??? ?int ret;
?? ??? ?BSTR varName = L"length";
?? ??? ?VARIANT varValue;
?? ??? ?DISPPARAMS noArgs = { NULL, NULL, 0, 0 };
?? ??? ?DISPID dispId;
?? ??? ?HRESULT hr = 0;
?? ??? ?hr = pDisp->GetIDsOfNames(IID_NULL, &varName, 1, LOCALE_USER_DEFAULT, &dispId);
?? ??? ?if (FAILED(hr))
?? ??? ??? ?return hr;
?? ??? ?hr = pDisp->Invoke(dispId, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET, &noArgs, &varValue, NULL, NULL);
?? ??? ?if (SUCCEEDED(hr))
?? ??? ?{
?? ??? ??? ?ret = varValue.intVal;
?? ??? ??? ?return ret;
?? ??? ?}
?? ??? ?else
?? ??? ?{
?? ??? ??? ?return 0;
?? ??? ?}
?? ?}
?? ?else?? //C#數(shù)組
?? ?{
?? ??? ?long Low(0), High(0);
?? ??? ?SAFEARRAY* pArr1 = v1.parray;
?? ??? ?SafeArrayGetLBound(pArr1, 1, &Low);
?? ??? ?SafeArrayGetUBound(pArr1, 1, &High);
?? ??? ?long len = High - Low + 1;
?? ??? ?return len;
?? ?}
}
2)數(shù)組取值
bool CSimpleActiveXCtrl::GetArrayDataI(VARIANT &v1, int index, int &data)
{
if (v1.vt == VT_DISPATCH)??? //JS數(shù)組
?? ?{
?? ??? ?IDispatch* pDisp = v1.pdispVal;
?? ??? ?ATL::CComVariant varName(index, VT_I4); // 數(shù)組下標(biāo)
?? ??? ?DISPPARAMS noArgs = { NULL, NULL, 0, 0 };
?? ??? ?DISPID dispId;
?? ??? ?VARIANT varValue;
?? ??? ?HRESULT hr = 0;
?? ??? ?varName.ChangeType(VT_BSTR); // 將數(shù)組下標(biāo)轉(zhuǎn)為數(shù)字型,以進(jìn)行GetIDsOfNames
?? ??? ?//
?? ??? ?// 獲取通過(guò)下標(biāo)訪問(wèn)數(shù)組的過(guò)程,將過(guò)程名保存在dispId中
?? ??? ?//
?? ??? ?hr = pDisp->GetIDsOfNames(IID_NULL, &varName.bstrVal, 1, LOCALE_USER_DEFAULT, &dispId);
?? ??? ?if (FAILED(hr))
?? ??? ??? ?return false;
?? ??? ?//
?? ??? ?// 調(diào)用COM過(guò)程,訪問(wèn)指定下標(biāo)數(shù)組元素,根據(jù)dispId 將元素值保存在varValue中
?? ??? ?//
?? ??? ?hr = pDisp->Invoke(dispId, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET, &noArgs, &varValue, NULL, NULL);
?? ??? ?if (SUCCEEDED(hr))
?? ??? ?{
?? ??? ??? ?data = varValue.intVal;??? // 將數(shù)組元素按int類型取出
?? ??? ??? ?return true;
?? ??? ?}
?? ??? ?else
?? ??? ?{
?? ??? ??? ?return false;
?? ??? ?}
?? ?}
?? ?else?? //C#數(shù)組
?? ?{
?? ??? ?SAFEARRAY* pArr = v1.parray;
?? ??? ?int *pValue;
?? ??? ?SafeArrayAccessData(pArr, (void**)&pValue);
?? ??? ?data = pValue[index];
?? ??? ?SafeArrayUnaccessData(pArr);
?? ??? ?return true;
?? ?}
}
3)數(shù)組賦值
bool CSimpleActiveXCtrl::SetArrayDataI(VARIANT &v1, int index, int data)
{
if (v1.vt == VT_DISPATCH)?? //JS數(shù)組
?? ?{
?? ??? ?IDispatch* pDisp = v1.pdispVal;
?? ??? ?ATL::CComVariant varName(index, VT_I4);
?? ??? ?DISPID dispId;
?? ??? ?ATL::CComVariant varValue;
?? ??? ?HRESULT hr = 0;
?? ??? ?varName.ChangeType(VT_BSTR); // 將數(shù)組下標(biāo)轉(zhuǎn)為數(shù)字型,以進(jìn)行GetIDsOfNames
?? ??? ?hr = pDisp->GetIDsOfNames(IID_NULL, &varName.bstrVal, 1, LOCALE_USER_DEFAULT, &dispId);
?? ??? ?if (FAILED(hr))
?? ??? ??? ?return false;
?? ??? ?DISPID dispidPut = DISPID_PROPERTYPUT; // put操作
?? ??? ?DISPPARAMS dispparams;
?? ??? ?dispparams.rgvarg = new VARIANTARG[1]; // 初始化rgvarg
?? ??? ?dispparams.rgvarg[0].vt = VT_I4; // 數(shù)據(jù)類型
?? ??? ?dispparams.rgvarg[0].intVal = data; // 更新值
?? ??? ?dispparams.cArgs = 1; // 參數(shù)數(shù)量
?? ??? ?dispparams.cNamedArgs = 1; // 參數(shù)名稱
?? ??? ?dispparams.rgdispidNamedArgs = &dispidPut; // 操作DispId,表明本參數(shù)適用于put操作
?? ??? ?hr = pDisp->Invoke(dispId, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT, &dispparams, NULL, NULL, NULL);
?? ??? ?return true;
?? ?}
?? ?else??? //C#數(shù)組
?? ?{
?? ??? ?long Low(0), High(0);
?? ??? ?SAFEARRAY* pArr = v1.parray;
?? ??? ?int *pValue;
?? ??? ?SafeArrayAccessData(pArr, (void**)&pValue);
?? ??? ?pValue[index]=data;
?? ??? ?SafeArrayUnaccessData(pArr);
?? ??? ?return true;
?? ?}
}
?
4)JS數(shù)組拷貝
LONG CSimpleActiveXCtrl::CopyArrayData(VARIANT &v1, VARIANT &v2)
{
?? ?AFX_MANAGE_STATE(AfxGetStaticModuleState());
?? ?long len = GetArrayLength(v1);
?? ?for (int i = 0; i < len; i++)
?? ?{
?? ??? ?int value;
?? ??? ?GetArrayDataI(v1, i, value);
?? ??? ?SetArrayDataI(v2, i, value);
?? ?}
?? ?return 0;
}
5)C#數(shù)組拷貝
LONG CSimpleActiveXCtrl::CopyArray_CS(VARIANT &v1, VARIANT* v2)
{
?? ?AFX_MANAGE_STATE(AfxGetStaticModuleState());
?? ?// TODO:? 在此添加調(diào)度處理程序代碼
?? ?long len = GetArrayLength(v1);
?? ?for (int i = 0; i < len; i++)
?? ?{
?? ??? ?int value;
?? ??? ?GetArrayDataI(v1, i, value);
?? ??? ?SetArrayDataI(*v2, i, value);
?? ?}
?? ?return 0;
}
?
JS中的調(diào)用例子:
function CopyArrayClick()
{
?? ?? var arr1 = new Array();
?? ?? var arr2 = new Array();
?? ?? for (var i = 0; i < 10; i++)
?? ?? {
?? ??? ??? arr1[i] = i;
?? ??? ??? arr2[i] = 0;
?? ?? }
?? ?? var c = SimpleActiveX.CopyArrayData(arr1, arr2);
?? ?? var tmp = "";
?? ?? for (var j = 0; j < 10; j++)
?? ??? ??? tmp += arr2[j];
?? ?? document.getElementById("ResultDisplay").value = "arr2:" + tmp;
}
C#中的調(diào)用例子:
private void button1_Click(object sender, EventArgs e)
{
??????????? int[] arr1 = new int[10];
??????????? int[] arr2 = new int[10];
??????????? for (int i = 0; i < 10; i++)
??????????????? arr1[i] = i;
??????????? object var = new System.Runtime.InteropServices.VariantWrapper(arr2);
??????????? axSimpleActiveX1.CopyArray_CS(arr1, ref var);
??????????? int[] arr3 = var as int[];
??????????? string te="";
??????????? for (int i = 0; i < 10; i++)
??????????????? te += string.Format("{0} ", arr3[i]);
??????????????? textBox1.AppendText(te);
}
從上面的測(cè)試結(jié)果來(lái)看,對(duì)于ocx控件開(kāi)發(fā)中,參數(shù)的選擇我有以下的建議:
1.避免使用指針類型;
2.如果需要輸出參數(shù)應(yīng)該以函數(shù)返回值的方式返回,如果有多個(gè)參數(shù)要返回可以分成多個(gè)函數(shù)來(lái)實(shí)現(xiàn)或者通過(guò)屬性來(lái)返回;
3.個(gè)人認(rèn)為可以使用BSTR來(lái)替代數(shù)組,不管作為參數(shù)或者返回值都更容易實(shí)現(xiàn),在不同語(yǔ)言中對(duì)字符串的操作都是類似的。
轉(zhuǎn)載于:https://www.cnblogs.com/WushiShengFei/p/9298768.html
總結(jié)
以上是生活随笔為你收集整理的C++ ActiveX开发的问题讨论的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 花生壳绑定顶级域名
- 下一篇: 操作系统的运行机制和体系机构