上位机学习笔记:Hid上位机软件的实现

利用了aardio这个软件,

话说这个软件应该属于小众软件了.

其实本人也没接触过多长时间,但是我还是推荐给目前只会下位机编程,上位机还从未自己实现过的人试试.

这款软件本身就只有5M,而且绿色不用安装,我一般都是放U盘,直接走哪用哪.

它生成的软件都是绿色的,就是经常看到的那种只有一个exe的软件.

好了,其他不多说,直接先上程序,之后再记录一些自己编辑过程中遇到的问题和解决的办法!

首先,我自己定义了一个用户hid库文件,名字Usbhidapi.aardio

//Usbhidapi用户库
namespace Usbhidapi;

var dll = ..raw.loadDll($"\res\hidapi.dll", , "cdecl");
//初始化函数,0成功,-1失败
Hidapi_init= dll.api("hid_init","int(void)");
//释放端口函数,0成功,-1失败
Hidapi_exit= dll.api("hid_exit","int(void)");
//枚举端口
Hidapi_enumerate= dll.api("hid_enumerate","struct(WORD vendor_id, WORD product_id)","cdecl");
//释放枚举端口
Hidapi_free_enumeration= dll.api("hid_free_enumeration","void(struct devs)","cdecl");
//vid和pid方式打开端口
Hidapi_open= dll.api("hid_open","pointer(WORD vendor_id, WORD product_id, string serial_number)","cdecl");
//路径名方式打开
Hidapi_open_path= dll.api("hid_open_path","pointer(STRING path)","cdecl");
//发送数据函数,返回发送成功的长度 或者 发送失败-1
Hidapi_write= dll.api("hid_write","int(POINTER device, pointer data, INT length)","cdecl");
//读取(超时方式)
Hidapi_read_timeout= dll.api("hid_read_timeout","int(POINTER device, pointer data, INT length, INT milliseconds)","cdecl");
//读取(普通方式)
Hidapi_read= dll.api("hid_read","int(POINTER device, pointer data, INT length)","cdecl");
//设置阻塞模式 0 使用,1 不使用
Hidapi_set_nonblocking= dll.api("hid_set_nonblocking","int(POINTER device, int nonblock)","cdecl");
//发送功能报告
Hidapi_send_feature_report= dll.api("hid_send_feature_report","int(POINTER device, pointer data, int length)","cdecl");
//获取功能报告
Hidapi_get_feature_report= dll.api("hid_get_feature_report","int(POINTER device, pointer data, int length)","cdecl");
//关闭端口函数
Hidapi_close = dll.api("hid_close","void(POINTER device)","cdecl");
//获取用户码
Hidapi_get_manufacturer_string= dll.api("hid_get_manufacturer_string","int(POINTER device, ustring& data, INT maxlen)","cdecl");
//获取产品码
Hidapi_get_product_string= dll.api("hid_get_product_string","int(POINTER device, ustring& data, int maxlen)","cdecl");
//获取序列号
Hidapi_get_serial_number_string= dll.api("hid_get_serial_number_string","int(POINTER device, ustring& data, int maxlen)","cdecl")
//获取字符(按照给定的帧首[string_index]获取 1=manufacturer_strin, 2=product_string, 3=serial_number_string),同上面的功能一样
Hidapi_get_indexed_string= dll.api("hid_get_indexed_string","int(POINTER device, int string_index, ustring& data, int maxlen)","cdecl");
//获取错误信息
Hidapi_error= dll.api("hid_error","ustring(POINTER device)","cdecl");

然后就是界面实现和使用逻辑.

名称:main.aardio

import win.ui;
import Usbhidapi;
import console;
/*DSG{{*/
mainForm = win.form(text="aardio form";right=691;bottom=408;border="dialog frame")
mainForm.add(
Rxdata={cls="listbox";left=429;top=57;right=650;bottom=128;edge=1;items={};z=20};
Txdata={cls="edit";text="123456abcd";left=136;top=101;right=304;bottom=134;align="center";edge=1;z=19};
button={cls="button";text="初始化";left=40;top=146;right=140;bottom=181;z=1};
button10={cls="button";text="设置非阻塞";left=40;top=251;right=140;bottom=286;z=10};
button11={cls="button";text="发送功能报告";left=381;top=146;right=481;bottom=181;z=11};
button12={cls="button";text="获取功能报告";left=381;top=199;right=481;bottom=234;z=12};
button13={cls="button";text="关闭";left=553;top=302;right=653;bottom=337;z=13};
button14={cls="button";text="获取用户码";left=219;top=146;right=319;bottom=181;z=14};
button15={cls="button";text="获取产品码";left=219;top=198;right=319;bottom=234;z=15};
button16={cls="button";text="获取序列号";left=219;top=251;right=319;bottom=286;z=16};
button17={cls="button";text="获取首字符";left=219;top=304;right=319;bottom=338;z=17};
button18={cls="button";text="获取错误信息";left=553;top=248;right=653;bottom=283;z=18};
button2={cls="button";text="退出";left=553;top=356;right=653;bottom=392;z=2};
button3={cls="button";text="枚举";left=381;top=304;right=481;bottom=339;z=3};
button4={cls="button";text="释放枚举";left=381;top=357;right=481;bottom=391;z=4};
button5={cls="button";text="普通方式打开";left=40;top=198;right=140;bottom=234;z=5};
button6={cls="button";text="路径名方式打开";left=381;top=252;right=481;bottom=286;z=6};
button7={cls="button";text="发送";left=40;top=304;right=140;bottom=340;z=7};
button8={cls="button";text="读取(超时)";left=219;top=356;right=319;bottom=391;z=8};
button9={cls="button";text="读取";left=40;top=357;right=140;bottom=391;z=9};
static={cls="static";text="发送数据:";left=63;top=109;right=121;bottom=132;transparent=1;z=21};
static2={cls="static";text="接收数据:";left=356;top=106;right=413;bottom=125;transparent=1;z=22};
static3={cls="static";text="UsbHid库调用示例";left=241;top=12;right=436;bottom=50;align="center";font=LOGFONT(h=-24);transparent=1;z=23}
)
/*}}*/

hid_device_info = class {
string path ;
WORD vendor_id ;
WORD product_id ;
ustring serial_number;
WORD release_number ;
ustring manufacturer_string ;
ustring product_string ;
WORD usage_page ;
WORD usage;
int interface_number;
pointer next ;
};

//转换成AISCII
Aiscii=function(data,len){
var str="";           
for(i=1;len;1){
str ++=string.pack(data[i]);
}
return str; 
}

var Hiddevice;

mainForm.button3.oncommand = function(id,event){
//mainForm.msgbox( mainForm.button3.text );
var devs = hid_device_info();
var cur_dev;

var devlist = Usbhidapi.Hidapi_enumerate(0,0);
cur_dev = raw.convert(devlist,hid_device_info());
while(cur_dev){
console.dump(cur_dev);
cur_dev = cur_dev.next;
if(cur_dev){
cur_dev = raw.convert(cur_dev,hid_device_info());
}
else {
break;
}

}


}

mainForm.button6.oncommand = function(id,event){
//mainForm.msgbox( mainForm.button6.text );
//mainForm.msgbox( "这个功能下面的写的不对,就没测了" );


/*
var str = "\\?\hid#vid_5555&pid_5555#6&8282ff9&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}";
Hiddevice = Usbhidapi.Hidapi_get_feature_report(str);
if(Hiddevice){
console.log("路径方式打开成功!")
}else {
console.log("路径方式打开失败!")
}
*/


}

mainForm.button12.oncommand = function(id,event){
mainForm.msgbox( "硬件电路里面没有使用到控制端点,所以这个功能没有测试" );
//硬件电路里面没有使用到控制端点,所以这个功能没有测试
/**
var buf = raw.malloc(1000, 0);
var len = 100;
var Rxlength = Usbhidapi.Hidapi_get_feature_report(Hiddevice, buf, len);
if(Rxlength == -1){
console.log("读取失败!")
}else {
console.log("读取成功!!读取长度为:",Rxlength,'\n读取到:' /*,raw.tostring(databuf)*/);
//console.log(raw.tostring(databuf, 1, Rxlength));
if(Rxlength == 0){
return; //没数据退出
}
var str = "";
str = Aiscii(buf,Rxlength);

mainForm.Rxdata.add(str);
console.log(str);
}
**/

}

mainForm.button11.oncommand = function(id,event){
mainForm.msgbox( "硬件电路里面没有使用到控制端点,所以这个功能没有测试" );
//硬件电路里面没有使用到控制端点,所以这个功能没有测试
/*
var Txlength = Usbhidapi.Hidapi_send_feature_report(Hiddevice,'\0'+mainForm.Txdata.text,#mainForm.Txdata.text+1);
if(Txlength == -1){
console.log("发送失败!")
}else {
console.log("发送成功!!发送长度为:",Txlength)
}

*/
}

mainForm.button8.oncommand = function(id,event){
//mainForm.msgbox( mainForm.button8.text );
var buf = raw.malloc(1000, 0);
var len,ms = 100,1000;
var Rxlength = Usbhidapi.Hidapi_read_timeout(Hiddevice, buf, len, ms);
if(Rxlength == -1){
console.log("读取失败!")
}else {
console.log("读取成功!!读取长度为:",Rxlength,'\n读取到:' /*,raw.tostring(databuf)*/);
//console.log(raw.tostring(databuf, 1, Rxlength));
if(Rxlength == 0){
return; //没数据退出
}
var str = "";
str = Aiscii(buf,Rxlength);

mainForm.Rxdata.add(str);
console.log(str);
}

}

mainForm.button17.oncommand = function(id,event){
//mainForm.msgbox( mainForm.button17.text );
var buf = raw.malloc(1000);
//var buf= "";
var Maxlen = 255;
var ret,buf2= Usbhidapi.Hidapi_get_indexed_string(Hiddevice,3,buf,Maxlen);
if(ret == -1){
console.log("获取首字符失败!")
}else {
console.log("获取首字符成功!")
console.log("首字符为:",buf2);

}

}

mainForm.button16.oncommand = function(id,event){
//mainForm.msgbox( mainForm.button16.text );

var buf = raw.malloc(1000);
//var buf= "";
var Maxlen = 255;
var ret,buf2= Usbhidapi.Hidapi_get_serial_number_string(Hiddevice,buf,Maxlen);
if(ret == -1){
console.log("获取序列号失败!")
}else {
console.log("获取序列号成功!")
console.log("序列号为:",buf2);

}
}

mainForm.button15.oncommand = function(id,event){
//mainForm.msgbox( mainForm.button15.text );
var buf = raw.malloc(1000);
//var buf= "";
var Maxlen = 255;
var ret,buf2= Usbhidapi.Hidapi_get_product_string(Hiddevice,buf,Maxlen);
if(ret == -1){
console.log("获取产品码失败!")
}else {
console.log("获取产品码成功!")
console.log("产品码为:",buf2);

}

}

mainForm.button14.oncommand = function(id,event){
//mainForm.msgbox( mainForm.button14.text );
var buf = raw.malloc(1000);
//var buf= "";
var Maxlen = 255;
var ret,buf2= Usbhidapi.Hidapi_get_manufacturer_string(Hiddevice,buf,Maxlen);
if(ret == -1){
console.log("获取用户码失败!")
}else {
console.log("获取用户码成功!")
console.log("用户码为:",buf2);

}

}

mainForm.button13.oncommand = function(id,event){
//mainForm.msgbox( mainForm.button13.text );
Usbhidapi.Hidapi_close(Hiddevice);
console.log("已经关闭");

}

//var buf = raw.malloc(100, 0);
mainForm.button9.oncommand = function(id,event){
//mainForm.msgbox( mainForm.button9.text );
var buf = raw.malloc(1000, 0);
var len = 100;
var Rxlength = Usbhidapi.Hidapi_read(Hiddevice, buf, len);
if(Rxlength == -1){
console.log("读取失败!")
}else {
console.log("读取成功!!读取长度为:",Rxlength,'\n读取到:' /*,raw.tostring(databuf)*/);
//console.log(raw.tostring(databuf, 1, Rxlength));
if(Rxlength == 0){
return; //没数据退出
}
var str = "";
str = Aiscii(buf,Rxlength);

mainForm.Rxdata.add(str);
console.log(str);
}

}


mainForm.button7.oncommand = function(id,event){
//mainForm.msgbox( mainForm.button7.text );
var Txlength = Usbhidapi.Hidapi_write(Hiddevice,'\0'+mainForm.Txdata.text,#mainForm.Txdata.text+1);
if(Txlength == -1){
console.log("发送失败!")
}else {
console.log("发送成功!!发送长度为:",Txlength)
}

}


mainForm.button10.oncommand = function(id,event){
//mainForm.msgbox( mainForm.button10.text );
var ret = Usbhidapi.Hidapi_set_nonblocking(Hiddevice, 1);
if(ret == -1){
console.log("设置非阻塞模式失败!")
}else {
console.log("设置非阻塞模式成功!")
}

}


mainForm.button5.oncommand = function(id,event){
//mainForm.msgbox( mainForm.button5.text );
Hiddevice = Usbhidapi.Hidapi_open(21845, 21845, null);
if(Hiddevice){
console.log("Vid和Pid方式打开成功!")
}else {
console.log("Vid和Pid方式打开失败!")
}
}


mainForm.button.oncommand = function(id,event){
//mainForm.msgbox( mainForm.button.text );

var ret = Usbhidapi.Hidapi_init();
if(ret == -1){
console.log("初始化失败!")
}else {
console.log("初始化成功!")
}

}
mainForm.show() 
return win.loopMessage();

下面是这个软件实现后的图片.

blob.png

功能演示:

blob.png

已邀请:

zdsurge

赞同来自:

历害,慢慢学习中。 

admin

赞同来自:

软件程序截图:

blob.png

源码和exe下载:本站网盘,名称:Usbhid_aardio上位机实现.zip



http://pan.baidu.com/s/1hsbT6Eo

admin

赞同来自:

这里写下编写过程中遇到的问题:

首先是dll库的声明中某些数据类型写错导致后续获取不到想要的数据

比如:open的C原型为

/** @brief Open a HID device using a Vendor ID (VID), Product ID
(PID) and optionally a serial number.

If @p serial_number is NULL, the first device with the
specified VID and PID is opened.

@ingroup API
@param vendor_id The Vendor ID (VID) of the device to open.
@param product_id The Product ID (PID) of the device to open.
@param serial_number The Serial Number of the device to open
               (Optionally NULL).

@returns
This function returns a pointer to a #hid_device object on
success or NULL on failure.
*/
HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number);


在这里遇到的问题就是这个hid_device* 指针,我试图把这个指针的结构体都弄出来了,因为我在他的文档里面看到了

struct hid_device_;
typedef struct hid_device_ hid_device; /**< opaque hidapi structure */

所以我理所当然的认为应该定义为一个struct类型,然后列出这个struct类型,下面就是我定义错误的代码:

Hidapi_open= dll.api("hid_open","struct(WORD vendor_id, WORD product_id, string serial_number)","cdecl");

这个错误导致后面获取hid_device这个handle一直失败,陷入了死胡同!

这里正确的理解应该是,这个函数返回一个指针,这个指针里存储了一个handle句柄.

由于后面是直接利用了这个handle句柄,无需我们自己解包,所以,这里就以指针类型输出即可.

正确的定义应该是pointer:

Hidapi_open= dll.api("hid_open","pointer(WORD vendor_id, WORD product_id, string serial_number)","cdecl");

这里定义好之后,那么就是写入,就像我上面说的,写入是利用了这个handle句柄,无需我们参与,所以写入就好声明了.

写入的函数原型是:

		/** @brief Write an Output report to a HID device.

The first byte of @p data[] must contain the Report ID. For
devices which only support a single report, this must be set
to 0x0. The remaining bytes contain the report data. Since
the Report ID is mandatory, calls to hid_write() will always
contain one more byte than the report contains. For example,
if a hid report is 16 bytes long, 17 bytes must be passed to
hid_write(), the Report ID (or 0x0, for devices with a
single report), followed by the report data (16 bytes). In
this example, the length passed in would be 17.

hid_write() will send the data on the first OUT endpoint, if
one exists. If it does not, it will send the data through
the Control Endpoint (Endpoint 0).

@ingroup API
@param device A device handle returned from hid_open().
@param data The data to send, including the report number as
the first byte.
@param length The length in bytes of the data to send.

@returns
This function returns the actual number of bytes written and
-1 on error.
*/
int  HID_API_EXPORT HID_API_CALL hid_write(hid_device *device, const unsigned char *data, size_t length);

这里我们可以利用aardio的工具直接生成:

注意复制进去之后要删除掉一些识别不了的命名,比如那个hid_api_call和hid_api_export

变为

int  hid_write(hid_device *device, const unsigned char *data, size_t length);

然后将这个利用工具转换为aardio的声明

blob.png

生成后为

hid_write= dll.api("hid_write","int(hid_device &device, const INT byte &data, size_t length)");

这里看到有好几个声明中的数据类型是不常见的,所以我们有需要把他们改成咱们能认识的类型

这里的hid_device&就要改为POINTER device,大写的意思就是不接受NULL空指针,后面的data是咱们要发送的数组,即数据组合,那么可以改为pointer指针类型,一般情况下数组都用指针类型声明.在看后面的size_t这个类型明显是识别不了的,这个length是要写入的长度,所以我们改为INT,大写的意思是无符号32位整型数据.长度不可能是负的,所以是INT,如果是返回值的话,因为可能会返回-1这个错误提示,所以定义为int小写,有符合数据.



admin

赞同来自:

再者就是读取各种string时候遇到的问题:

比如原型为:

		/** @brief Get The Manufacturer String from a HID device.

@ingroup API
@param device A device handle returned from hid_open().
@param string A wide string buffer to put the data into.
@param maxlen The length of the buffer in multiples of wchar_t.

@returns
This function returns 0 on success and -1 on error.
*/
int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *device, wchar_t *string, size_t maxlen);

利用工具直接生成的aardio调用为

hid_get_manufacturer_string= dll.api("hid_get_manufacturer_string","int(hid_device &device, wchar_t &string, size_t  maxlen)");

然后我按照自己的理解,这个就是返回一个字符串嘛,我就定义成了下面的错误方式:

hid_get_manufacturer_string= dll.api("hid_get_manufacturer_string","int(pointer device, string &string, int maxlen)");

后续这样调用的时候发生了一个问题就是,返回的数据string一直都只是一个字节,就是只显示了一个blob.png

在这里一直纳闷了好久,最后无奈,只好从头按照aardio的帮助文档一个类型一个类型的对照改了下,我发现文档的api数据类型中这样写道

blob.png

这里明明已经写的很明白了,wchar_t*就要转换为ustring这种类型,所以我就改为

Hidapi_get_manufacturer_string= dll.api("hid_get_manufacturer_string","int(POINTER device, ustring& data, INT maxlen)","cdecl");

这里再啰嗦下,ustring&的&的意思也在帮助手册中:

blob.png

意思是返回.

之后调试就返回了正确的结果了.

blob.png

这里我只想说明: 官方提供的帮助文档真的很重要!要多看,不要自己主观臆断!!!

admin

赞同来自:

继续:

话说我前面其实下载过很多个hid相关的dll,都调用过,基本上没有成功过,一般都是卡到了枚举这里.所以我其他功能都实现了之后才开始编写这个Hidapi_enumerate枚举端口指令.

函数原型:

		/** @brief Enumerate the HID Devices.

This function returns a linked list of all the HID devices
attached to the system which match vendor_id and product_id.
If @p vendor_id is set to 0 then any vendor matches.
If @p product_id is set to 0 then any product matches.
If @p vendor_id and @p product_id are both set to 0, then
all HID devices will be returned.

@ingroup API
@param vendor_id The Vendor ID (VID) of the types of device
to open.
@param product_id The Product ID (PID) of the types of
device to open.

    @returns
     This function returns a pointer to a linked list of type
     struct #hid_device, containing information about the HID devices
     attached to the system, or NULL in the case of failure. Free
     this linked list by calling hid_free_enumeration().
*/
struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id);

这里将dll调用声明没什么可说的,返回的是struct很明显,所以我写作:

//枚举端口
Hidapi_enumerate= dll.api("hid_enumerate","struct(WORD vendor_id, WORD product_id)","cdecl");

好了问题来了,我返回了一个struct的hid_device_info结构体,这个结构体是怎么定义的?

返回的这个结构体里面肯定是枚举出来的一系列数据,数据应该怎么取出来?

这个结构体的原型,文档也提供了

		/** hidapi info structure */
struct hid_device_info {
/** Platform-specific device path */
char *path;
/** Device Vendor ID */
unsigned short vendor_id;
/** Device Product ID */
unsigned short product_id;
/** Serial Number */
wchar_t *serial_number;
/** Device Release Number in binary-coded decimal,
    also known as Device Version Number */
unsigned short release_number;
/** Manufacturer String */
wchar_t *manufacturer_string;
/** Product string */
wchar_t *product_string;
/** Usage Page for this Device/Interface
    (Windows/Mac only). */
unsigned short usage_page;
/** Usage for this Device/Interface
    (Windows/Mac only).*/
unsigned short usage;
/** The USB interface which this logical device
    represents. Valid on both Linux implementations
    in all cases, and valid on the Windows implementation
    only if the device contains more than one interface. */
int interface_number;

/** Pointer to the next device */
struct hid_device_info *next;
};

于是,我继续利用aardio提供的工具进行转换:结果如下

struct hid_device_info {

pointer path;

WORD vendor_id;

WORD product_id;

pointer serial_number;

WORD release_number;

pointer manufacturer_string;

pointer product_string;

WORD usage_page;

WORD usage;

int interface_number;

struct pointer next;
};

咱们看看他转换的,path原来是char*,变成了pointer,这里我也不讨论它对不对了,我直接和帮助文档进行了比对

blob.png

于是我果断把它改为了string path;

继续看下面的wchar_t *serial_number; 上面我们已经说过,aardio中wchar_t要变成什么?

对,就是ustring ,所以我也改变它为:ustring serial_number;

依次类推,其他类似的都改掉.

最后看

			/** Pointer to the next device */
struct hid_device_info *next;

这个是指向下一个设备的指针,他的原型是它自己的struct,这个应该怎么弄啊??

工具把它转换为了一个

struct pointer next;

但是明显是不对的,有两个类型声明.那么应该删掉哪个?

删掉struct,这里我已经说了这个是指向下个设备的指针,指针,指针....

果断改为pointer next;

好了,改后变成了

hid_device_info = class {
string path ;
WORD vendor_id ;
WORD product_id ;
ustring serial_number;
WORD release_number ;
ustring manufacturer_string ;
ustring product_string ;
WORD usage_page ;
WORD usage;
int interface_number;
pointer next ;
};

这个可是完全按照aardio帮助文档来写的!!


admin

赞同来自:

之后就是这个结构体怎么使用了.

这里也卡住了好久,因为对aar确实不熟悉.

纠结的过程就不写了.直接写怎么弄出来的.

先打开这个dll官方提供的一个示例代码hidtest.cpp 这个貌似用c++写的,我们可以参考改改

blob.png

看到了三个重点标注.

一个获取设备列表,第二个把列表进行struct转换,然后判断结构体中有没数据,有数据就输出里面的数据,while最后一句把指针更改为next的指向,即指向下一个设备,然后再while进行判断是不是空数据,不是空的就输出第二个设备,然后继续......

看到这,我猜想:

	var cur_dev;//定义当前设备列表
//获取hid设备列表
var devlist = Usbhidapi.Hidapi_enumerate(0,0);
//将这个列表指向的数据强制转化为hid_device_info这个结构体形式
cur_dev = raw.convert(devlist,hid_device_info());
//判断第一个设备存不存在
while(cur_dev){
        //输出当前设备所有的信息
console.dump(cur_dev);
//将next指向的下一个设备数据复制到当前设备
cur_dev = cur_dev.next;
//判断设备是否存在
if(cur_dev){
//存在,则下一个设备数据强制转化为hid_device_info这个结构体形式
cur_dev = raw.convert(cur_dev,hid_device_info());
}
else {//不存在则退出循环
break;
}

}

ok,这样操作的结果证明猜想的正确性!

同时也学会了怎么使用next这种自己调用自己的形式.

blob.png

我这里枚举出了9个设备,最后一个是我用开发板做的一个custom_hid,数据完全正确!

为了验证正确性,我也下载了一个网上的usb调试软件,得出的结果和上面的一致

blob.png

好了,这里hid上位机dll调用编写测试就基本结束了.

再次感谢aardiio群里很多大神对我的帮助

admin

赞同来自:

想要实现插入usb设备界面能提示插入了这个设备功能:

参考了aar的官方示例u盘检测:然后修改下面的

import win.ui;
/*DSG{{*/
var winform = win.form(text="自动检测插入U盘";right=740;bottom=296)
winform.add(
edit={cls="edit";text="请插入设备";left=15;top=15;right=726;bottom=263;edge=1;multiline=1;z=1}
)
/*}}*/

import win.util.deviceNotification;
var deviceNotification = win.util.deviceNotification(winform)

deviceNotification.onDeviceArrival = function(devicetype,deviceBroadcastData,ptrData){
if( devicetype == 5/*_DBT_DEVTYP_DEVICEINTERFACE*//**2/*_DBT_DEVTYP_VOLUME*/**/ ){
winform.edit.print("发现了设备",deviceBroadcastData.name);
}
}

deviceNotification.onDeviceRemoveComplete = function(devicetype,deviceBroadcastData,ptrData){
if( devicetype == 5 ){
 winform.edit.print("移除设盘" + " " + deviceBroadcastData.name )
}


winform.show() 
win.loopMessage();

blob.png

blob.png

说明:
框架调用这个函数以通知应用程序或设备驱动程序,设备或计算机的硬件配置发生了改变。
对于提供了软件控制功能,如弹出和锁定的设备,操作系统通常发送一条DBT_DEVICEREMOVEPENDING消息,以便使应用程序和设备驱动程序停止对设备的使用。
如果操作系统强行清除了一个设备,它可能不会发送DBT_DEVICEQUERYREMOVE消息。
nEvent参数可以是下列值之一:

·DBT_DEVICEARRIVAL已经加入了一个设备,现在可以使用。
·DBT_DEVICEQUERYREMOVE允许清除被请求的设备。任何应用程序都可以拒绝这个请求并取消清除操作。
·DBT_DEVICEQUERYREMOVEFAILED清除设备的请求被取消了。
·DBT_DEVICEREMOVEPENDING设备将要被清除。不能拒绝。
·DBT_DEVICEREMOVECOMPLETE设备已经被清除。
·DBT_DEVICETYPESPECIFIC与设备有关的事件。
·DBT_CONFIGCHANGED当前配置发生了变化。
·DBT_DEVNODES_CHANGED设备节点发生了变化。

注意 框架调用这个成员函数以允许你的应用程序处理一个Windows消息。传递给你的成员函数的参数反映了接收到消息时框架接收到的参数。如果你调用了这个函数的基类实现,则该实现将使用最初传递给消息的参数(而不是你提供给这个函数的参数)。

程序里为什么是5/*_DBT_DEVTYP_DEVICEINTERFACE*/ ???

blob.png

admin

赞同来自:

线程的使用,

利用线程后台读取数据的方法:

import win.ui;
import Usbhidapi;
import console;
/*DSG{{*/
mainForm = win.form(text="AAR_Hid调试";right=384;bottom=357;border="dialog frame")
mainForm.add(
button={cls="button";text="打开";left=288;top=17;right=363;bottom=41;z=5};
button2={cls="button";text="发送";left=288;top=94;right=363;bottom=118;z=10};
hid_pid={cls="edit";text="22352";left=195;top=17;right=270;bottom=41;edge=1;z=4};
hid_vid={cls="edit";text="1155";left=70;top=17;right=145;bottom=41;edge=1;z=3};
receivedata={cls="listbox";left=28;top=181;right=363;bottom=344;edge=1;hscroll=1;items={};vscroll=1;z=8};
senddata={cls="edit";text="du01";left=31;top=97;right=269;bottom=121;autovscroll=false;edge=1;z=7};
static={cls="static";text="Vid:";left=25;top=17;right=65;bottom=37;font=LOGFONT(h=-20);transparent=1;z=1};
static2={cls="static";text="Pid:";left=150;top=17;right=190;bottom=37;font=LOGFONT(h=-20);transparent=1;z=2};
static3={cls="static";text="发送数据:";left=28;top=65;right=119;bottom=89;font=LOGFONT(h=-20);transparent=1;z=6};
static4={cls="static";text="接收数据:";left=28;top=152;right=119;bottom=179;font=LOGFONT(h=-20);transparent=1;z=9}
)
/*}}*/

/*
默认仅主窗体支持跨线程调用,
winform.edit.threadCallable();开启窗口上指定控件的跨线程调用功能,
winform.threadCallable();开启窗口上所有控件的跨线程调用功能,
*/
mainForm.threadCallable();

//转换为HEX码
var Hex=function(data,len){
var str="";
for(i=1;len;1){
str = str++" "++string.right(string.format("X", data[ i ]),2);//默认转换成有符号字节,因此取最右边两位  HEX码
}
return str;                    
}
//转换成AISCII
var Aiscii=function(data,len){
var str="";           
for(i=1;len;1){
str ++=string.pack(data[i]);
}
return str; 
}

var Hiddevice;
var thrdHandle;

mainForm.wndproc = function(hwnd,message,wParam,lParam){
select( message ) { 
case 0x10/*_WM_CLOSE*/{
if(thrdHandle != null){
raw.closehandle(thrdHandle);
}
}
else{

}
}
//无返回值则继续调用默认回调函数
}


mainForm.button2.disabled = true;

mainForm.button.oncommand = function(id,event){
if(owner.text == "打开"){
var ret = Usbhidapi.Hidapi_init();
if(ret == -1){
mainForm.msgbox("初始化失败!")
//失败则退出
return;
}else {
//console.log("初始化成功!")
}

Hiddevice = Usbhidapi.Hidapi_open(tonumber(mainForm.hid_vid.text), tonumber(mainForm.hid_pid.text), null);
if(Hiddevice){
//console.log("Vid和Pid方式打开成功!")
//线程中hid读取只能在非阻塞模式使用,否则会死机
var ret = Usbhidapi.Hidapi_set_nonblocking(Hiddevice, 1);
if(ret == -1){
mainForm.msgbox("设置非阻塞模式失败!")
Usbhidapi.Hidapi_close(Hiddevice);
return;
}else {
//console.log("设置非阻塞模式成功!")
}


thrdHandle = thread.create(
     function(mainForm,Hiddevice,Hex){
     //import console;
     import Usbhidapi
   while(true){
   var buf = raw.malloc(1000, 0);
var len = 100;
var Rxlength = Usbhidapi.Hidapi_read(Hiddevice, buf, len);
if(Rxlength == -1){
//console.log("读取失败!")
}else {
if(Rxlength == 0){
continue ; //没数据退出
}
var str = "";
//str = Aiscii(buf,Rxlength);
str = Hex(buf,Rxlength);
mainForm.receivedata.add(str);
mainForm.receivedata.scrollToBottom();
//console.log(str);
}  

    } //end while
 
     }, mainForm,Hiddevice,Hex

);

mainForm.button2.disabled = false;
owner.text = "关闭";
}else {
mainForm.msgbox("Vid和Pid方式打开失败!")
return;
}


}elseif(owner.text == "关闭"){
Usbhidapi.Hidapi_close(Hiddevice);
owner.text = "打开";
mainForm.button2.disabled = true;
//console.log("已经关闭");
//thread.suspend(thrdHandle);
}

}

mainForm.button2.oncommand = function(id,event){
//发送函数
var Txlength = Usbhidapi.Hidapi_write(Hiddevice,'\0'+mainForm.senddata.text,#mainForm.senddata.text+1);
if(Txlength == -1){
mainForm.msgbox("发送失败!")
}else {
//console.log("发送成功!!发送长度为:",#mainForm.senddata.text)
}

}

//listbox的纵向滚动条显示最下方,消息方式
mainForm.receivedata.scrollToBottom = function () {

    return ::SendMessageInt(owner.hwnd, 0x115/*_WM_VSCROLL*/, 0x7/*_SB_BOTTOM*/, 0);

}
//设置listbox横向滚动条
//::SendMessageInt( mainForm.receivedata.hwnd,0x194/*_LB_SETHORIZONTALEXTENT*/,500,0)

mainForm.enableDpiScaling();
mainForm.show();

return win.loopMessage();

GIF.gif

admin

赞同来自:

多线程的使用,暂停,继续

import win.ui;
import console;
/*DSG{{*/
var winform = win.form(text="aardio form";right=518;bottom=412)
winform.add(
button={cls="button";text="button";left=178;top=327;right=259;bottom=363;z=1};
button2={cls="button";text="button2";left=396;top=329;right=502;bottom=367;z=2}
)
/*}}*/


console.open()
var flag = 0;

thread.create_suspended=true
var vthandle = thread.create(
function( ... ){
import console; 
for(i=1;10000;1){
console.log(i)
sleep(1000)
}


},

)
winform.button2.oncommand = function(id,event){
//winform.msgbox( winform.button2.text );

thread.resume(vthandle)
}


winform.button.oncommand = function(id,event){
//winform.msgbox( winform.button.text );
thread.suspend(vthandle)

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


admin

赞同来自:

hid软件新增:

Ascii码和Hex码相互转换功能,增加窗口固顶功能,添加 打开设备时候显示 设备用户设备名提示功能.

blob.png

完整代码如下:

import win.ui;
import Usbhidapi;
import console;
/*DSG{{*/
mainForm = win.form(text="Hid调试工具(By Stm32cube中文网)";right=384;bottom=366;border="dialog frame";max=false)
mainForm.add(
button={cls="button";text="打开";left=288;top=26;right=363;bottom=50;bgcolor=32768;z=5};
button2={cls="button";text="发送";left=288;top=103;right=363;bottom=127;z=10};
guding={cls="checkbox";text="固顶";left=28;top=336;right=76;bottom=356;z=14};
hid_pid={cls="edit";text="22352";left=195;top=26;right=270;bottom=50;edge=1;z=4};
hid_vid={cls="edit";text="1155";left=70;top=26;right=145;bottom=50;edge=1;z=3};
receivedata={cls="listbox";left=28;top=167;right=363;bottom=330;edge=1;hscroll=1;items={};vscroll=1;z=8};
sel_ascii={cls="radiobutton";text="ASCII";left=184;top=78;right=244;bottom=99;checked=1;font=LOGFONT(h=-16);z=12};
sel_hex={cls="radiobutton";text="HEX";left=120;top=78;right=180;bottom=99;font=LOGFONT(h=-16);z=11};
senddata={cls="edit";text="du01";left=31;top=106;right=269;bottom=130;autovscroll=false;edge=1;z=7};
static={cls="static";text="Vid:";left=25;top=26;right=65;bottom=46;font=LOGFONT(h=-20);transparent=1;z=1};
static2={cls="static";text="Pid:";left=150;top=26;right=190;bottom=46;font=LOGFONT(h=-20);transparent=1;z=2};
static3={cls="static";text="发送数据:";left=28;top=74;right=119;bottom=98;font=LOGFONT(h=-20);transparent=1;z=6};
static4={cls="static";text="接收数据:";left=28;top=138;right=119;bottom=165;font=LOGFONT(h=-20);transparent=1;z=9};
user_name={cls="static";left=82;top=339;right=363;bottom=359;align="right";color=32768;transparent=1;z=13}
)
/*}}*/

mainForm.guding.oncommand = function(id,event){
//mainForm.msgbox( mainForm.guding.text );
if(mainForm.guding.checked){
win.setTopmost(mainForm.hwnd)
}else {
win.setTopmost(mainForm.hwnd,false)
}



}
//转换为HEX码
var Hex=function(data,len){
var str="";
for(i=1;len;1){
str = str++" "++string.right(string.format("X", data[ i ]),2);//默认转换成有符号字节,因此取最右边两位  HEX码
}
return string.trim(str);                    
}
 //hex转ascii
 var Ascii=function(data){
  var data = string.replace(data," ","");
var str="";           
for(i=1;#data;2){
str =str ++ string.pack( eval("0x"++data[[i]]++data[[i+1]] ));
}
return str; 
}

//初始化单选对象
var sel_Obj = mainForm.sel_ascii.checked ? "ascii" : "hex";

//ascii单选被点击
mainForm.sel_ascii.oncommand = function(id,event){
//mainForm.msgbox( mainForm.sel_ascii.text );
if(sel_Obj != "ascii"){
sel_Obj = "ascii";
var showdata = Ascii(mainForm.senddata.text);
mainForm.senddata.text = showdata;
}

}


//hex单选被点击
mainForm.sel_hex.oncommand = function(id,event){
//mainForm.msgbox( mainForm.sel_hex.text );
if(sel_Obj != "hex"){
sel_Obj = "hex";
var editdata = string.replace(mainForm.senddata.text," ","");
var showdata = Hex(editdata,#editdata);
mainForm.senddata.text = showdata;
}

}


/*
默认仅主窗体支持跨线程调用,
winform.edit.threadCallable();开启窗口上指定控件的跨线程调用功能,
winform.threadCallable();开启窗口上所有控件的跨线程调用功能,
*/
mainForm.threadCallable();


var Hiddevice;
var thrdHandle;

mainForm.wndproc = function(hwnd,message,wParam,lParam){
select( message ) { 
case 0x10/*_WM_CLOSE*/{
if(thrdHandle != null){
raw.closehandle(thrdHandle);
}
}
else{

}
}
//无返回值则继续调用默认回调函数
}


mainForm.button2.disabled = true;

mainForm.button.oncommand = function(id,event){
if(owner.text == "打开"){
var ret = Usbhidapi.Hidapi_init();
if(ret == -1){
mainForm.msgbox("初始化失败!")
//失败则退出
return;
}else {
//console.log("初始化成功!")
}

Hiddevice = Usbhidapi.Hidapi_open(tonumber(mainForm.hid_vid.text), tonumber(mainForm.hid_pid.text), null);
if(Hiddevice){
//console.log("Vid和Pid方式打开成功!")
//线程中hid读取只能在非阻塞模式使用,否则会死机
var ret = Usbhidapi.Hidapi_set_nonblocking(Hiddevice, 1);
if(ret == -1){
mainForm.msgbox("设置非阻塞模式失败!")
Usbhidapi.Hidapi_close(Hiddevice);
return;
}else {
//console.log("设置非阻塞模式成功!")
}


thrdHandle = thread.create(
     function(mainForm,Hiddevice,Hex){
     //import console;
     import Usbhidapi
   while(true){
   var buf = raw.malloc(1000, 0);
var len = 100;
var Rxlength = Usbhidapi.Hidapi_read(Hiddevice, buf, len);
if(Rxlength == -1){
//console.log("读取失败!")
}else {
if(Rxlength == 0){
continue ; //没数据退出
}
var str = "";
//str = Aiscii(buf,Rxlength);
str = Hex(buf,Rxlength);
mainForm.receivedata.add(str);
mainForm.receivedata.scrollToBottom();
//console.log(str);
}  

    } //end while
 
     }, mainForm,Hiddevice,Hex

);

mainForm.button2.disabled = false;
owner.text = "关闭";
var namebuf = raw.malloc(1000);
//var buf= "";
var Maxlen = 255;
var ret,buf2= Usbhidapi.Hidapi_get_manufacturer_string(Hiddevice,namebuf,Maxlen);
if(ret != -1){
mainForm.user_name.text = "HID设备: " ++ buf2 ++ " 已打开!";
mainForm.user_name.disabled = false;
}


}else {
mainForm.msgbox("Vid和Pid方式打开失败!")
return;
}


}elseif(owner.text == "关闭"){
Usbhidapi.Hidapi_close(Hiddevice);
owner.text = "打开";
mainForm.user_name.text = "";
mainForm.user_name.disabled = true;
mainForm.button2.disabled = true;
//console.log("已经关闭");
//thread.suspend(thrdHandle);
}

}

mainForm.button2.oncommand = function(id,event){
//发送函数
var trandata = (sel_Obj=="ascii") ? mainForm.senddata.text : Ascii(mainForm.senddata.text);
var Txlength = Usbhidapi.Hidapi_write(Hiddevice,'\0'+trandata,#trandata+1);
if(Txlength == -1){
mainForm.msgbox("发送失败!")
}else {
//console.log("发送成功!!发送长度为:",#mainForm.senddata.text)
}

}

//listbox的纵向滚动条显示最下方,消息方式
mainForm.receivedata.scrollToBottom = function () {

    return ::SendMessageInt(owner.hwnd, 0x115/*_WM_VSCROLL*/, 0x7/*_SB_BOTTOM*/, 0);

}
//设置listbox横向滚动条
//::SendMessageInt( mainForm.receivedata.hwnd,0x194/*_LB_SETHORIZONTALEXTENT*/,500,0)

mainForm.enableDpiScaling();
mainForm.show();

return win.loopMessage();


admin

赞同来自:

更新: 增加弹出菜单功能[删除]

添加下列代码即可:

import win.ui.menu;
//创建弹出菜单
mainForm.popmenu = win.ui.popmenu(mainForm); 
mainForm.popmenu.add('删除',function(id){ 
mainForm.receivedata.delete()
} ) 

mainForm.receivedata.wndproc = function(hwnd,message,wParam,lParam){
select( message ) { 
case 0x205/*_WM_RBUTTONUP*/{
var x,y = win.getMessagePos();  
var item = mainForm.receivedata.hitTest(x,y,true); 
if( item ){
mainForm.receivedata.selIndex = item;
mainForm.popmenu.popup(x,y,true)
}

}
}


admin

赞同来自:

继续更新,

新增列表框内容保存到txt功能,新增右键菜单清空数据功能:

import fsys.dlg;
exp_to_txt=function(){
    var path = fsys.dlg.save(
        "*.txt|*.txt|",
        io.fullpath("") 
    )
    var str="";
    for(i=1;mainForm.receivedata.count;1){
       str = str ++ mainForm.receivedata.getItemText(i) ++ '\r\n';
    }
   var ret = string.save(path,str);
   if(ret){
    mainForm.msgbox("保存成功!")
   }else {
    mainForm.msgbox("保存失败!")
   }
   
}

//创建弹出菜单
mainForm.popmenu = win.ui.popmenu(mainForm); 
mainForm.popmenu.add('删除选中行',function(id){ 
mainForm.receivedata.delete();
} ) 
mainForm.popmenu.add('清空列表内容',function(id){ 
mainForm.receivedata.clear();
} ) 
mainForm.popmenu.add('全部数据导出到TXT',function(id){ 
exp_to_txt();
} )


admin

赞同来自:

wps表格和图表操作:

//Excel 图表
import wps.et;

var excel = wps.et( true );
if( !excel ) error("该示例需要安装wps");

var book  = excel.WorkBooks.Add()
var sheet = book.Worksheets(1)
excel.Visible = true
 
for row=1;30 begin
  sheet.Cells(row, 1).Value2 = math.floor(math.random(1*19) * 100)
end
 
var chart = excel.Charts.Add()
chart.ChartType = 4 //xlLine
var range = sheet.Range("A1:A30")
chart.SetSourceData(range,2)

随手记录一个: 标准库自带的解析器

//CSV,TXT格式文本数据
//下面的代码仅使用系统组件,不需要安装ACCESS软件

var txt = /*
Name,Starred,Contact_Id,xxxx
"孟轲","0",0
"张九龄","1",1 
*/ 
string.save("/Contact.csv",..string.fromto(txt) ); //创建测试的TXT数据库

//指定分隔符,不是逗号就要在这里改
import fsys.ini;
var schema = fsys.ini("/schema.ini")
schema.write("Contact.csv","Format","Delimited(,)")

import access;
import console;

var txtDb =  access(  "/" );   
for(rs in txtDb.each("SELECT * FROM [Contact.csv] " ) ){ 
     console.log( rs("Name").value,rs("Starred").value    );  
}

txtDb.close();

console.log("下面试试标准库自带的解析器")
//--------------------------------------------------
console.more(1)

import string.database;
var strDb = string.database(",");

var data = strDb.parse(txt); //解析数据
console.dump( data )

var str = strDb.stringify(data); //存为文本
console.dump( str );
console.pause();


admin

赞同来自:

更新:

增加导出数据到excel表:

exp_to_wps=function(){
    var path = fsys.dlg.save(
        "*.csv|*.csv|",
        io.fullpath("") 
    )
    var str="";
    for(i=1;mainForm.receivedata.count;1){
       str = str ++ mainForm.receivedata.getItemText(i) ++ '\r\n';
    }
    str = string.replace(str," ",",");
   var ret = string.save(path,str);
   if(ret){
    mainForm.msgbox("保存成功!")
   }else {
    mainForm.msgbox("保存失败!")
   }
   
}
//创建弹出菜单
mainForm.popmenu = win.ui.popmenu(mainForm); 
mainForm.popmenu.add('删除选中行',function(id){ 
mainForm.receivedata.delete();
} ) 
mainForm.popmenu.add('清空列表内容',function(id){ 
mainForm.receivedata.clear();
} ) 
mainForm.popmenu.add('全部数据导出到TXT',function(id){ 
exp_to_txt();
} ) 
mainForm.popmenu.add('全部数据导出到wps',function(id){ 
exp_to_wps();
} )

blob.png

admin

赞同来自:

更新:

增加发送前对输入数据进行判断,1:是否是hex规定的字符,2:是否hex输入的是偶数个

mainForm.button2.oncommand = function(id,event){
//发送函数
if(sel_Obj == "hex"){
var strd = string.replace(mainForm.senddata.text,"\s","");
var tt = string.find(strd,"[^0-9a-fA-F]");
if(tt != null){
mainForm.msgboxErr("输入了非十六进制字符!")
return;
}else {
if((#strd%2) != 0){ //非偶数
mainForm.msgboxErr("Hex格式输入错误!")
return;
}
}

}
var trandata = (sel_Obj=="ascii") ? mainForm.senddata.text : Ascii(mainForm.senddata.text);
var Txlength = Usbhidapi.Hidapi_write(Hiddevice,'\0'+trandata,#trandata+1);
if(Txlength == -1){
mainForm.msgbox("发送失败!")
}else {
//console.log("发送成功!!发送长度为:",#mainForm.senddata.text)
}

}


admin

赞同来自:

更新:

发布为exe之后,发现问题: 打开设备然后关闭设备,再次点击打开就会提示打开出错....

经过多次修改和调试后,发现是因为死在了read读取的线程中hid_read函数地方,初步判断是read貌似在线程中模式是阻塞模式,但是我线程中添加设置为非阻塞还是同样的问题,现在不得而知,

解决办法是: read换成超时模式,read_timeout

另外增加线程的打开和关闭判断,使用了thread.set(标志)和get(标志)

另外将hid_open获取到的Hiddevice,也用thread.set(HHiddevice,Hiddevice)和get来传递,利于判断非空.

thread.set("handlexx",null);

mainForm.button.oncommand = function(id,event){
if(owner.text == "打开"){
thread.set("opedclose", true);
var ret = Usbhidapi.Hidapi_init();
if(ret == -1){
mainForm.msgbox("初始化失败!")
//失败则退出
return;
}else {
//console.log("初始化成功!")
}

Hiddevice = Usbhidapi.Hidapi_open(tonumber(mainForm.hid_vid.text), tonumber(mainForm.hid_pid.text), null);
if(Hiddevice){
thread.set("handlexx",Hiddevice );
//console.log("Vid和Pid方式打开成功!")
//线程中hid读取只能在非阻塞模式使用,否则会死机
var ret = Usbhidapi.Hidapi_set_nonblocking(Hiddevice, 0);
if(ret == -1){
mainForm.msgbox("设置阻塞模式失败!")
Usbhidapi.Hidapi_close(Hiddevice);
return;
}else {
//console.log("设置非阻塞模式成功!")
}


thrdHandle = thread.create(
     function(mainForm,Hex){
     //import console;
     import Usbhidapi
   while(thread.get("opedclose")){
   var buf = raw.malloc(1000, 0);
var len = 65;
var devhandle = thread.get("handlexx");
if(devhandle == null){
break ;
}
var Rxlength = Usbhidapi.Hidapi_read_timeout(devhandle, buf, len ,1);//1ms超时
if(Rxlength == -1){
//console.log("读取失败!")
}else {
if(Rxlength == 0){
continue ; //没数据退出
}
var str = "";
//str = Aiscii(buf,Rxlength);
str = Hex(buf,Rxlength);
mainForm.receivedata.add(str);
mainForm.receivedata.scrollToBottom();
//console.log(str);
}  

    } //end while
 
     }, mainForm,Hex

);

mainForm.button2.disabled = false;
owner.text = "关闭";
var namebuf = raw.malloc(1000);
//var buf= "";
var Maxlen = 255;
var ret,buf2= Usbhidapi.Hidapi_get_manufacturer_string(Hiddevice,namebuf,Maxlen);
if(ret != -1){
mainForm.user_name.text = "HID设备: " ++ buf2 ++ " 已打开!";
mainForm.user_name.disabled = false;
}


}else {
mainForm.msgbox("Vid和Pid方式打开失败!")
return;
}


}elseif(owner.text == "关闭"){
thread.set("opedclose",false);
thread.set("handlexx",null )
thread.waitOne(thrdHandle);
Usbhidapi.Hidapi_close(Hiddevice);
owner.text = "打开";
mainForm.user_name.text = "";
mainForm.user_name.disabled = true;
mainForm.button2.disabled = true;
//console.log("已经关闭");
//thread.suspend(thrdHandle);
}

}


admin

赞同来自:

监控并获取Bushound中的数据导入到aar的listview中:

import win.ui;
import console;
/*DSG{{*/
mainForm = win.form(text="获取BUShound数据";right=1299;bottom=434)
mainForm.add(
listview={cls="listview";left=13;top=9;right=1289;bottom=424;ah=1;asel=false;aw=1;db=1;dl=1;dr=1;dt=1;edge=1;fullRow=1;gridLines=1;hscroll=1;msel=false;vscroll=1;z=1}
)
/*}}*/

mainForm.threadCallable();

//console.open();

import win.imageList;
var imagelist = win.imageList(1,30);
mainForm.listview.setImageList(imagelist, 1/*_LVSIL_NORMAL*/);

mainForm.listview.insertColumn("Device",50);
mainForm.listview.insertColumn("Length",100);
mainForm.listview.insertColumn("Phase");
mainForm.listview.insertColumn("Data",500);
mainForm.listview.insertColumn("Description",200);
mainForm.listview.insertColumn("Data");
mainForm.listview.insertColumn("Time",-1);

thread.invoke( 
function(mainForm){

import winex;
import winex.ctrl.listview;
var 计数 = 0;

hwnd = 1313058;//此数据是编程助手抓到的list控件的句柄
xxlistview = winex.ctrl.listview( hwnd ); 
wRirelist = function(start,number){
for(i=start;number;1 ) 
{  
mainForm.listview.addItem();
mainForm.listview.setItemText(xxlistview.getItemText(i,1,1000),i,1);
mainForm.listview.setItemText(xxlistview.getItemText(i,3,1000),i,2);
mainForm.listview.setItemText(xxlistview.getItemText(i,4,1000),i,3);
mainForm.listview.setItemText(xxlistview.getItemText(i,5,1000),i,4);
mainForm.listview.setItemText(xxlistview.getItemText(i,6,1000),i,5);
mainForm.listview.setItemText(xxlistview.getItemText(i,9,1000),i,6);
mainForm.listview.setItemText(xxlistview.getItemText(i,10,1000),i,7);
mainForm.listview.scrollToBottom();


}

while(true){
var 获取到的外部行数 = xxlistview.count;

if(获取到的外部行数 != 计数){
if(计数 == 0){
wRirelist(1,获取到的外部行数);
计数 = 获取到的外部行数;
}else {

if(计数>获取到的外部行数){ //说明窗体清零过一次
mainForm.listview.clear();
wRirelist(1,获取到的外部行数);
计数 = 获取到的外部行数;
}else {

var 起始位置 = 计数+1;
wRirelist(起始位置,获取到的外部行数);
计数 = 获取到的外部行数;


}

}

}

}

},mainForm
)

//listbox的纵向滚动条显示最下方,消息方式
mainForm.listview.scrollToBottom = function () {
 
    return ::SendMessageInt(owner.hwnd, 0x115/*_WM_VSCROLL*/, 0x7/*_SB_BOTTOM*/, 0);
 
}
mainForm.enableDpiScaling();
mainForm.show();

return win.loopMessage();


admin

赞同来自:

bushound数据获取:

更新: 打开bushound后,打开aar做的监控软件,自动获取窗口中数据句柄,无需手动输入了.后台线程自动更新数据

import win.ui;
import console;
/*DSG{{*/
mainForm = win.form(text="获取BUShound数据";right=1299;bottom=501)
mainForm.add(
listview={cls="listview";left=13;top=9;right=1289;bottom=424;ah=1;asel=false;aw=1;db=1;dl=1;dr=1;dt=1;edge=1;font=LOGFONT(h=-16);fullRow=1;gridLines=1;hscroll=1;msel=false;vscroll=1;z=1}
)
/*}}*/

mainForm.threadCallable();

//console.open();

import win.imageList;
var imagelist = win.imageList(1,30);
mainForm.listview.setImageList(imagelist, 1/*_LVSIL_NORMAL*/);

mainForm.listview.insertColumn("Device",50);
mainForm.listview.insertColumn("Length",100);
mainForm.listview.insertColumn("Phase");
mainForm.listview.insertColumn("Data",500);
mainForm.listview.insertColumn("Description",200);
mainForm.listview.insertColumn("Data");
mainForm.listview.insertColumn("Time",-1);



thread.invoke( 
function(mainForm){

import winex;
import winex.ctrl.listview;
var hwnd = 0;//此数据是编程助手抓到的list控件的句柄
var hwnd1,线程ID,进程ID = winex.find( ,"Bus Hound",,) //Form1 换为被抓数据的软件的父窗口标题。
for hwnd2,title,theadId,processId in winex.each( ,,hwnd1){//抓取二级窗口控件类句柄
for hwnd3,title,theadId,processId in winex.each("", ,hwnd2) { //抓取三级句柄
if(title == "List3"){//数据句柄的标题
hwnd = hwnd3;//赋值给后续使用
break;
}
}

}

var 计数 = 0;

//hwnd = 1313058;//此数据是编程助手抓到的list控件的句柄
xxlistview = winex.ctrl.listview( hwnd ); //通过获取到的句柄取得listview数据列表
wRirelist = function(start,number){
for(i=start;number;1 ) 
{  
mainForm.listview.addItem();
mainForm.listview.setItemText(xxlistview.getItemText(i,1,1000),i,1);
mainForm.listview.setItemText(xxlistview.getItemText(i,3,1000),i,2);
mainForm.listview.setItemText(xxlistview.getItemText(i,4,1000),i,3);
mainForm.listview.setItemText(xxlistview.getItemText(i,5,1000),i,4);
mainForm.listview.setItemText(xxlistview.getItemText(i,6,1000),i,5);
mainForm.listview.setItemText(xxlistview.getItemText(i,9,1000),i,6);
mainForm.listview.setItemText(xxlistview.getItemText(i,10,1000),i,7);
mainForm.listview.scrollToBottom();


}

while(true){
var 获取到的外部行数 = xxlistview.count;

if(获取到的外部行数 != 计数){
if(计数 == 0){
wRirelist(1,获取到的外部行数);
计数 = 获取到的外部行数;
}else {

if(计数>获取到的外部行数){ //说明窗体清零过一次
mainForm.listview.clear();
wRirelist(1,获取到的外部行数);
计数 = 获取到的外部行数;
}else {

var 起始位置 = 计数+1;
wRirelist(起始位置,获取到的外部行数);
计数 = 获取到的外部行数;

}

}

}

}

},mainForm
)

//listbox的纵向滚动条显示最下方,消息方式
mainForm.listview.scrollToBottom = function () {
 
    return ::SendMessageInt(owner.hwnd, 0x115/*_WM_VSCROLL*/, 0x7/*_SB_BOTTOM*/, 0);
 
}
mainForm.enableDpiScaling();
mainForm.show();

return win.loopMessage();


admin

赞同来自: tinyun

bushound数据采集更新: 增加虚拟桌面 使用

先前的程序使用的前提必须先手动打开bushound软件,然后打开这个采集软件,这样就出现了个问题,桌面上即要显示bushound软件也要现世采集软件,桌面不干净.

于是先前想了一种办法: 点击采集软件自动后台线程process打开bushound,然后瞬间将bushound的窗口最小化并隐藏到进程中.

但是这个导致了一个问题,打开采集软件的同时会突然发现桌面上闪现了一下bushound的窗口然后消失了..

闪现的这下怎么看都不舒服,

于是我想了另外一种办法:

通过 虚拟桌面 来在虚拟桌面里面打开bushound,然后主桌面里采集程序通过线程来采集bushound的数据.

虚拟桌面的好处是他专门开辟一个内存来存放打开的程序,在主桌面里面是看不到这个程序运行的.而且也不会有任何能使人感受不好的现象发生.

import win.ui;
import win.util.desktop;//虚拟桌面
/*DSG{{*/
mainForm = win.form(text="获取BUShound数据";right=1299;bottom=501)
mainForm.add(
button={cls="button";text="开启桌面";left=26;top=441;right=222;bottom=484;z=2};
button2={cls="button";text="切换桌面";left=237;top=439;right=433;bottom=482;z=3};
button3={cls="button";text="关闭桌面";left=458;top=441;right=654;bottom=484;z=4};
button4={cls="button";text="采集";left=688;top=438;right=884;bottom=481;z=5};
listview={cls="listview";left=13;top=9;right=1289;bottom=424;ah=1;asel=false;aw=1;db=1;dl=1;dr=1;dt=1;edge=1;font=LOGFONT(h=-16);fullRow=1;gridLines=1;hscroll=1;msel=false;vscroll=1;z=1}
)
/*}}桌面*/

var virDesktp = win.util.desktop();
//注册热键 Ctrl+D快捷键来切换桌面
hkid = mainForm.reghotkey(function(id,mod,vk){
    virDesktp.switch( ) //切换桌面   
},2/*_MOD_CONTROL*/,'D'#); 

mainForm.button.oncommand = function(id,event){
//mainForm.msgbox( mainForm.button.text );

virDesktp.create("myDesktop") //创建桌面
}
mainForm.button3.oncommand = function(id,event){
//mainForm.msgbox( mainForm.button3.text );
virDesktp.close(); //关闭桌面

}
mainForm.button2.oncommand = function(id,event){
//mainForm.msgbox( mainForm.button2.text );
 virDesktp.switch( ) //切换桌面  

}
//使主界面控件线程控制
mainForm.threadCallable();

//console.open();
//使用image属性来重设listview行高
import win.imageList;
var imagelist = win.imageList(1,30);
mainForm.listview.setImageList(imagelist, 1/*_LVSIL_NORMAL*/);
//设置所有需要的列名
mainForm.listview.insertColumn("Device",50);
mainForm.listview.insertColumn("Length",100);
mainForm.listview.insertColumn("Phase",50);
mainForm.listview.insertColumn("Data",500);
mainForm.listview.insertColumn("Description",200);
mainForm.listview.insertColumn("Data",50);
mainForm.listview.insertColumn("Time",-1);
//
mainForm.button4.oncommand = function(id,event){
//开启采集线程
thread.invoke( 
function(mainForm,hDesktop){
::User32.SetThreadDesktop(hDesktop);//切换线程到新桌面,这样才能采集到句柄
import winex;
import winex.ctrl.listview;
var hwnd = 0;//此数据是编程助手抓到的list控件的句柄
var hwnd1,线程ID,进程ID = winex.find( ,"Bus Hound",,) //Form1 换为被抓数据的软件的父窗口标题。
for hwnd2,title,theadId,processId in winex.each( ,,hwnd1){
for hwnd3,title,theadId,processId in winex.each("", ,hwnd2) { 
if(title == "List3"){
hwnd = hwnd3;
break;
}
}

}
if(hwnd == null){
return;
}
var 计数 = 0;
xxlistview = winex.ctrl.listview( hwnd ); 
wRirelist = function(start,number){
for(i=start;number;1 ) 
{  
mainForm.listview.addItem();
mainForm.listview.setItemText(xxlistview.getItemText(i,1,1000),i,1);
mainForm.listview.setItemText(xxlistview.getItemText(i,3,1000),i,2);
mainForm.listview.setItemText(xxlistview.getItemText(i,4,1000),i,3);
mainForm.listview.setItemText(xxlistview.getItemText(i,5,1000),i,4);
mainForm.listview.setItemText(xxlistview.getItemText(i,6,1000),i,5);
mainForm.listview.setItemText(xxlistview.getItemText(i,9,1000),i,6);
mainForm.listview.setItemText(xxlistview.getItemText(i,10,1000),i,7);
mainForm.listview.scrollToBottom();


}

while(true){
var 获取到的外部行数 = xxlistview.count;

if(获取到的外部行数 != 计数){
if(计数 == 0){
wRirelist(1,获取到的外部行数);
计数 = 获取到的外部行数;
}else {

if(计数>获取到的外部行数){ //说明窗体清零过一次
mainForm.listview.clear();
wRirelist(1,获取到的外部行数);
计数 = 获取到的外部行数;
}else {

var 起始位置 = 计数+1;
wRirelist(起始位置,获取到的外部行数);
计数 = 获取到的外部行数;

}

}

}

}
},mainForm,virDesktp.desktop.myDesktop
)

}


//listbox的纵向滚动条显示最下方,消息方式
mainForm.listview.scrollToBottom = function () {
 
    return ::SendMessageInt(owner.hwnd, 0x115/*_WM_VSCROLL*/, 0x7/*_SB_BOTTOM*/, 0);
 
}
mainForm.enableDpiScaling();
mainForm.show();

return win.loopMessage();


admin

赞同来自: tinyun

额,接上面 虚拟桌面 方式采集数据:

忘了记录一个功能: 虚拟桌面中

virDesktopMgr.execute("桌面名字","程序路径","参数") = 在虚拟桌面运行程序

这个可以直接在新虚拟桌面中打开一个exe

mengydz.com

赞同来自:

太猛了,厉害厉害

PamPam

赞同来自:

工程哪里可以下载

长春老猫

赞同来自:

aardio扩展库里的“hid USB通信接口”也是你发的呗!厉害。我用hid扩展库刚刚驱动了一个游戏手柄。

京城老付

赞同来自:

dashen   

flydreamsky

赞同来自:

厉害厉害

要回复问题请先登录注册