我想用GetExtendedTcpTable函数获取系统当前TCP的连接信息,我是这样做的
#define TABLE_SIZE 1024typedef struct {
DWORD dwState;
DWORD dwLocalAddr;
DWORD dwLocalPort;
DWORD dwRemoteAddr;
DWORD dwRemotePort;
DWORD dwOwningPid;
} MIB_TCPROW_OWNER_PID, *PMIB_TCPROW_OWNER_PID;typedef struct {
DWORD dwNumEntries;
MIB_TCPROW_OWNER_PID table[TABLE_SIZE];
} MIB_TCPTABLE_OWNER_PID, *PMIB_TCPTABLE_OWNER_PID;typedef enum
{
TCP_TABLE_BASIC_LISTENER,
TCP_TABLE_BASIC_CONNECTIONS,
TCP_TABLE_BASIC_ALL,
TCP_TABLE_OWNER_PID_LISTENER,
TCP_TABLE_OWNER_PID_CONNECTIONS,
TCP_TABLE_OWNER_PID_ALL,
TCP_TABLE_OWNER_MODULE_LISTENER,
TCP_TABLE_OWNER_MODULE_CONNECTIONS,
TCP_TABLE_OWNER_MODULE_ALL
}TCP_TABLE_CLASS, *PTCP_TABLE_CLASS;
typedef DWORD (*PGetExtendedTcpTable)(
PVOID pTcpTable,
PDWORD pdwSize,
BOOL bOrder,
ULONG ulAf,
TCP_TABLE_CLASS TableClass,
ULONG Reserved
);//main函数:
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0; MIB_TCPROW_OWNER_PID tableTCP;
WSADATA WSAData;
HINSTANCE hLibrary = LoadLibrary("Iphlpapi.dll");
PGetExtendedTcpTable pFuncGetTCPTable;
pFuncGetTCPTable = (PGetExtendedTcpTable)::GetProcAddress(hLibrary, "GetExtendedTcpTable");
WSAStartup(MAKEWORD(1, 1), &WSAData );
DWORD dwSize;
pFuncGetTCPTable(&tableTCP, &dwSize, TRUE, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0); //函数调用 return nRetCode;
}
但是在调试的时候,每次走到函数调用(也就是pFuncGetTCPTable(&tableTCP, &dwSize, TRUE, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0); )的时候都会中断,提示信息如下:
Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.这个问题捆饶我好几天了,恳请个为帮忙. 任何建议都欢迎!
#define TABLE_SIZE 1024typedef struct {
DWORD dwState;
DWORD dwLocalAddr;
DWORD dwLocalPort;
DWORD dwRemoteAddr;
DWORD dwRemotePort;
DWORD dwOwningPid;
} MIB_TCPROW_OWNER_PID, *PMIB_TCPROW_OWNER_PID;typedef struct {
DWORD dwNumEntries;
MIB_TCPROW_OWNER_PID table[TABLE_SIZE];
} MIB_TCPTABLE_OWNER_PID, *PMIB_TCPTABLE_OWNER_PID;typedef enum
{
TCP_TABLE_BASIC_LISTENER,
TCP_TABLE_BASIC_CONNECTIONS,
TCP_TABLE_BASIC_ALL,
TCP_TABLE_OWNER_PID_LISTENER,
TCP_TABLE_OWNER_PID_CONNECTIONS,
TCP_TABLE_OWNER_PID_ALL,
TCP_TABLE_OWNER_MODULE_LISTENER,
TCP_TABLE_OWNER_MODULE_CONNECTIONS,
TCP_TABLE_OWNER_MODULE_ALL
}TCP_TABLE_CLASS, *PTCP_TABLE_CLASS;
typedef DWORD (*PGetExtendedTcpTable)(
PVOID pTcpTable,
PDWORD pdwSize,
BOOL bOrder,
ULONG ulAf,
TCP_TABLE_CLASS TableClass,
ULONG Reserved
);//main函数:
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0; MIB_TCPROW_OWNER_PID tableTCP;
WSADATA WSAData;
HINSTANCE hLibrary = LoadLibrary("Iphlpapi.dll");
PGetExtendedTcpTable pFuncGetTCPTable;
pFuncGetTCPTable = (PGetExtendedTcpTable)::GetProcAddress(hLibrary, "GetExtendedTcpTable");
WSAStartup(MAKEWORD(1, 1), &WSAData );
DWORD dwSize;
pFuncGetTCPTable(&tableTCP, &dwSize, TRUE, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0); //函数调用 return nRetCode;
}
但是在调试的时候,每次走到函数调用(也就是pFuncGetTCPTable(&tableTCP, &dwSize, TRUE, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0); )的时候都会中断,提示信息如下:
Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.这个问题捆饶我好几天了,恳请个为帮忙. 任何建议都欢迎!
我完全重现你的问题,整待解决了中似乎是MS的一个bug啊。因为MSDN说GetExtendedTcpTable声明在Iphlpapi.h中,但实际却找不到(已经是最近SDK了),但在.dll和.lib中都能找到。显然是MS的一个bug。迫不得己,才用动态加载的方式。但却运行错误。
现在怀疑MSDN中关于GetExtenedTcpTable函数的参数说明是否正确?
extern "C" DWORD __stdcall GetExtendedTcpTable(
PVOID pTcpTable,
PDWORD pdwSize,
ULONG bOrder,
ULONG ulAf,
ULONG TableClass,
ULONG Reserved
);关于C和C++函数声明方式的问题,可以去看http://blog.csdn.net/thomasliu83/archive/2006/03/08/618403.aspx
typedef DWORD (*PGetExtendedTcpTable)(
PVOID pTcpTable,
PDWORD pdwSize,
BOOL bOrder,
ULONG ulAf,
TCP_TABLE_CLASS TableClass,
ULONG Reserved
);
改为:
typedef DWORD (WINAPI*PGetExtendedTcpTable)(
PVOID pTcpTable,
PDWORD pdwSize,
BOOL bOrder,
ULONG ulAf,
TCP_TABLE_CLASS TableClass,
ULONG Reserved
);
调用dll中的函数要特别小心这里
而c/c++默认的调用方式为__cdecl,意思是由主调函数清栈(主函数_tmain会完成调用函数的清栈工作)。此时,你没有为函数GetExtendedTcpTable原型前加入WINAPI,c/c++编译器会加入清栈部分代码,而win32 API中的函数都是__stdcall调用方式,函数内部会完成清栈工作,这样,一次压栈对应了2次清栈,打破了堆栈的平衡,不出错才怪。如果你在函数GetExtendedTcpTable原型前加入WINAPI,则c/c++编译器知道该函数内部会自己清栈,所以编译后不会再在主函数_tmain中加入函数GetExtendedTcpTable的清栈代码,堆栈得到平衡,调用也就成功了。不知道这样说你明白了没有
而c/c++默认的调用方式为__cdecl,意思是由主调函数清栈(主函数_tmain会完成调用函数的清栈工作)。此时,你没有为函数GetExtendedTcpTable原型前加入WINAPI,c/c++编译器会加入清栈部分代码,而win32 API中的函数都是__stdcall调用方式,函数内部会完成清栈工作,这样,一次压栈对应了2次清栈,打破了堆栈的平衡,不出错才怪。如果你在函数GetExtendedTcpTable原型前加入WINAPI,则c/c++编译器知道该函数内部会自己清栈,所以编译后不会再在主函数_tmain中加入函数GetExtendedTcpTable的清栈代码,堆栈得到平衡,调用也就成功了。不知道这样说你明白了没有