我先把一个dll文件从A文件夹复制到B文件夹,紧接着我打开B文件夹并调用dll里的函数,没有成功。可我如果从复制dll开始,一直到调用dll里的函数完毕,一步一步的执行,复制文件完毕后,调用dll里的函数却可以成功,这是什么原因?我以为可能是复制文件需要时间,直接执行可能是没有复制完毕就开始调用dll里的函数,为了防止这种情况,我在复制完毕后Sleep(10000),这次直接执行,却发现还是不行,所以不是时间的问题,那会是什么原因呢?我实在想不出来了,请各位帮我分析一下吧。
调试欢乐多
在应用程序创建一个快方式,此时运行能成功
将快捷方式移到工作目录(一般为.dsw,.cpp目录),再运行一下,不成功
如果是上面情况,原因就是目录问题
1、sdk程序。
2、网络程序,基于TCP/IP,下面所写程序段是服务器端程序
2、窗口过程大体如下:LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
case: WM_CREATE
AfxBeginThread()//程序执行开始就创建一新线程,新线程名为B
.....
}
UINT WINAPI B(..)//线程B
{
listen()//监听客户端连接
Accept()//接收连接,这里可能需要阻塞(或挂起)一段时间.
.......//判断是否有连接成功,如果连接成功,进入一个新线程C;
}UINT WINAPI C(..)//线程C
{
case MY_COMMAND//连接成功后,客户端立即向服务器发送MY_COMMAND命令
Function()//其中Function是dll内的函数。
}
问题就在Function()处,如果直接执行,程序不报错,但是Function()的功能根本没有执行。可是,如果你单步执行,执行完Function()这一条语句后,函数就能达到预期效果,这是一种情况。还有,如果把Function()放在主线程内(即窗口过程中),无论是不是单步执行,还是直接运行程序,都可以取得预期效果,这又是一种情况,还有一种情况,就是如果把Function()放在线程B内,也完全可以成功执行。所以,这样看来,只是在线程C内不能正确完成Function()的功能。这是什么意思呢?太奇怪了。值得注意的是,程序一开始运行后(即发出WM_CREATE消息后),线程A与线程B都执行了(从程序代码上可以看出来),而线程C却没有立即执行,因为线程B必须等待(阻塞或挂起)一段时间,等有了客户端的连接请求后,才有机会进入线程C,我觉得这里比较可疑,但却找不到充分的理由,也不知道怎么解决。请大家帮忙分析一下,感激!
我的Function()功能是开始一键盘钩子的函数,当然,这个开始键盘钩子的函数(Function,核心是SetWindowsHookEx),是在dll内的,我事先已经将dll的导出函数,头文件等这些常规操作完成了。而且放在主线程内确实可以开始一键盘钩子。怎么到了C内就不开始了呢?而且,也没有错误提示,提示操作成功完成。但就是Function()的功能没有显示出来(不能开始键盘记录)。我把B的线程代码写在下面:
UINT WINAPI AcceptThread(LPVOID lParam)
{ SOCKET socket;
SOCKET acceptSock;
CONNECTINFO connectInfo;
THREADINFO acceptThreadInfo;
SOCKADDR retAddr;
SOCKADDR_IN retInAddr;
WSAEVENT event[2]={0};
WSANETWORKEVENTS wederYes; if(!LSdcerCreateSocket(&socket,SOCK_STREAM))
{
return -1;
}
if(!LSdcerBindSocket(socket,hostaddress,hostPort))
{
return -1;
}
if(!LSdcerListenSocket(socket))
{
return -1;
} WSAEVENT workEvent=WSACreateEvent();
if(WSA_INVALID_EVENT==workEvent)
{
LSdcerCloseSocket(socket);
return -1;
} event[0]=hExitEvent;
event[1]=workEvent;
if(WSAEventSelect(socket,workEvent,FD_ACCEPT)==SOCKET_ERROR)
{
WSACloseEvent(workEvent);
LSdcerCloseSocket(socket);
return -1;
}
SetEvent(hPrepareEvent); for(;;)
{ DWORD whichEvent=WSAWaitForMultipleEvents(2,event,FALSE,WSA_INFINITE,FALSE);
if(whichEvent==WSA_WAIT_FAILED||whichEvent==WAIT_OBJECT_0)
{
WSACloseEvent(workEvent);
LSdcerCloseSocket(socket);
return -1;
}
int right=WSAEnumNetworkEvents(socket,workEvent,&wederYes);
if(right==SOCKET_ERROR)
{
WSACloseEvent(workEvent);
LSdcerCloseSocket(socket);
return -1;
}
if(wederYes.lNetworkEvents==FD_ACCEPT)
{
int sockaddrret=sizeof(retAddr);
acceptSock=WSAAccept(socket,&retAddr,&sockaddrret,0,0);
if(acceptSock==INVALID_SOCKET)
{
continue;
}
else
{
memcpy(&retInAddr,&retAddr,sizeof(SOCKADDR_IN));
strcpy(connectInfo.IP,inet_ntoa(retInAddr.sin_addr));
connectInfo.sock=acceptSock; hSendReceiveHandle=NewThreads(SendReceiveThread,&connectInfo,&SendReceiveID);
if(hSendReceiveHandle==0)
{
continue;
}
else
{
acceptThreadInfo.hThreadHandle =hSendReceiveHandle;
acceptThreadInfo.ThreadID=SendReceiveID;
EnterCriticalSection(&g_CriticalSection);
threadList.push_back(acceptThreadInfo);
LeaveCriticalSection(&g_CriticalSection);
}
}
}
}
return 0;
}
hSendReceiveHandle=NewThreads(SendReceiveThread,&connectInfo,&SendReceiveID);//为开始新线程C的语句。
下面我再把C线的代码写下来:
UINT WINAPI SendReceiveThread(LPVOID lParam)//线程C
{ CONNECTINFO *sockInfo=(CONNECTINFO*)lParam;
SOCKET s=sockInfo->sock;
WSAEVENT workEvent=WSACreateEvent();
if(workEvent==WSA_INVALID_EVENT)
{
return -1;
}
DWORD retLen;
NETCOMMAND comm;
memset(&comm,0,sizeof(NETCOMMAND));
if(!LSdcerRecvDataS(s,(char*)&comm,sizeof(NETCOMMAND),&retLen,workEvent,SNDRCVTIME_OUT))
{
WSACloseEvent(workEvent);
LSdcerCloseSocket(s);
DeleteThread(GetCurrentThreadId());
return 0;
}
switch(comm.commandID)
{
case WM_COMAND:
Function()/////在这里面调用dll的操作
break;...//结束本线程的操作。
}void Function()
{
//////调用dll内的函数(开始一键盘钩子),如果单步执行完这一步,完全可以实现我的功能,但只要是直接运行,不报错,功能没有。
}
改成显式Dll调用试试。
先定义函数指针:
typedef VOID (*MYPFUN)();
然后将
switch(comm.commandID)
{
case WM_COMAND:
Function()/////在这里面调用dll的操作
break;
改为
switch(comm.commandID)
{
case WM_COMAND:
{
HINSTANCE hinstLib;
hinstLib=LoadLibrary(yourpath+"\\b\\fuckyou.dll");
if (hinstLib == NULL)
{
AfxMessageBox("fuck you!!, the handle of the dll is invalid!!");
return;
}
ProcFun = (MYPFUN) GetProcAddress(hinstLib, "MyFun");
if (ProcFun == NULL)
{
AfxMessageBox("fuck you!!, the handle of the fun is invalid!!");
return;
}
ProcFun();//调 用你的函数。
FreeLibrary(hinstLib);
}
break;
你是sdk程序,反正我在sdk程序中用AfxBeginThread,编译都不能通过,因此请改用CreateThread来抛线程(记住CloseHandle),可能就OK了;
switch(comm.commandID)
{
case WM_COMAND:
{
HINSTANCE hinstLib;
hinstLib=LoadLibrary(yourpath+"\\b\\fuckyou.dll");
if (hinstLib == NULL)
{
AfxMessageBox("fuck you!!, the handle of the dll is invalid!!");
return;
}
ProcFun = (MYPFUN) GetProcAddress(hinstLib, "MyFun");
if (ProcFun == NULL)
{
AfxMessageBox("fuck you!!, the handle of the fun is invalid!!");
return;
}
ProcFun();//调 用你的函数。
Sleep(5000);//这条语句是我自己加的,我的函数竟然实现了其功能。看来是时间的问题,可是没道理呀?我的线程C中,调用ProcFun()后,会自动删除自己的线程(C线程句柄),可是这是在ProcFun()执行以后才删除的呀。难道是ProcFun()还没有执行完毕,其所在的线程就被删除了?有这种可能吗?好比是如下程序段:
f()
{ dllFunc();//调用库里的函数
deletethread//删除线程,虽然这一句是删除线程的语句,但是它是在dllFunc()后,有没有可能是直接运行的时候,dllFunc()没有执行完成就执行了deletethread(删除线程)的语句呢?这有可能吗?我觉得肯定是得先完成dllFunc()的操作后才执行deletethread呀?不是吗?怎么回事?
FreeLibrary(hinstLib);
break;
.......删除本线程句柄