本帖最后由 winner 于 2012-11-3 10:43 编辑
最近学习api操作,拿wlan的api练手
例如下面这个API,这是MSDN的官方C++示例
http://msdn.microsoft.com/en-us/library/windows/desktop/ms706716(v=vs.85).aspx- DWORD WINAPI WlanEnumInterfaces(
- _In_ HANDLE hClientHandle,
- _Reserved_ PVOID pReserved,
- _Out_ PWLAN_INTERFACE_INFO_LIST *ppInterfaceList
- );
复制代码 里面的一个参数
PWLAN_INTERFACE_INFO_LIST *ppInterfaceList
因为不懂C++,所以我查阅了一下资料,
好像ppInterfaceList参数是一个PWLAN_INTERFACE_INFO_LIST型的结构体,
加上*号代表传入的是指向PWLAN_INTERFACE_INFO_LIST型结构体的一个指针,
然后我开始写aardio代码,
先查阅了结构体类型的相关资料,在api数据类型文档中发现一句
http://bbs.aardio.com/doc/reference/libraries/kernel/raw/datatype.html
注意在API参数中,struct被转换为指针按引用传递,如果是按值传递的结构体,需要展开所有成员为普通参数.
所以我这样定义了这个API函数,对上面这句话的理解就是 只需要把结构体声明一个结构体对象,然后传进去就行了,最后发现理解的不对
结构体:
import win.guid;
class WLAN_INTERFACE_INFO_LIST{
int dwNumberOfItems;
int dwIndex;
struct InterfaceInfo[] = { {
struct InterfaceGuid = ..win.guid();
byte strInterfaceDescription[256];
int isState;
} };
}
WlanEnumInterfaces = ::Wlanapi.api("WlanEnumInterfaces","int(int hClientHandle,pointer pReserved,struct ppInterfaceList)")
pIfList = WLAN_INTERFACE_INFO_LIST();
var dwResult = WlanEnumInterfaces(hClient,null,pIfList)
io.print(dwResult,pIfList['InterfaceInfo'][1]['InterfaceGuid'])
结果发现他只能打印出一个空的,也就是默认的那个GUID 00000000-0000-0000-0000-000000000000
然后我又把API声明改成这个样子,
WlanEnumInterfaces = ::Wlanapi.api("WlanEnumInterfaces","int(int hClientHandle,pointer pReserved,struct& ppInterfaceList)")
pIfList = WLAN_INTERFACE_INFO_LIST();
var dwResult,pIfList2 = WlanEnumInterfaces(hClient,null,pIfList)
io.print(dwResult,pIfList2['InterfaceInfo'][1]['InterfaceGuid'])
结果还是输出GUID 00000000-0000-0000-0000-000000000000
接着我又改成这种,API最后一个参数传入指针(我也不知道这算不算是指针)
WlanEnumInterfaces = ::Wlanapi.api("WlanEnumInterfaces","int(int hClientHandle,pointer pReserved,pointer ppInterfaceList)")
pIfList = WLAN_INTERFACE_INFO_LIST();
var pPointer = raw.buffer(pIfList)
var dwResult = WlanEnumInterfaces(hClient,null,pPointer)
pIfList2 = raw.convert(pPointer,pIfList)
io.print(dwResult,pIfList2['InterfaceInfo'][1]['InterfaceGuid'])
结果还是输出GUID 00000000-0000-0000-0000-000000000000
于是我又改,改成传入引用指针
WlanEnumInterfaces = ::Wlanapi.api("WlanEnumInterfaces","int(int hClientHandle,pointer pReserved,pointer& ppInterfaceList)")
pIfList = WLAN_INTERFACE_INFO_LIST();
var pPointer = raw.buffer(pIfList)
var dwResult = WlanEnumInterfaces(hClient,null,pPointer)
pIfList2 = raw.convert(pPointer,pIfList)
io.print(dwResult,pIfList2['InterfaceInfo'][1]['InterfaceGuid'])
结果还是输出GUID 00000000-0000-0000-0000-000000000000
然后我查手册,发现传入参数加&,会有一个返回值,于是我又修改了,加了个返回值
WlanEnumInterfaces = ::Wlanapi.api("WlanEnumInterfaces","int(int hClientHandle,pointer pReserved,pointer& ppInterfaceList)")
pIfList = WLAN_INTERFACE_INFO_LIST();
var pPointer = raw.buffer(pIfList)
var dwResult,pPointer2 = WlanEnumInterfaces(hClient,null,pPointer)
pIfList2 = raw.convert(pPointer2,pIfList)
io.print(dwResult,pIfList2['InterfaceInfo'][1]['InterfaceGuid'])
终于得到了正常的GUID 449b23c8-f18c-4d64-9bbd-221c2c9671fe
关键问题就是:
1.
结构体 | struct | 32位 | table | struct | | 可以在API参数中使用空表 {} 表示C/C++中的null结构体指针
注意在API参数中,struct被转换为指针按引用传递,如果是按值传递的结构体,需要展开所有成员为普通参数. |
手册里这么说"在API参数中,struct被转换为指针按引用传递"
我直接传入struct对象,为什么获取不到值呢?
后来必须用raw.buffer() 把结构体对象复制到内存中,然后传入指向这个结构体的指针 才能正常获取数据
2.
raw.buffer分配定长的内存,并返回托管指针.
参数如果是一个普通的结构体(struct table).raw.buffer创建相同大小的内存并复制结构体的内存数据.
托管指针一般是由指向aardio分配的内存,内存不再使用时会自动释放,是一种内部指针、伪指针。
raw.buffer创建的托管指针并可在API函数中作为pointer指针类型参数使用,也可以可以使用索引操作符直接读写内存数据.这与aardio中的字符串类似,指定索引返回指定位置的字节码,如果索引溢出(过大或过小)会返回0.
像我这个结构体,算是个普通机构体吧?
class WLAN_INTERFACE_INFO_LIST{
int dwNumberOfItems;
int dwIndex;
struct InterfaceInfo[] = { {
struct InterfaceGuid = ..win.guid();
byte strInterfaceDescription[256];
int isState;
} };
}
根据上面手册的说明,
"参数如果是一个普通的结构体(struct table).raw.buffer创建相同大小的内存并复制结构体的内存数据."
那我这样用raw.buffer()函数复制的结构体,是一个空的结构体,里面没有任何数据,申请的内存也肯定不大,
如果这个api函数往里面添加数据过多,会不会导致内存错误之类的问题?
|