对aardio生成activeX EXE功能的研究学习

By admin at 2022-05-03 • 0人收藏 • 1639人看过

假设有个需求,需要将目前写好的某种控制算法库共享给别人用,他们用的是其他编程软件,如果重新移植一遍就需要花费更多的时间和精力。如果用户那边是c#那么移植到c#就会有算法被还原代码风险,那么就要用c++把算法重新实现一遍生成dll,那么还需要下载安装vs并学c++,反正挺麻烦。


于是考虑将aardio生成的程序通过activex来提供给其他软件使用, 这里研究下.

用这个方法生成的exe注册后, 就和ocx一样的使用方式  , 不仅能提供函数方法也能提供界面控件方式.


这样就可以将aardio里封装的一些方法库通过这种方式提供给其他程序直接使用,而不需要重新移植一遍,


先测试下aardio的IDE里有相关生成activex的示例


image.png

测试步骤:

  1.   打开main工程后, 直接点击[发布] , 发布编译为exe文件.

    image.png

  2. 打开编译好的exe目录吗双击exe , 选择[注册]

    image.png

  3. 看到AardioCOM.exe文件上面那个test文件夹, 打开后, 双击test.aardio,运行

    image.png

  4. 运行test.vbs

    image.png



测试范例没问题, 那么后面慢慢测试编写模式.



13 个回复 | 最后更新于 2022-05-19
2022-05-03   #1

期待后续

2022-05-03   #2

复制出所有工程代码, 自己新建个生成activex的工程 ,  删除不需要的多余代码, 一步步简化测试.

简化后的 工程:

activeX.zip


生成activex最重要的文件就是那个SampleControl.tlb

这个文件定义了Activex接口和函数, 它是由SampleControl.odl 这个文件通过vc编译而来. 编译用到的文件正是 MKTYPLIB.aardio 这个文件. 

打开MKTYPLIB.aardio , 直接运行, 会看到编译过程.

image.png

然后就生成了同名.tlb文件



2022-05-03   #3

这里重点看下 odl文件 , 文件夹里有个简易的ODL参考手册,

import "ocidl.idl";

[
uuid(84DF165D-F254-4A88-9D32-445B69DB340F),
version(1.0)
]
library AardioTestControl {

	importlib("stdole32.tlb");

	[ uuid(9DFAA296-6DFC-4B21-BACD-B8E1CB0587C2) ]
	dispinterface IAardioTestControlSample {
	
		properties: 
		
		methods: 
			[ id(1) ]
			int Add( [in] int a, [in] int b );
			
			[ id(2) ]
			void Quit( void );
	
	};
	
	[ uuid(72E56402-47CE-47F3-B6B5-09F5DD1F6746),control ]
	coclass Sample {
		[default] dispinterface IAardioTestControlSample;
	};

};

对比观看, 可以得出一个简单的使用方法:

无标题.png

如果修改了odl文件, 就重新生成下tlb.


2022-05-03   #4

调用其他库 , 

新建个test.aardio库, 

namespace test;
add = function(a,b){
	return a+b;
}

修改Sample.aardio库, 将Add改为引用test.add()

import test;
namespace AardioTestControl;

class Sample{
    
   	ctor(activeX){
   		this.activeX = activeX;
   	}
   	
    Quit = function(){ 
        //COM控件调用方必须调用这个函数退出进程
		this.activeX.stop(); 
	}

	Add = function(a,b){
		//return a+b;
		return ..test.add(a,b);
	} 

}

image.png

结果没问题.

这就意味着调用其他库应该没问题. 

下面调用sio库试试,将sio库改为ActiveX方式.

2022-05-03   #5

新增一个testSio库

import sys.comPort;
namespace testSio;
var comPorts = ..sys.comPort.list();
getcomPortsNum = function(){
	return #comPorts;
}
getcomPortsName = function(index){
	if(#comPorts){
		return comPorts[index].portName;	
	}
	return null;
}

然后将Sample库更改为 , 这个是用来给activeX提供函数实现的.

import testSio;

namespace AardioTestControl;

class Sample{
    
   	ctor(activeX){
   		this.activeX = activeX;
   	}
   	
    Quit = function(){ 
        //COM控件调用方必须调用这个函数退出进程
		this.activeX.stop(); 
	}

	getNameNum = function(){
		return ..testSio.getcomPortsNum();
	} 
	
	getNameStr = function(index){
		return ..testSio.getcomPortsName(index);
	}
	
}


然后, 需要把 ODL文件内容修改下:

import "ocidl.idl";

[
uuid(84DF165D-F254-4A88-9D32-445B69DB340F),
version(1.0)
]
library AardioTestControl {

	importlib("stdole32.tlb");

	[ uuid(9DFAA296-6DFC-4B21-BACD-B8E1CB0587C2) ]
	dispinterface IAardioTestControlSample {
	
		properties: 
		
		methods: 
			[ id(1) ]
			int getNameNum(  );
			[ id(3) ]
			BSTR getNameStr( [in] int index );
			[ id(2) ]
			void Quit( void );
	
	};
	
	[ uuid(72E56402-47CE-47F3-B6B5-09F5DD1F6746),control ]
	coclass Sample {
		[default] dispinterface IAardioTestControlSample;
	};

};

运行 MKTYPLIB.aardio 编译ODL文件为TLB二进制文件.

发布exe , 注册exe , 编写测试代码:

import console;
import com;

try{
	obj = com.CreateObject("AardioTestControl.Sample")
}

var num = obj.getNameNum() ;
for(i=1;num;1){
	console.log( obj.getNameStr(i) );
}

obj.Quit();
 
console.pause();

执行:

image.png

2022-05-03   #6

同楼上, 

testSio.aarido添加sio代码如下:

import sio;
import sys.comPort;
namespace testSio;
var sioPort;
var comPorts = ..sys.comPort.list();
getcomPortsNum = function(){
	return #comPorts;
}
getcomPortsName = function(index){
	if(#comPorts){
		return comPorts[index].portName;	
	}
	return null;
}
open = function(name){
	if(sioPort){
		sioPort.close();
	}
	
	var err;
	sioPort,err = ..sio.port(name);
	if(!sioPort){
		return false;
	}
	return true;
}
close = function(){
	if(sioPort){
		sioPort.close();
	}
}
writeStr = function(str){
	if(sioPort){
		if( !sioPort.write( str ) ){
			return false;
		}	
	}else {
		return false;
	}
	return true;
}


Sample.aardio 库 添加sio函数进去

import testSio;
namespace AardioTestControl;

class Sample{
    
   	ctor(activeX){
   		this.activeX = activeX;
   	}
   	
    Quit = function(){ 
        //COM控件调用方必须调用这个函数退出进程
		this.activeX.stop(); 
	}

	getNameNum = function(){
		return ..testSio.getcomPortsNum();
	} 
	
	getNameStr = function(index){
		return ..testSio.getcomPortsName(index);
	}
	
	open = function(name){
		return ..testSio.open(name);
	}
	
	close = function(){
		..testSio.close();
	}
	
	writeStr = function(str){
		return ..testSio.writeStr(str);
	}
}

编辑ODL文件:

[ id(1) ]
int getNameNum(  );
[ id(3) ]
BSTR getNameStr( [in] int index );
[ id(4) ]
int open( [in] BSTR name );
[ id(5) ]
void close(  );
[ id(6) ]
bool writeStr( [in] BSTR name );
[ id(2) ]
void Quit( void );

测试代码:

import console;
import com;

try{
	obj = com.CreateObject("AardioTestControl.Sample")
}

var num = obj.getNameNum() ;
for(i=1;num;1){
	console.log( obj.getNameStr(i) );
}

var ret = obj.open(obj.getNameStr(1));
console.log(ret)
if(ret){
	obj.writeStr("abcd1234");
	obj.close();
}

obj.Quit();
 
console.pause();

image.png

测试成功.


修改test.vbs代码:

Dim sample,num
Set sample = CreateObject("AardioTestControl.Sample") 
sample.open(sample.getNameStr(1))
sample.writeStr("vbs-abcd1234")
sample.close()

sample.Quit()
msgbox "ok"

image.png

2022-05-03   #7

2022-05-04   #8

测试下, 如果acitveX的函数里执行耗时操作, 直接调用会不会卡界面?

答案是:

writeStr = function(str){
	sleep(3000);
	return ..testSio.writeStr(str);
}

将发送增加个延时, 模拟耗时 , 换成win.delay(3000); 也一样

测试代码:

winform.button.oncommand = function(id,event){
	var ret = obj.open("COM1");
	console.log(ret)
	if(ret){
		console.log( obj.writeStr("abcd1234") );
		console.log("send ok")
	}
}

会发现耗时执行的时候卡界面.

所以, ActiveX EXE和ocx一样, 耗时操作需要在线程里执行避免卡界面.

2022-05-04   #9

测试 ActiveX 界面功能:

aardio的范例里已经有了这个form基本功能代码定义, 只是缺少使用示例, 在这里我们只需要就像调用ocx一样winform.createEmbed() 加载即可.

我这里随意增加一些其他按键, 然后新建一个demo界面, 添加引用代码:

这里演示下 调用事件, 定义事件的代码参看范例 SampleForm.aardio

import win.ui;
/*DSG{{*/
var winform = win.form(text="aardio form";right=759;bottom=469;bgcolor=15780518)
winform.add(
custom={cls="custom";text="自定义控件";left=114;top=76;right=618;bottom=355;bgcolor=12639424;z=1}
)
/*}}*/

import console
console.open()

var obj = winform.custom.createEmbedEx("AardioTestControl.Sample",,{
    onHello = function(str){
        obj._object.onHello(str);
             
    };
});
obj.onHello = function(str){
    console.log(str)
}

winform.show();
win.loopMessage();
return winform;

screenshots.gif

2022-05-04   #10

实例: 将ScottPlot波形图生成ActiveX进行调用.

screenshots.gif

import win.ui;

namespace AardioTestControl;
class SampleForm{
	ctor(parent,tParam){
	/*DSG{{*/
	this = ..win.form(text="test.control";right=823;bottom=525;bgcolor=12632256;border="none";exmode="none";mode="child";parent=parent;tParam=tParam)
	this.add(
	button={cls="button";text="aardio Button";left=19;top=473;right=183;bottom=521;z=2};
	custom={cls="custom";text="自定义控件";left=16;top=12;right=814;bottom=464;bgcolor=12639424;db=1;dl=1;dr=1;dt=1;z=1};
	edit={cls="edit";text="Edit";left=209;top=477;right=438;bottom=516;edge=1;z=3}
	)
	/*}}*/
	
	this.button.oncommand = function(id,event){
		this.externalEvent.onHello("来自com点击事件 hello");
	}

    import ScottPlot;
	import dotNet;
	var Chart = ..ScottPlot.FormsPlot();
	//绑定界面
	..dotNet.setParent(Chart,this.custom);
	
 	// plot one set of data using the primary Y axis
	var sigSmall = Chart.Plot.AddSignal(..ScottPlot.DataGen.Sin(51, 1));
	sigSmall.YAxisIndex = 0;
	Chart.Plot.YAxis.Label("Primary Axis");
	Chart.Plot.YAxis.Color(sigSmall.Color);
 	
	// plot another set of data using an additional axis
	var sigBig = Chart.Plot.AddSignal(..ScottPlot.DataGen.Cos(51,1,0,100));
	var yAxis3 = Chart.Plot.AddAxis(0/*Left*/, 2);
	sigBig.YAxisIndex = 2;
	yAxis3.Label("Additional Axis");
	yAxis3.Color(sigBig.Color);
	
	var Crosshair = Chart.Plot.AddCrosshair(15.0, 0.25);
	Crosshair.VerticalLine.IsVisible = false;
	Crosshair.HorizontalLine.IsVisible = false;
	
	Chart.Refresh(true);
	
	Chart.MouseEnter = function(e,r){
    	Crosshair.VerticalLine.IsVisible = true;
    	Crosshair.HorizontalLine.IsVisible = true
    	Chart.Refresh(false,false);
	}
	Chart.MouseLeave = function(e,r){
    	Crosshair.VerticalLine.IsVisible = false;
    	Crosshair.HorizontalLine.IsVisible = false;
    	Chart.Refresh(false,false);
	}
  	
	Chart.MouseMove = function(){
    	var mouseCoordinates = Chart.GetMouseCoordinates(0,0);
    	Crosshair.X = mouseCoordinates.Item1;
    	Crosshair.Y = mouseCoordinates.Item2;
    	Chart.Refresh(false,true);
	}

	this.show()
    };
}

if( !owner ) ..AardioTestControl.SampleForm().doModal();
/**intellisense()
AardioTestControl.SampleForm() = 窗口类\n!winform.
end intellisense**/

以上是将scottPlot图表那个里面的代码直接复制到了窗体定义那里.

工程代码:

777777777.zip

测试的时候, 先取dist目录,双击注册AardioCOM.exe , 然后, 到test目录里运行demoform.aardio, 应该就可以看到效果了.

2022-05-04   #11

在vs创建c#工程, 添加引用, 是可以使用add(a,b)这些方法的 , 

image.png

但是怎么使用这个调出界面那个, 还需要研究研究, 有知道方法的吗?

2022-05-18   #12

生成的EXE如何支持com.GetObject("")?就像office一样,调用已经运行的实例,不用重复初始化进程,能节省一些资源吧

2022-05-19   #13

回复#12 @money :

没咋用过这个功能,不知道,一起研究吧

登录后方可回帖

登 录
信息栏
 私人小站

本站域名

ChengXu.XYZ

投诉联系:  popdes@126.com



快速上位机开发学习,本站主要记录了学习过程中遇到的问题和解决办法及上位机代码分享

这里主要专注于学习交流和经验分享.
纯私人站,当笔记本用的,学到哪写到哪.
如果侵权,联系 Popdes@126.com

友情链接
Aardio官方
Aardio资源网


才仁机械


网站地图SiteMap

Loading...