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

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

假设有个需求,需要将目前写好的某种控制算法库共享给别人用,他们用的是其他编程软件,如果重新移植一遍就需要花费更多的时间和精力。如果用户那边是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 :

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

登录后方可回帖

登 录
信息栏
公告:
私人站, 专注分享, 可在分享中适当提问, 但谢绝纯提问, 否则不再提醒一律删帖, 谢谢合作!



本站域名:HtmLayout.Cn
aardio可以快速开发上位机,本站主要记录了学习过程中遇到的问题和解决办法及aardio代码分享

这里主要专注于aardio学习交流和经验分享.
纯私人站,当笔记本用的,学到哪写到哪.

Aardio 官方站:Aardio官方
Aardio最新功能:Aardio官方更新日志
本 站 主 站:Stm32cube中文网
Sciter中文在线文档Sciter在线学习文档
空间赞助:才仁机械
Loading...