junyee 发表于 2021-3-12 09:08:19

数组传递给dll


    离第一次接触AU3一晃近15年了. 虽然学了不下十来种语言,但写点小东西还是这个最顺手.

    AU3 是一种弱变量语言, 用起来很方便, 玩得深后就会有困扰.
    由于并不是开源软件,碰到问题也只能凭脑洞瞎分析.

    AU3和很多高级语言/脚本一样,不带指针功能.但C的指针用起来却是很爽.
   自带的ptr 函数至今不知道有何具体实用意义?

   在调用winapi或其它dll,便经常要碰到指针参数.

   这几天读了"CommMG.au3" 发现一个有趣的函数.
Func _CommSendByteArray($pAddr, $iNum, $iWait)
    If Not $fPortOpen Then
      SetError(1)
      Return 0
    EndIf

    Local $vDllAns = DllCall($hDll, 'int', 'SendByteArray', 'ptr', $pAddr, 'int', $iNum, 'int', $iWait)
    If @error <> 0 Or $vDllAns = -1 Then
      SetError(1)
      Return -1
    Else
      Return $vDllAns
    EndIf

EndFunc   ;==>_CommSendByteArray


一般情况我只能用dllstruct*系列函数 将数组转换为自定义类型 并获取指针传入.
而他这里,数组竟然可以作为参数传入 $pAddr.
在C 中数组名就是数组的首地址, au3 的数组可以混合各种类型的变量,元素宽度都可以不统一.而 au3 明显不会这样,用指针操作就要乱套了.

百思不得其解.
猜测是 dll 内部有对 $pAddr 进一步处理.
至少我在别的地方如此调用是行不通的.

大佬路过请不吝赐教,谢谢!



gyp2000 发表于 2021-3-12 10:15:16

我估计你是被这个函数的名字忽悠了。
我估计这个函数的目的就是发送一个数组,他需要的参数是一个指针。
而不是将AU3的数组变量直接发出去。

gyp2000 发表于 2021-3-12 10:05:57

并没看到直接传入了一个数组。变量名 $pAddr,一般按照命名规则,可以判断他是个指针。

然后找到列子:
Func _ReadFreq()
$bBinData = Binary("0xFEFE94E003FD")    ; code to request frequency
$iNumbytes = BinaryLen($bBinData)
$tBinData = DllStructCreate("byte["&$iNumbytes&"]")
DllStructSetData($tBinData, 1, $bBinData)
$iRet = _CommSendByteArray(DllStructGetPtr($tBinData),$iNumbytes,1)   ;这里传入的是一个指针。。
If @error Or $iRet = -1 Then ConsoleWrite("!Error: " &@error & @CRLF)

;here goes the code to read input buffer and change to ascii
;using BinaryToString, I guess
;$sfreq var holds frequency

EndFunc

haijie1223 发表于 2021-3-12 11:55:12

目测二楼的示例代码就是正确的用法。dllcall的写法有很多种,只要理解透了,怎么写都行。p版的dllcall精讲,你值得拥有。

junyee 发表于 2021-3-12 17:08:56

本帖最后由 junyee 于 2021-3-12 17:11 编辑

haijie1223 发表于 2021-3-12 11:55
目测二楼的示例代码就是正确的用法。dllcall的写法有很多种,只要理解透了,怎么写都行。p版的dllcall精讲 ...
..
确实被这个函数名迷惑了.

翻看这个函数的起因是, commMG.dll 没有提供64位的.
就自己写个 moxa 的 pcoom.dll, 要用的函数都写好了,
就是数组转换很不爽,翻看 commMG.au3 误以为可以支持 au3数组.
大概是14年用 commMG.au3 写了个串口调试工具.
当时为了处理数组自己写了个 "__CommSendByteArray" 函数,(个人习惯自己写的函数喜欢多加个下划线)
今天重读别的代码时误认为是 commMG.au3 中的.

这个是 commMG.au3 的作者帖子.
https://www.autoitscript.com/for ... -port-com-port-udf/


---

换个语言写就没这些麻烦事了.:face (17): ...

junyee 发表于 2021-3-12 17:14:43

在这里谢谢 2,4楼的朋友.

已经好多年没有来这个论坛了,
都是 隔壁多个论坛的熟面孔, 世界真小.

junyee 发表于 2021-3-12 17:49:24

发现 au3 的字符串 是指针方式传递的.

如:

Local $vDllAns = DllCall($hDll, 'int', 'SendByteArray', 'str', "0123456789abcdef", 'int', 16, 'int', 50 )

这样是可以工作的.不过,没啥用.
在C语言中用指针就能解决 ,到au3 中用 BinarytoString 遇到\0就会切断.


haijie1223 发表于 2021-3-12 18:34:47

junyee 发表于 2021-3-12 17:49
发现 au3 的字符串 是指针方式传递的.

如:


在C中遇到0不一样结束么?字符串都是以指针传送。AU3内部封装了au3特有的STR类型而已。

junyee 发表于 2021-3-12 18:51:22

本帖最后由 junyee 于 2021-3-12 19:00 编辑

haijie1223 发表于 2021-3-12 18:34
在C中遇到0不一样结束么?字符串都是以指针传送。AU3内部封装了au3特有的STR类型而已。
是的.
我没有说这有不妥.

似乎au3的字符串传递的就是指针,如果想把 变量,如 binaray("0x303132330035363738") 转为字符串传递给dllcall就会遇到截断的问题.
打个比方,三楼提供的代码可以简化写为:

Local $vDllAns = DllCall($hDll, 'int', 'SendByteArray', 'str', BinaryToString("0xFEFE94E003FD"), 'int', 6, 'int', 10 )

但是,如果数据中有 00 就不行了..







haijie1223 发表于 2021-3-12 19:02:45

junyee 发表于 2021-3-12 18:51
是的.
我没有说这有不妥.



但是正常的字符串转为二进制,怎么会出现00呢?

junyee 发表于 2021-3-12 19:06:00

haijie1223 发表于 2021-3-12 19:02
但是正常的字符串转为二进制,怎么会出现00呢?

看来您是不常接触串口调试.

我用AU3 写上位机, 用来与 单片机之类的通讯.
通讯的数据不是字符串.

我用字符串是可以方便绕过一堆的 dllstruct 操作.

haijie1223 发表于 2021-3-12 19:09:02

junyee 发表于 2021-3-12 19:06
看来您是不常接触串口调试.

我用AU3 写上位机, 用来与 单片机之类的通讯.


硬件数据是有可能的。
正打算研究一下串口数据的协议,QQ好友聊一波252951233

junyee 发表于 2021-3-12 19:52:23

本帖最后由 junyee 于 2021-3-12 19:53 编辑

haijie1223 发表于 2021-3-12 19:09
硬件数据是有可能的。
正打算研究一下串口数据的协议,QQ好友聊一波252951233
已加.

---
我把 pcomm 常用的API都用au3封装了下.,初步测试成功.
经测试这个 PCOMM.DLL 比 commg.dll 要好用很多. moxa 官方提供了详细的开发文档.




gyp2000 发表于 2021-3-13 00:00:24

junyee 发表于 2021-3-12 18:51
是的.
我没有说这有不妥.



STR 是字符串类型,一般字符串类型可以忽略长度参数。因为字符串的结束符就是00
你想传入00进去,那怎么可能呢。

junyee 发表于 2021-3-13 08:51:16

本帖最后由 junyee 于 2021-3-13 08:54 编辑

gyp2000 发表于 2021-3-13 00:00
STR 是字符串类型,一般字符串类型可以忽略长度参数。因为字符串的结束符就是00
你想传入00进去,那怎么 ...
你没理解我的意思..

AU3 没有指针,但str类型是以指针的方式传递.
我想用 Binary 转为 string 变通实现指针传递.


可以工作.
Local $vDllAns = DllCall($hDll, 'int', 'SendByteArray', 'str', BinaryToString("0xFEFE94E003FD"), 'int', 6, 'int', 10 )

这个就不行
Local $vDllAns = DllCall($hDll, 'int', 'SendByteArray', 'str', BinaryToString("0xFE0094E003FD"), 'int', 6, 'int', 10 )

在传递时时字符串被破坏.或者说是new 了一个变量.我讨论不是AU3 这种处理方式是否不妥(事实上是很妥当的,向不明函数传递一个指针是很危险的),
而是我这个变通的方法在此行不通.

用C写个示例你就明白了.


#include "stdio.h"


void test(char* str)
{
      int i;
      printf("\n%s\n",str);
      for (i=0;i<12;i++){
                printf("%02x ", *(str++));
      }
}

int main(int args, char* argc[])
{
      char str ="hello,world!";

      test(str);
      
      str=0;
      test(str);
      return 0;
}












页: [1] 2
查看完整版本: 数组传递给dll