C++ ActiveX开发的问题讨论

最近在一个项目中需要开发一个ocx插件,在开发过程中发现了一些问题,所以在此记录一下。

我想讨论的主要是函数的参数问题,我分别使用c++,JavaScript,C#对ocx插件做了测试,发现不同的参数类型在这几种语言中表现的差异很大。

(1)首先ocx我是使用C++开发的,所以在同样使用c++语言开发的程序中调用,所有的参数类型都没有问题。

(2)所有指针类型如:long *,float *,BSTR*作为参数时,在JavaScript中调用都会失败,可能在JavaScript中就不能支持这种指针传参方式。

在C#中是能够正常调用的。指针类型在C#中会被转换为ref type类型,指明这个参数的值是能够被函数内部所修改的。像以下的调用方式是成功的。

ActiveX中的函数原型:

LONG CSimpleActiveXCtrl::GetData(LONG v1, LONG* v2)
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());
    *v2 = 10;
    return v1;
}

C#自动生成的函数定义:

public virtual int GetData(int v1, ref int v2);

C#中调用:

   int a=12, b=0;
        int c=axSimpleActiveX1.GetData(a,ref b);

虽然在C#中能够正常调用,但是在JavaScript没办法调用,说明这种类型不是通用的,如果你想你开发的控件是通用的,应该禁止使用指针类型。

 

(3)数组参数

如果你需要传递一个数组,参数类型可以定义为Variant,但是对于数组的处理,在C#中和JavaScript中又是不一样的。JavaScript传入的数组,其vt类型是VT_DISPATCH,

而C#传入的数组不是VT_DISPATCH类型,所以取值或赋值的方式又不同了。如果你只需要取得数组的值,那么只需要定义为Variant类型就可以了,如果你需要修改数组

的值,用于C#需要定义为Variant*类型,而对于JavaScript只需要定义为Variant类型就可以。所以说在不同语言里面的表现很不一样。很显然Variant类型也没办法做到通用。

ActiveX中的定义:

1)取数组长度:

long CSimpleActiveXCtrl::GetArrayLength(VARIANT &v1)
{
    if (v1.vt == VT_DISPATCH)   //JS数组
    {
        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#数组
    {
        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)数组取值

bool CSimpleActiveXCtrl::GetArrayDataI(VARIANT &v1, int index, int &data)

{

 if (v1.vt == VT_DISPATCH)    //JS数组
    {
        IDispatch* pDisp = v1.pdispVal;
        ATL::CComVariant varName(index, VT_I4); // 数组下标
        DISPPARAMS noArgs = { NULL, NULL, 0, 0 };
        DISPID dispId;
        VARIANT varValue;
        HRESULT hr = 0;
        varName.ChangeType(VT_BSTR); // 将数组下标转为数字型,以进行GetIDsOfNames
        //
        // 获取通过下标访问数组的过程,将过程名保存在dispId中
        //
        hr = pDisp->GetIDsOfNames(IID_NULL, &varName.bstrVal, 1, LOCALE_USER_DEFAULT, &dispId);
        if (FAILED(hr))
            return false;
        //
        // 调用COM过程,访问指定下标数组元素,根据dispId 将元素值保存在varValue中
        //
        hr = pDisp->Invoke(dispId, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET, &noArgs, &varValue, NULL, NULL);
        if (SUCCEEDED(hr))
        {
            data = varValue.intVal;    // 将数组元素按int类型取出
            return true;
        }
        else
        {
            return false;
        }
    }
    else   //C#数组
    {
        SAFEARRAY* pArr = v1.parray;
        int *pValue;
        SafeArrayAccessData(pArr, (void**)&pValue);
        data = pValue[index];
        SafeArrayUnaccessData(pArr);
        return true;
    }

}

3)数组赋值

bool CSimpleActiveXCtrl::SetArrayDataI(VARIANT &v1, int index, int data)

{

 if (v1.vt == VT_DISPATCH)   //JS数组
    {
        IDispatch* pDisp = v1.pdispVal;
        ATL::CComVariant varName(index, VT_I4);
        DISPID dispId;
        ATL::CComVariant varValue;
        HRESULT hr = 0;
        varName.ChangeType(VT_BSTR); // 将数组下标转为数字型,以进行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; // 数据类型
        dispparams.rgvarg[0].intVal = data; // 更新值
        dispparams.cArgs = 1; // 参数数量
        dispparams.cNamedArgs = 1; // 参数名称
        dispparams.rgdispidNamedArgs = &dispidPut; // 操作DispId,表明本参数适用于put操作

        hr = pDisp->Invoke(dispId, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT, &dispparams, NULL, NULL, NULL);
        return true;
    }
    else    //C#数组
    {
        long Low(0), High(0);
        SAFEARRAY* pArr = v1.parray;
        int *pValue;
        SafeArrayAccessData(pArr, (void**)&pValue);
        pValue[index]=data;
        SafeArrayUnaccessData(pArr);
        return true;
    }

}

 

4)JS数组拷贝

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#数组拷贝

LONG CSimpleActiveXCtrl::CopyArray_CS(VARIANT &v1, VARIANT* v2)
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState());

    // TODO:  在此添加调度处理程序代码
    long len = GetArrayLength(v1);
    for (int i = 0; i < len; i++)
    {
        int value;
        GetArrayDataI(v1, i, value);
        SetArrayDataI(*v2, i, value);
    }
    return 0;
}

 

JS中的调用例子:

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#中的调用例子:

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);
}

从上面的测试结果来看,对于ocx控件开发中,参数的选择我有以下的建议:

1.避免使用指针类型;

2.如果需要输出参数应该以函数返回值的方式返回,如果有多个参数要返回可以分成多个函数来实现或者通过属性来返回;

3.个人认为可以使用BSTR来替代数组,不管作为参数或者返回值都更容易实现,在不同语言中对字符串的操作都是类似的。

转载于:https://www.cnblogs.com/WushiShengFei/p/9298768.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/413749.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[vue-cli]vue-cli3插件有写过吗?怎么写一个代码生成插件?

[vue-cli]vue-cli3插件有写过吗&#xff1f;怎么写一个代码生成插件&#xff1f; MyPlugin.install function (Vue, options) { // 1. 添加全局方法或属性 Vue.myGlobalMethod function () { // 逻辑... }// 2. 添加全局资源 Vue.directive(my-directive, { bind (el, bindi…

javaScript数据类型(包括基本数据类型和非基本数据类型)

一、五种基本数据类型 1、number 数字类型 - 包括浮点数和整数&#xff0c;例如&#xff1a;1,100,3.14 2、string 字符串类型 - 包括任意数字字符组成的序列&#xff0c;例如&#xff1a;“1”&#xff0c; “one”&#xff0c; “one 2 one” 3、boolean 布尔类型 - 包括 t…

Codeforces Round #496 (Div. 3 ) E1. Median on Segments (Permutations Edition)(中位数计数)

E1. Median on Segments (Permutations Edition)time limit per test3 secondsmemory limit per test256 megabytesinputstandard inputoutputstandard outputYou are given a permutation p1,p2,…,pnp1,p2,…,pn. A permutation of length nn is a sequence such that each i…

数组转换为字符串方法

1. toString() 方法 和 toLocaleString() 方法 var arr [ "a", "b", "c"]; alert(arr.toString()); // a,b,c alert(arr.toLocaleString()); // a,b,c 返回数组的字符串表示&#xff0c;中间以逗号隔开 2. join() 方法 var a…

[vue-cli]vue-cli生成的项目可以使用es6、es7的语法吗?为什么?

[vue-cli]vue-cli生成的项目可以使用es6、es7的语法吗&#xff1f;为什么&#xff1f; vue-cli 配置了babel,可以将es6,es7....etc在webpack打包的时候转换成es5的代码&#xff0c;所以上线的时候没有问题。但是脚手架只是配置了一些默认常见的用法&#xff0c; 可以根据babel…

做小程序的流程总结(基本篇)

一、首先当我们借助小程序实现我们的网站搭建时&#xff0c;就需要使用小程序自带的一些功能&#xff1b;且需要根据该小程序获取到的一些参数存储到对应的数据库中。 openID&#xff1a;每个微信用户使用该小程序时都会产生一个openID&#xff0c;且该openID是唯一标识&#x…

js对象数组 按对象的某一属性进行去重

var array [{ id: 1, name: "张三"},{ id: 2, name: "李四"},{ id: 3, name: "张龙"},{ id: 4, name: "赵虎"},{ id: 5, name: "王朝"},{ id: 1, name: "刘金刚"},{ id: 6, name: "马汉"}, ]var obj …

[vue-cli]vue-cli怎么解决跨域的问题?

[vue-cli]vue-cli怎么解决跨域的问题&#xff1f; 在根目录下新建&#xff1a;vue.config.js注意名不能错误&#xff0c;然后里面配置 module.exports { devServer: { proxy: { //配置跨域 /api: { target: 跨域url, ws: true, changOrigin: true // pathRewrite: { // ^/api…

java - springmvc整合cxf发布webservice

1.jar包已上传百度云盘&#xff0c;在jar包目录下 2.web.xml配置 <web-app xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance" xmlns"http://java.sun.com/xml/ns/javaee" xsi:schemaLocation" http://java.sun.com/xml/ns/javaee http://jav…

CSS3 选择前几个元素 选择后几个元素等问题

//例如有如下代码块 <div><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p> </div>1.选择第n个p div:nth-child(n) p:nth-of-type(n)2.选择倒数第n…

[vue-cli] vue-cli中你经常的加载器有哪些?

[vue-cli] vue-cli中你经常的加载器有哪些&#xff1f; style,css,vue,postcss,url等个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣一起通关前端面试题

Python中将array类型不按科学计数法存在文件中的方法

直接上代码&#xff1a; from numpy import *import numpy as npDrug_array zeros((708,708),dtype int)f open(D:\mat_drug_drug.txt)lines f.readlines()Drug_row 0for line in lines: list line.strip(\n).split( ) Drug_array[Drug_row:] list[:] Drug_row…

[vue-cli] 你知道什么是脚手架吗?

[vue-cli] 你知道什么是脚手架吗&#xff1f; vue项目一般是使用webpack进行打包构建的&#xff0c;然而如果每一个项目都需要我们去配置loader和plugin的话&#xff0c;是很重复的劳动&#xff0c;并且vue项目需要使用到的最基本的webpack loader和webpack plugin是相同的。因…

Vue报错:Elements in iteration expect to have ‘v-bind:key‘ directives的解决办法

1.我们在使用v-for的时候&#xff0c;在v-for 后添加 v-bind:key"ite Vue 2.2.0的版本里&#xff0c;当在组件中使用v-for时&#xff0c;key是必须的。 1.我们在使用v-for的时候&#xff0c;在v-for 后添加 v-bind:key"item" <div v-for"todo in to…

vue报错:error Strings must use singlequote quotes 字符串必须使用单引号

例出现下面报错 这个问题说明必须使用单引号&#xff0c;在vue的项目开发中&#xff0c;如果我们在通过vue-cli脚手架构建项目的时候使用了Eslint严格模式&#xff0c;那么对于字符串类型的数据String必须要使用单引号&#xff0c;不能使用双引号&#xff0c;否则会报异常。所以…

Java数组概述和定义

1、数组概述和定义格式说明    为什么要有数组(容器)&#xff1a;       为了存储同种数据类型的多个值  数组概念&#xff1a;      数组是存储同一种数据类型多个元素的集合。也可以看成是一个容器。      数组既可以存储基本数据类型&#xff0c;也可…

工作327:uni-数据格式处理

allPrpos(obj) { // 用来保存所有的属性名称和值let list[]var props "";// 开始遍历for(var p in obj){ // 方法if(typeof(obj[p])"function"){ obj[p]();}else{ // p 为属性名称&#xff0c;obj[p]为对应属性的值if(p.indexOf("apic") ! -1){…

vue eslint报错Expected linebreaks to be ‘LF‘ but found ‘CRLF‘

原因&#xff1a;在使用不同的编辑器和操作系统时&#xff0c;我们使用的换行操作不一样&#xff0c;造成了这种报错 解决方法&#xff1a;在.eslintrc.js文件里面&#xff0c;在 rule&#xff1a;下面加上”linebreak-style“:[0&#xff0c;“error”&#xff0c;“window”…

mysql数据库的设计

数据库的设计有一个严谨的流程&#xff0c;根据流程制作一个完整的数据库&#xff0c;可以省去很多的时间&#xff0c;也可以最大程度上与客户的想法契合。 需求分析阶段&#xff1a;分析客户的业务和数据处理需求 概要设计阶段&#xff1a;设计数据库的E-R模型图&#xff0c;确…

[vue-cli] 说下你了解的vue-cli原理?你可以自己实现个类vue-cli吗?

[vue-cli] 说下你了解的vue-cli原理&#xff1f;你可以自己实现个类vue-cli吗&#xff1f; 原理就是通过node环境发起git请求&#xff0c;把预先设置好的模板下载下来。 给时间的话&#xff0c;应该可以实现&#xff0c;需要用到一些npm包个人简介 我是歌谣&#xff0c;欢迎和…