CButton是怎么从mfc100u.dll导出的

lovestxu 2017-11-15 05:46:58
CButton是怎么从mfc100u.dll导出的
...全文
124 10 点赞 打赏 收藏 举报
写回复
10 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
qq_32690723 2020-08-26
引用 9 楼 lovestxu 的回复:
[quote=引用 8 楼 schlafenhamster 的回复:] MFC 可以直接导出类。
你说的直接导出类是怎么导出的,不是使用 _declspec(dllexport) 或.def文件? [/quote] 请问这个问题最终解决了吗
  • 打赏
  • 举报
回复
lovestxu 2017-11-17
引用 8 楼 schlafenhamster 的回复:
MFC 可以直接导出类。
你说的直接导出类是怎么导出的,不是使用 _declspec(dllexport) 或.def文件?
  • 打赏
  • 举报
回复
赵4老师 2017-11-16
dll 导出函数名的那些事 关键字: VC++  DLL 导出函数  经常使用VC6的Dependency查看DLL导出函数的名字,会发现有DLL导出函数的名字有时大不相同,导致不同的原因大多是和编译DLL时候指定DLL导出函数的界定符有关系。 VC++支持两种语言:即C/C++,这也是造成DLL导出函数差异的根源 我们用VS2008新建个DLL工程,工程名为"TestDLL" 把默认的源文件后缀 .CPP改为.C(C文件) 输入测试代码如下: 01 int _stdcall MyFunction(int iVariant) 02 { 03 return 0; 04 } 为了导出上面这个函数,我们有以下几个方法: 1. 使用传统的模块定义文件 (.def) 新建一个 后缀为.def的文本文件(这里建一个TestDll.Def),文件内容为: LIBRARY TestDll EXPORTS MyFunction 在 Link 时指定输入依赖文件:/DEF:"TestDll.Def" 2. Visual C++ 提供的方便方法 在01行的int 前加入 __declspec(dllexport) 关键字 通过以上两种方法,我们就可以导出MyFunction函数。 我们用Dependency查看导出的函数: 第一种方法导出的函数为: MyFunction 第二种方法导出的函数为: _MyFunction@4 __stdcall会使导出函数名字前面加一个下划线,后面加一个@再加上参数的字节数,比如_MyFunction@4的参数(int iVariant)就是4个字节 __fastcall与 __stdcall类似,不过前面没有下划线,而是一个@,比如@MyFunction@4 __cdecl则是始函数名。 小结:如果要导出C文件中的函数,并且不让编译器改动函数名,用def文件导出函数。 下面我们来看一下C++文件 我们用VS2008新建个DLL工程,工程名为"TestDLL" 默认的源文件后缀为 .CPP (即C++文件)。 输入测试代码如下: 01 int _stdcall MyFunction(int iVariant) 02 { 03 return 0; 04 } 为了导出上面这个函数,我们有以下几个方法: 3. 使用传统的模块定义文件 (.def) 新建一个 后缀为.def的文本文件(这里建一个TestDll.Def),文件内容为: LIBRARY TestDll EXPORTS MyFunction 在 Link 时指定输入依赖文件:/DEF:"TestDll.Def" 4. Visual C++ 提供的方便方法 在01行的int 前加入 __declspec(dllexport) 关键字 通过以上两种方法,我们就可以导出MyFunction函数。 我们用Dependency查看导出的函数: 第一种方法导出的函数为: MyFunction 第二种方法导出的函数为: ?MyFunction@@YGHH@Z 可以看到 第二种方法得到的 导出函数名 并不是我们想要的,如果在exe中用显示方法(LoadLibrary、GetProcAddress)调用 MyFunction 肯定会失败。 但是用引入库(*.LIB)的方式调用,则编译器自动处理转换函数名,所以总是没有问题。 解决这个问题的方法是: 用VC 提供的预处理指示符 "#pragma" 来指定链接选项。 如下: #pragma comment(linker, "/EXPORT:MyFunction=?MyFunction@@YGHH@Z") 这时,就会发现导出的函数名字表中已经有了我们想要的MyFunction。但我们发现原来的那个 ?MyFunction@@YGHH@Z 函数还在,这时就可以把 __declspec() 修饰去掉,只需要 pragma 指令即可。 而且还可以使如下形式: #pragma comment(linker, "/EXPORT:MyFunction=_MyFunction@4,PRIVATE") PRIVATE 的作用与其在 def 文件中的作用一样。更多的#pragram请查看MSDN。 小结:如果要导出C++文件中的函数,并且不让编译器改动函数名,用def文件导出函数。 同时可以用#pragma指令(C 中也可以用)。 总结: C++编译器在生成DLL时,会对导出的函数进行名字改编,并且不同的编译器使用的改编规则不一样,因此改编后的名字也是不同的(一般涉及到C++ 中的重载等)。 如果利用不同编译器分别生成DLL和访问DLL的exe程序,后者在访问该DLL的导出函数时就会出现问题。如上例中函数MyFunction在C++编译器改编后的名字是?MyFunction@@YGHH@Z。我们希望编译后的名字不发生改变,这里有几种方法。 第一种方法是通过一个称为模块定义文件DEF来解决。 LIBRARY TestDll EXPORTS MyFunction LIBRARY 用来指定动态链接库内部名称。该名称与生成的动态链接库名一定要匹配,这句代码不是必须的。 EXPORTS说明了DLL将要导出的函数,以及为这些导出函数指定的符号名。 第二种是定义导出函数时加上限定符:extern "C" 如:#define DLLEXPORT_API extern "C" _declspec(dllexport) 但extern "C"只解决了C和C++语方之间调用的问题(extern "C" 是告诉编译器,让它按C的方式编译),它只能用于导出全局函数这种情况 而不能导出一个类的成员函数。 同时如果导出函数的调用约定发生改变,即使使用extern "C",编译后的函数名还是会发生改变。例如上面我们加入_stdcall关键字说明调用约定(标准调用约定,也就是WINAPI调用约定)。 #define DLLEXPORT_API extern "C" _declspec(dllexport) 01 DLLEXPORT_API int _stdcall MyFunction(int iVariant) 02 { 03 return 0; 04 } 编译后函数名MyFunction改编成了_MyFunction@4 通过第一种方法模块定义文件的方式DLL编译后导出函数名不会发生改变。 DLL(动态库)导出函数名乱码含义 C++编译时函数名修饰约定规则: __stdcall调用约定: 1、以"?"标识函数名的开始,后跟函数名; 2、函数名后面以"@@YG"标识参数表的开始,后跟参数表; 3、参数表以代号表示: X--void D--char E--unsigned char F--short H--int I--unsigned int J--long K--unsigned long M--float N--double _N--bool .... PA--表示指针,后面的代号表明指针类型,如果相同类型的指针连续出现,以"0"代替,一个"0"代表一次重复; 4、参数表的第一项为该函数的返回值类型,其后依次为参数的数据类型,指针标识在其所指数据类型前; 5、参数表后以"@Z"标识整个名字的结束,如果该函数无参数,则以"Z"标识结束。 其格式为"?functionname@@YG*****@Z"或"?functionname@@YG*XZ",例如 int Test1(char *var1, unsigned long)-----"?Test1@@YGHPADK@Z" void Test2()-----"?Test2@@YGXXZ" __cdecl调用约定: 规则同上面的_stdcall调用约定,只是参数表的开始标识由上面的"@@YG"变为"@@YA"。 __fastcall调用约定: 规则同上面的_stdcall调用约定,只是参数表的开始标识由上面的"@@YG"变为"@@YI"。 如果要用DEF文件输出一个"C++"类,则把要输出的数据和成员的修饰名都写入.def模块定义文件 所以... 通过def文件来导出C++类是很麻烦的,并且这个修饰名是不可避免的
  • 打赏
  • 举报
回复
lovestxu 2017-11-16
引用 3 楼 oyljerry 的回复:
[quote=引用 2 楼 lovestxu 的回复:] [quote=引用 1 楼 oyljerry 的回复:] CButton类应该是在VC中有源码,只不过里面的一些API会用到mfc100u.dll中
很明显不是用的源码,不然不会在mfc100u.dll里构造了。[/quote] 那就是用的mfc扩展dll,导出类的方式[/quote] 使用dependency Walker查看mfc100u.dll看不到导出CButton类名信息,mfc100u.dll具体是怎么导出CButton类的。
  • 打赏
  • 举报
回复
smwhotjay 2017-11-16
afxwin.h 2904行
class CButton : public CWnd
{
	DECLARE_DYNAMIC(CButton)

// Constructors
public:
	CButton();
	virtual BOOL Create(LPCTSTR lpszCaption, DWORD dwStyle,
				const RECT& rect, CWnd* pParentWnd, UINT nID);

// Attributes
	UINT GetState() const;
	void SetState(BOOL bHighlight);
	int GetCheck() const;
	void SetCheck(int nCheck);
	UINT GetButtonStyle() const;
	void SetButtonStyle(UINT nStyle, BOOL bRedraw = TRUE);

	HICON SetIcon(HICON hIcon);
	HICON GetIcon() const;
	HBITMAP SetBitmap(HBITMAP hBitmap);
	HBITMAP GetBitmap() const;
	HCURSOR SetCursor(HCURSOR hCursor);
	HCURSOR GetCursor();

#if (_WIN32_WINNT >= 0x501)
	BOOL GetIdealSize(SIZE* psize);
	BOOL SetImageList(PBUTTON_IMAGELIST pbuttonImagelist);
	BOOL GetImageList(PBUTTON_IMAGELIST pbuttonImagelist);
	BOOL SetTextMargin(RECT* pmargin);
	BOOL GetTextMargin(RECT* pmargin);
#endif  // (_WIN32_WINNT >= 0x501)

// Overridables (for owner draw only)
	virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);

// Implementation
public:
	virtual ~CButton();
protected:
	virtual BOOL OnChildNotify(UINT, WPARAM, LPARAM, LRESULT*);
};
winctrl1.cpp CButton部分实现
/////////////////////////////////////////////////////////////////////////////
// CButton

BOOL CButton::Create(LPCTSTR lpszCaption, DWORD dwStyle,
		const RECT& rect, CWnd* pParentWnd, UINT nID)
{
	CWnd* pWnd = this;
	return pWnd->Create(_T("BUTTON"), lpszCaption, dwStyle, rect, pParentWnd, nID);
}

CButton::~CButton()
{
	DestroyWindow();
}

// Helper for radio buttons
int CWnd::GetCheckedRadioButton(int nIDFirstButton, int nIDLastButton)
{
	for (int nID = nIDFirstButton; nID <= nIDLastButton; nID++)
	{
		if (IsDlgButtonChecked(nID))
			return nID; // id that matched
	}
	return 0; // invalid ID
}

// Derived class is responsible for implementing all of these handlers
//   for owner/self draw controls
void CButton::DrawItem(LPDRAWITEMSTRUCT)
{
	ASSERT(FALSE);
}

BOOL CButton::OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam,
	LRESULT* pResult)
{
	if (message != WM_DRAWITEM)
		return CWnd::OnChildNotify(message, wParam, lParam, pResult);

	ASSERT(pResult == NULL);       // no return value expected
	UNUSED(pResult); // unused in release builds
	DrawItem((LPDRAWITEMSTRUCT)lParam);
	return TRUE;
}
afxwin2.inl CButton的内联实现

_AFXWIN_INLINE CButton::CButton()
	{ }
_AFXWIN_INLINE UINT CButton::GetState() const
	{ ASSERT(::IsWindow(m_hWnd)); return (UINT)::SendMessage(m_hWnd, BM_GETSTATE, 0, 0); }
_AFXWIN_INLINE void CButton::SetState(BOOL bHighlight)
	{ ::SendMessage(m_hWnd, BM_SETSTATE, bHighlight, 0); }
_AFXWIN_INLINE int CButton::GetCheck() const
	{ ASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd, BM_GETCHECK, 0, 0); }
_AFXWIN_INLINE void CButton::SetCheck(int nCheck)
	{ ASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, BM_SETCHECK, nCheck, 0); }
_AFXWIN_INLINE UINT CButton::GetButtonStyle() const
	{ ASSERT(::IsWindow(m_hWnd)); return (UINT)GetWindowLong(m_hWnd, GWL_STYLE) & 0xff; }
_AFXWIN_INLINE void CButton::SetButtonStyle(UINT nStyle, BOOL bRedraw)
	{ ASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, BM_SETSTYLE, nStyle, (LPARAM)bRedraw); }
// Win4
_AFXWIN_INLINE HICON CButton::SetIcon(HICON hIcon)
	{ ASSERT(::IsWindow(m_hWnd)); return (HICON)::SendMessage(m_hWnd, BM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon); }
_AFXWIN_INLINE HICON CButton::GetIcon() const
	{ ASSERT(::IsWindow(m_hWnd)); return (HICON)::SendMessage(m_hWnd, BM_GETIMAGE, IMAGE_ICON, 0L); }
_AFXWIN_INLINE HBITMAP CButton::SetBitmap(HBITMAP hBitmap)
	{ ASSERT(::IsWindow(m_hWnd)); return (HBITMAP)::SendMessage(m_hWnd, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hBitmap); }
_AFXWIN_INLINE HBITMAP CButton::GetBitmap() const
	{ ASSERT(::IsWindow(m_hWnd)); return (HBITMAP)::SendMessage(m_hWnd, BM_GETIMAGE, IMAGE_BITMAP, 0L); }
_AFXWIN_INLINE HCURSOR CButton::SetCursor(HCURSOR hCursor)
	{ ASSERT(::IsWindow(m_hWnd)); return (HCURSOR)::SendMessage(m_hWnd, BM_SETIMAGE, IMAGE_CURSOR, (LPARAM)hCursor); }
_AFXWIN_INLINE HCURSOR CButton::GetCursor()
	{ ASSERT(::IsWindow(m_hWnd)); return (HCURSOR)::SendMessage(m_hWnd, BM_GETIMAGE, IMAGE_CURSOR, 0L); }
  • 打赏
  • 举报
回复
oyljerry 2017-11-16
引用 2 楼 lovestxu 的回复:
[quote=引用 1 楼 oyljerry 的回复:] CButton类应该是在VC中有源码,只不过里面的一些API会用到mfc100u.dll中
很明显不是用的源码,不然不会在mfc100u.dll里构造了。[/quote] 那就是用的mfc扩展dll,导出类的方式
  • 打赏
  • 举报
回复
lovestxu 2017-11-16
引用 1 楼 oyljerry 的回复:
CButton类应该是在VC中有源码,只不过里面的一些API会用到mfc100u.dll中


很明显不是用的源码,不然不会在mfc100u.dll里构造了。
  • 打赏
  • 举报
回复
oyljerry 2017-11-16
CButton类应该是在VC中有源码,只不过里面的一些API会用到mfc100u.dll中
  • 打赏
  • 举报
回复
schlafenhamster 2017-11-16
MFC 可以直接导出类。
  • 打赏
  • 举报
回复
lovestxu 2017-11-16
mfc100u.dll 不像是通过 _declspec(dllexport) 这种方式导出类的。 到像是通过def文件来导出C++类,所以用Dependency 看到的类的函数都是匿名的, 可是mfc100u.dll导出了很多类的,不可能都是写到def文件吧
  • 打赏
  • 举报
回复
相关推荐
发帖
VC/MFC
加入

1.5w+

社区成员

VC/MFC相关问题讨论
申请成为版主
帖子事件
创建了帖子
2017-11-15 05:46
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……