为什么dll中的导出函数,在调用它的程序中无法导入,奇怪在dll中的导出函数有的正常,有的不正常,我都检查得快要疯了,都没办法,请高手

bphantom 2003-10-04 03:27:49
dll是一个键盘钩子,我想让dll和调用它的程序发消息通信或通过导出函数传字符。
hodll.h如下:
LRESULT __declspec(dllexport) __stdcall CALLBACK KeyboardProc(
int nCode,
WPARAM wParam,
LPARAM lParam);


BOOL __declspec(dllexport) __stdcall installhook();//此函数正常
BOOL __declspec(dllexport)__stdcall UnHook();//不正常
extern "C" _declspec(dllexport) char *sendstr();//不正常

class CHodllApp : public CWinApp
{
public:
BOOL ExitInstance ();
CHodllApp();
BOOL InitInstance ();

// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CHodllApp)
//}}AFX_VIRTUAL

//{{AFX_MSG(CHodllApp)
// NOTE - the ClassWizard will add and remove member functions here.
// DO NOT EDIT what you see in these blocks of generated code !
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};

//hodll.cpp如下:

#pragma data_seg(".SHARDAT")
static HHOOK hkb=NULL;
#pragma data_seg()
HINSTANCE hins;

char szBuf[256];
char *p;
CString msg;
CString strMsg;

#define MAX_LEN 2

//#define WM_MY_MESSAGE (WM_USER+100)
////////////////////////////////////////////////
BEGIN_MESSAGE_MAP(CHodllApp, CWinApp)
END_MESSAGE_MAP()
//////////////////////////////////////////////////////////////////////////

LRESULT __declspec(dllexport)__stdcall CALLBACK KeyboardProc(int nCode,WPARAM wParam,LPARAM lParam)
{

if(((DWORD)lParam&0x40000000) && (HC_ACTION==nCode))
{
switch(wParam)
{

case 'R':
/*DWORD result;
SendMessageTimeout(HWND_BROADCAST, // 目标窗口
WM_MY_MESSAGE, // 消息
0, // WPARAM
0, // LPARAM
SMTO_ABORTIFHUNG |
SMTO_NORMAL,
TIMEOUT_INTERVAL,
&result);*/
//PostMessage(hAim,WM_MY_MESSAGE,NULL,NULL);
//AfxMessageBox("send r msg");
strMsg="r";
break;
case 'S':
//PostMessage(hAim,WM_MY_MESSAGE,NULL,NULL);
strMsg="s";
break;
case 'T':
//PostMessage(hAim,WM_MY_MESSAGE,NULL,NULL);
strMsg="t";
break;
case 'U':
//PostMessage(hAim,WM_MY_MESSAGE,NULL,NULL);
strMsg="u";
break;
case 'V':
//PostMessage(hAim,WM_MY_MESSAGE,NULL,NULL);
strMsg="v";
break;
case 'W':
//PostMessage(hAim,WM_MY_MESSAGE,NULL,NULL);
strMsg="w";
break;
case 'X':
//PostMessage(hAim,WM_MY_MESSAGE,NULL,NULL);
strMsg="x";
break;
case 'Y':
//PostMessage(hAim,WM_MY_MESSAGE,NULL,NULL);
strMsg="y";
break;
default:
break;
}


}

LRESULT RetVal = CallNextHookEx( hkb, nCode, wParam, lParam );
return RetVal;
}

BOOL __declspec(dllexport)__stdcall installhook()
{

hkb=SetWindowsHookEx(WH_KEYBOARD,(HOOKPROC)KeyboardProc,hins,0);
return TRUE;
}
extern "C" _declspec(dllexport) char *sendstr()
{

static char string[MAX_LEN];
strncpy(string,strMsg,sizeof(string)-1);
string[sizeof(string)-1]='\0';
return string;

}

BOOL __declspec(dllexport)__stdcall UnHook()
{

BOOL unhooked = UnhookWindowsHookEx(hkb);
return unhooked;
}

BOOL CHodllApp::InitInstance ()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
hins=AfxGetInstanceHandle();

GetModuleFileName(AfxGetInstanceHandle( ),szBuf,sizeof(szBuf));
p = szBuf;
while(strchr(p,'\\'))
{
p = strchr(p,'\\');
p++;
}
*p = '\0';
msg=szBuf;
return TRUE;
}
BOOL CHodllApp::ExitInstance ()
{
return TRUE;
}
CHodllApp::CHodllApp()
{
}
CHodllApp theApp;

//////////////////////////////
在调用它的程序中如果是静态调用,则出现函数UnHook();sendstr();,而installhook则正常。
在动态调用中,如下:
static HINSTANCE hinstDLL;
typedef BOOL (CALLBACK *inshook)();
inshook instkbhook;

typedef char* (*dsendstr)();
dsendstr lsendstr;

typedef BOOL (*dunhook)();
dunhook lunhook;

if(hinstDLL=LoadLibrary((LPCTSTR)"hodll.dll"))
{
lsendstr=(dsendstr)GetProcAddress(hinstDLL, "sendstr");
//lsendstr调试时为空
lunhook=(dunhook)GetProcAddress(hinstDLL, "UnHook");
//lunhook调试时为空
instkbhook=(inshook)GetProcAddress
(hinstDLL, "installhook");
//instkbhook调试时不为空,正常。
instkbhook();
}

为什么这样呢?我已经是晕了,找不出原因。高手指点指点了。
...全文
63 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
lop5712 2003-10-06
  • 打赏
  • 举报
回复
回去帮你看了一下,静态连接时失败的原因应该是你的函数声明时错误,即在.exe端,也应该有相同的函数原型
LRESULT __stdcall CALLBACK KeyboardProc(
int nCode,
WPARAM wParam,
LPARAM lParam);


BOOL __stdcall installhook();//此函数正常
BOOL __stdcall UnHook();//不正常
extern "C" char *sendstr();//不正常
可能楼主将里面的__stdcall或extern "C"等去掉了
__stdcall这种调用规则也是必须的,之所以这样是因为VC是以C++语言规则进行编译的,由于函数重载的原因,所以以C++语言规则编译时生成的函数名将会被编译器改为内部名称以适应重载函数的需求。其内部命名的规则也考察了调用规则(__stdcall、__cdecl和__fastcall),所以调用规则不同将会导致其内部名称不同,所以静态时连接找不到函数名。

动态时楼主的代码错误就多了,首先是每个typedef后都没写明函数调用规则(第一个写了CALLBACK),这样当后面使用相应的函数指针时将可能会发生错误(参数、返回值传递不正确)。其次CALLBACK就是__stdcall,不应该重复定义(虽然没什么问题)。最后因为函数名已经被变为内部名称,所以不应该再使用原来的名称,VC下的内部名称以上面的声明所生成的内部函数名如下:
extern "C" char *sendstr(); -> sendstr
BOOL __stdcall installhook(); -> ?installhook@@YGHXZ
BOOL __stdcall UnHook(); -> ?UnHook@@YGHXZ
因此,对于动态调用,代码应改为如下:
static HINSTANCE hinstDLL;
typedef BOOL (CALLBACK *inshook)();
inshook instkbhook;

typedef char* ( __stdcall *dsendstr)();
dsendstr lsendstr;

typedef BOOL ( __stdcall *dunhook)();
dunhook lunhook;

if(hinstDLL=LoadLibrary((LPCTSTR)"adf.dll"))
{
lsendstr=(dsendstr)GetProcAddress(hinstDLL, "sendstr");
//lsendstr调试时为空
lunhook=(dunhook)GetProcAddress(hinstDLL, "?UnHook@@YGHXZ");
//lunhook调试时为空
instkbhook=(inshook)GetProcAddress
(hinstDLL, "?installhook@@YGHXZ");
//instkbhook调试时不为空,正常。
instkbhook();
}
如果觉得不爽(要使用内部名称),则在声明函数时在前面加上extern "C"以要求编译器以C语言规则编译,将不会改变函数名,不过不能导出重载函数了。

另外的,楼主的
#pragma data_seg(".SHARDAT")
static HHOOK hkb=NULL;
#pragma data_seg()
想必是想声明一个用于共享的节(SHARe DATa),但上面的声明将会产生read、write的节,没有shared属性,将不能共享,应改为
#pragma section( ".SHARDAT", read, write, shared )
__declspec( allocate( ".SHARDAT" ) ) static HHOOK hkb = NULL;
lop5712 2003-10-06
  • 打赏
  • 举报
回复
我暂时还没有看出原因,回去帮你看一下,不过你这里有个错误,虽然我觉得和这无关

#pragma data_seg(".SHARDAT")
static HHOOK hkb=NULL;
#pragma data_seg()

你的hkb将不会放在.SHARDAT中,因为data_seg间的变量必须是初始化了的变量,但VC文档中专门记录了一条,被赋值为非零的变量才算初始化了的数据,否则是未初始化数据,放在.bss节中,应改为

#pragma bss_seg(".SHARDAT")
static HHOOK hkb=NULL;
#pragma bss_seg()
bphantom 2003-10-05
  • 打赏
  • 举报
回复
up
Gelim 2003-10-04
  • 打赏
  • 举报
回复
up
lsl7909 2003-10-04
  • 打赏
  • 举报
回复
UP,关注中!
bphantom 2003-10-04
  • 打赏
  • 举报
回复
在调用它的程序中如果是静态调用,则出现函数UnHook();sendstr()不能定位之类的错误;,

15,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 进程/线程/DLL
社区管理员
  • 进程/线程/DLL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧