搜索
查看: 3187|回复: 7

调用外部API的疑问(包括二级指针与字符串)

[复制链接]

2

主题

7

帖子

55

积分

一级会员

Rank: 2

积分
55
发表于 2014-2-26 13:09:21 | 显示全部楼层 |阅读模式
下面是aardio代码
import wsock;
io.open();//打开控制台
::Wpcap := ..raw.loadDll("Wpcap.dll");
pcap_findalldevs := ::Wpcap.api("pcap_findalldevs","int( pointer& alldevsp, pointer errbuf)");
pcap_rmtauth = class {
    int type;
    string username;
           string password;
};
pcap_if = class  {
        pointer next;
        string name;
        string description;
        pointer addresses;
        int flags;
};
pcap_addr = class {
            pointer next;
          pointer addr;
          pointer  netmask;
          pointer  broadaddr;
        pointer dstaddr;
};
_PCAP_ERRBUF_SIZE = 256;

alldevs = pcap_if();
ppointer = raw.buffer(alldevs,512);
errbuf  = raw.buffer(256);
var n,Ppcap2,str = pcap_findalldevs( ppointer ,errbuf);
调用函数pcap_findalldevs()时,出错:"0x004256bb"指令引用的"0x00000000"内存。该内存不能为"written"。
我知道一定是函数声明类型出错,但是,去不知道该如何声明该类型。
以下附上C语言原型。
int pcap_findalldevs  ( pcap_if_t **  alldevsp,   char *  errbuf )  //C函数原型
//以下是所用到的结构体
struct pcap_if {
        struct pcap_if *next;
        char *name;               
        char *description;       
        struct pcap_addr *addresses;
        bpf_u_int32 flags;       
};
struct pcap_addr {
        struct pcap_addr *next;
        struct sockaddr *addr;               
        struct sockaddr *netmask;       
        struct sockaddr *broadaddr;       
        struct sockaddr *dstaddr;       
};
发现该函数结构体内有指针。
pcap_if_t **声明为:pointer& ,char* errbuf (由于API会改动理应声明为string*),但是老出错。我尝试了过,编译不了。
问题是,这类函数要如何声明,如何调用。

回复

使用道具 举报

45

主题

707

帖子

3945

积分

版主

Rank: 7Rank: 7Rank: 7

积分
3945
发表于 2014-2-26 14:56:11 | 显示全部楼层

调用API报错, 不仅仅要检查API声明里的参数类型,另外要检查一个最容易弄错的地方:就是调用约定。 aardio默认使用的是stdcall约定,而Wpca

调用API报错,
不仅仅要检查API声明里的参数类型,另外要检查一个最容易弄错的地方:就是调用约定。
aardio默认使用的是stdcall约定,而Wpcap使用的是cdecl调用约定。所以首先你要把加载DLL的代码改为:
::Wpcap = raw.loadDll("Wpcap.dll",,"cdecl");
再看一下API函数的正确声明:
pcap_findalldevs = ::Wpcap.api("pcap_findalldevs","int(pointer& alldevsp,string& errbuf)");
这里的 errbuf需要你提供缓冲区放错误信息,这种输出类型的字符串声明为 string&就可以,然后调用时你传入缓冲区有长度就可以,例如:
var n,alldevsp,errbuf = pcap_findalldevs(  ,256/*_PCAP_ERRBUF_SIZE*/);  
而第一个参数是一个输出指针,指针声明为pointer没错,输出指针声明为 pointer & 也没错。
但是你搞错了一个东西,这个指针的内存是API来分配的,不是你自己来分配。所以你不需要给他任何参数,传一个空值进去就可以了。而返回值里的alldevsp才是你需要的东西。

这个 alldevsp 就是返回的指针,里面是一个链表,链表的每个节点的next成员又指向下一个节点。
所以你只需要 raw.convert() 将指针转换为结构体,又取结构体的next成员里的指针重复前面的操作,一直到next的指针为空停止。


那么完整代码如下:
  1. import wsock;
  2. import console;

  3. ::Wpcap := raw.loadDll("Wpcap.dll",,"cdecl");
  4. pcap_findalldevs = ::Wpcap.api("pcap_findalldevs","int(pointer& alldevsp,string& errbuf)");

  5. class pcap_if {
  6.     pointer next;
  7.     string name;               
  8.     string description;        
  9.     pointer addresses;
  10.     INT flags;        
  11. };
  12. class pcap_addr {
  13.     pointer next;
  14.     pointer addr;               
  15.     pointer netmask;        
  16.     pointer broadaddr;        
  17.     pointer dstaddr;        
  18. };

  19. //调用API
  20. var n,alldevsp,errbuf = pcap_findalldevs(  ,256/*_PCAP_ERRBUF_SIZE*/);

  21. //遍历指针链表
  22. while( alldevsp ) {
  23.         var interface = raw.convert( alldevsp, pcap_if() );
  24.         console.log( interface.name, interface.description )
  25.         alldevsp = interface.next;
  26. }
复制代码


至于char *这些只要简单的声明为string就可以了。
再好的编程语言到了不会用的人手里,都会变成恶魔,不幸的是 - 不会用的是大多数。
回复

使用道具 举报

2

主题

16

帖子

107

积分

一级会员

Rank: 2

积分
107
发表于 2014-2-26 15:00:14 | 显示全部楼层

版主们回答每一个问题都很用心,代码很工整非常用心的排版, 对于每一个原理、细节都非常耐心的详细解释。在论坛不提问经常看帖子都能学到东西。

版主们回答每一个问题都很用心,代码很工整非常用心的排版,
对于每一个原理、细节都非常耐心的详细解释。在论坛不提问经常看帖子都能学到东西。
回复

使用道具 举报

2

主题

7

帖子

55

积分

一级会员

Rank: 2

积分
55
 楼主| 发表于 2014-2-27 00:11:42 | 显示全部楼层

谢谢,受益非浅,我再调试一下.

谢谢,受益非浅,我再调试一下.
回复

使用道具 举报

0

主题

12

帖子

692

积分

三级会员

Rank: 4

积分
692
发表于 2014-2-28 09:56:43 | 显示全部楼层

好多细节,受教了,好人多哈

好多细节,受教了,好人多哈
回复

使用道具 举报

2

主题

7

帖子

55

积分

一级会员

Rank: 2

积分
55
 楼主| 发表于 2014-3-2 14:52:31 | 显示全部楼层

{:)}终于搞清一件事。 我在上面代码的指针遍历改成如下语句。 //遍历指针链表 while( alldevsp ) { var interface

终于搞清一件事。
我在上面代码的指针遍历改成如下语句。
//遍历指针链表
while( alldevsp ) {
        var interface = raw.convert( alldevsp, pcap_if() );
        console.log("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
        console.log( interface.name, interface.description )
        console.log("next",interface.next,"addresses",interface.addresses)
        alldevsp = interface.next;
}
如果网卡没有启用,它的addresses指针是空的,这一点在写程序时要注意。
另外就是要注意,各函数的返回值,对应关系。
与pcap_findalldevs功能相似的另一个函数,声明如下,供有需要的人参考。
pcap_findalldevs_ex := ::Wpcap.api("pcap_findalldevs_ex","int( string source,pointer auth, pointer& alldevs ,string& errbuf)");
调用时:
var n,alldevsp,errbuf = pcap_findalldevs_ex(_PCAP_SRC_IF_STRING,null,,_PCAP_ERRBUF_SIZE);
注意返回值是3个,我之前就是犯迷,写成了
var n,source,,alldevsp,errbuf = pcap_findalldevs_ex(_PCAP_SRC_IF_STRING,null,null,_PCAP_ERRBUF_SIZE);
这个低级错误,让我找不到要的指针,想了一晚上,现在终于搞定了。同时也多谢论坛朋友的无私奉献。
回复

使用道具 举报

7

主题

103

帖子

641

积分

三级会员

叫我何细尔

Rank: 4

积分
641
QQ
发表于 2014-9-2 08:54:05 | 显示全部楼层

版主的解答细致耐心,又有完整代码。学到了很多,受益匪浅。

版主的解答细致耐心,又有完整代码。学到了很多,受益匪浅。
回复

使用道具 举报

0

主题

17

帖子

108

积分

一级会员

Rank: 2

积分
108
发表于 2017-2-15 18:12:54 | 显示全部楼层
学习。。。。。。。。。。。。。
回复

使用道具 举报

手机版|未经许可严禁引用或转载本站文章|站长邮箱|aardio.com|aardio官方社区 ( 皖ICP备09012014号 )

GMT+8, 2017-9-22 07:07 , Processed in 0.171875 second(s), 22 queries , Wincache On.

Powered by Discuz! X3.3

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表