网站开发验收模板营销课程培训视频
1、查看动态库导出哪些函数
1.1、在 Windows 和 Linux 上,可以使用不同的方法来查看动态库(.dll 或 .so)导出的函数
Windows:使用 dumpbin:Windows 提供了 dumpbin 工具(Visual Studio 自带),可以用于查看 .dll 导出的符号。
方法 1:使用 dumpbin
- 打开 x64/x86 Native Tools Command Prompt(VS 命令行工具)。
- 运行以下命令:
dumpbin /EXPORTS your_library.dll
- 会看到类似下面的输出:
Dump of file your_library.dllSection contains the following exports:00000000 characteristics12345678 time date stamp0.00 version1 ordinal base10 number of functions10 number of namesordinal hint RVA name1 0 1234ABCD FunctionA2 1 5678DCBA FunctionB
- 其中FunctionA 和 FunctionB 就是导出的函数。
- 可以看到如下例子:
E:\SteamTest\SteamSDK - 副本\SteamLogon\bin\Release>dumpbin /exports sdologinsdk.dll
- 输出:
E:\SteamTest\SteamSDK - 副本\SteamLogon\bin\Release>dumpbin /exports sdologinsdk.dll
Microsoft (R) COFF/PE Dumper Version 14.29.30151.0
Copyright (C) Microsoft Corporation. All rights reserved.Dump of file sdologinsdk.dllFile Type: DLLSection contains the following exports for sdologinsdk.dll00000000 characteristics67C7E536 time date stamp Wed Mar 5 13:46:30 20250.00 version7 ordinal base20 number of functions5 number of namesordinal hint RVA name21 0 0000C320 DoLogin = _DoLogin23 1 0000C630 GetAgreementStatus = _GetAgreementStatus24 2 0000C4B0 GetLoginedCompanyId = _GetLoginedCompanyId25 3 0000C5A0 OpenActivityWindow = _OpenActivityWindow26 4 0000C4F0 SetGameClientType = _SetGameClientType7 0000C240 [NONAME] _GhomeInitialize8 0000C280 [NONAME] _GhomeShowLoginDialog9 0000C2B0 [NONAME] _GhomeCloseLoginDialog10 0000C5D0 [NONAME] _GhomeDoPrivacyAgreement11 0000C680 [NONAME] _GhomeDoInit12 0000C260 [NONAME] _GhomeSetOwnerWindow13 0000C4C0 [NONAME] _GhomeSetLoginDialogState14 0000C480 [NONAME] _GhomeOpenWindow15 0000C300 [NONAME] _GhomeLogout16 0000C370 [NONAME] _GhomeGetTicket17 0000C6E0 [NONAME] _GhomeSetLoginArea18 0000C700 [NONAME] _GhomeGetLoinAreaList19 0000C350 [NONAME] _GhomeSetLoginMode20 0000C2D0 [NONAME] _GhomeMoveLoginDialog22 0000C340 [NONAME] _GHomeTerminalSummary8000 .data2F000 .rdata14000 .reloc1000 .rsrcF4000 .text1000 .tlsE:\SteamTest\SteamSDK - 副本\SteamLogon\bin\Release>dumpbin /exports sdologinsdk.dll
Microsoft (R) COFF/PE Dumper Version 14.29.30151.0
Copyright (C) Microsoft Corporation. All rights reserved.Dump of file sdologinsdk.dllFile Type: DLLSection contains the following exports for sdologinsdk64.dll00000000 characteristics67C7E588 time date stamp Wed Mar 5 13:47:52 20250.00 version1 ordinal base20 number of functions20 number of namesordinal hint RVA name1 0 0000C320 DoLogin = _DoLogin2 1 0000C340 GHomeTerminal = _GHomeTerminal3 2 0000C630 GetAgreementStatus = _GetAgreementStatus4 3 0000C4B0 GetLoginedCompanyId = _GetLoginedCompanyId5 4 0000C2B0 GhomeCloseLoginDialog = _GhomeCloseLoginDialog6 5 0000C680 GhomeDoInit = _GhomeDoInit7 6 0000C5D0 GhomeDoPrivacyAgreement = _GhomeDoPrivacyAgreement8 7 0000C700 GhomeGetLoinAreaList = _GhomeGetLoinAreaList9 8 0000C370 GhomeGetTicket = _GhomeGetTicket10 9 0000C240 GhomeInitialize = _GhomeInitialize11 A 0000C300 GhomeLogout = _GhomeLogout12 B 0000C2D0 GhomeMoveLoginDialog = _GhomeMoveLoginDialog13 C 0000C480 GhomeOpenWindow = _GhomeOpenWindow14 D 0000C6E0 GhomeSetLoginArea = _GhomeSetLoginArea15 E 0000C4C0 GhomeSetLoginDialogState = _GhomeSetLoginDialogState16 F 0000C350 GhomeSetLoginMode = _GhomeSetLoginMode17 10 0000C260 GhomeSetOwnerWindow = _GhomeSetOwnerWindow18 11 0000C280 GhomeShowLoginDialog = _GhomeShowLoginDialog19 12 0000C5A0 OpenActivityWindow = _OpenActivityWindow20 13 0000C4F0 SetGameClientType = _SetGameClientTypeSummary8000 .data2F000 .rdata14000 .reloc1000 .rsrcF4000 .text1000 .tlsE:\SteamTest\SteamSDK - 副本\SteamLogon\bin\Release>dumpbin /exports sdologinsdk.dll
Microsoft (R) COFF/PE Dumper Version 14.29.30151.0
Copyright (C) Microsoft Corporation. All rights reserved.Dump of file sdologinsdk.dllFile Type: DLLSection contains the following exports for sdologinsdk64.dll00000000 characteristics67C7EA7E time date stamp Wed Mar 5 14:09:02 20250.00 version1 ordinal base20 number of functions20 number of namesordinal hint RVA name1 0 0000C1F0 DoLogin = _DoLogin2 1 0000C210 GHomeTerminal = _GHomeTerminal3 2 0000C500 GetAgreementStatus = _GetAgreementStatus4 3 0000C380 GetLoginedCompanyId = _GetLoginedCompanyId5 4 0000C180 GhomeCloseLoginDialog = _GhomeCloseLoginDialog6 5 0000C550 GhomeDoInit = _GhomeDoInit7 6 0000C4A0 GhomeDoPrivacyAgreement = _GhomeDoPrivacyAgreement8 7 0000C5D0 GhomeGetLoinAreaList = _GhomeGetLoinAreaList9 8 0000C240 GhomeGetTicket = _GhomeGetTicket10 9 0000C110 GhomeInitialize = _GhomeInitialize11 A 0000C1D0 GhomeLogout = _GhomeLogout12 B 0000C1A0 GhomeMoveLoginDialog = _GhomeMoveLoginDialog13 C 0000C350 GhomeOpenWindow = _GhomeOpenWindow14 D 0000C5B0 GhomeSetLoginArea = _GhomeSetLoginArea15 E 0000C390 GhomeSetLoginDialogState = _GhomeSetLoginDialogState16 F 0000C220 GhomeSetLoginMode = _GhomeSetLoginMode17 10 0000C130 GhomeSetOwnerWindow = _GhomeSetOwnerWindow18 11 0000C150 GhomeShowLoginDialog = _GhomeShowLoginDialog19 12 0000C470 OpenActivityWindow = _OpenActivityWindow20 13 0000C3C0 SetGameClientType = _SetGameClientType
- Ghome.h:
#ifndef GHOME_H
#define GHOME_H#include <windows.h>
#include <ObjBase.h>#ifdef GHOME_EXPORTS
#define GHOME_API __declspec(dllexport)
#else
#define GHOME_API __declspec(dllimport)
#endif#ifdef __cplusplus
extern "C" {
#endif#pragma pack(push,1)// ======================== 错误码定义 ========================
#define SDOL_ERRORCODE_OK 0
#define SDOL_ERRORCODE_FAILED -1
#define SDOL_ERRORCODE_UNEXCEPT -100
#define SDOL_ERRORCODE_LOGINCANCEL -101
#define SDOL_ERRORCODE_INVALIDPARAM -102
#define SDOL_ERRORCODE_INVALIDBUFFER -103
#define SDOL_ERRORCODE_GETTICKET_TIMEOUT -104
#define SDOL_ERRORCODE_NOT_SUPPORT -105 // ======================== 登录模式 ========================
#define NormalLoginMode 0
#define LauncherLoginMode 1
#define AttachToLoginMode 2// ======================== 更新动作 ========================
#define UPDATE_ACTION_DOWNLOAD 1
#define UPDATE_ACTION_SETUP 2// ======================== 结构体定义 ========================typedef struct GhomeLAppInfo {DWORD Size; // = sizeof(GhomeLAppInfo)int AppID; // 盛趣统一游戏IDLPCWSTR AppName; // 游戏名称LPCWSTR AppVer; // 游戏版本int AreaId; // 游戏区ID (注意:不可用时传-1)int GroupId; // 游戏组ID (注意:不可用时传-1)} GhomeLAppInfo;typedef struct SDOLLoginResult{DWORD Size; // sizeof(SDOLLoginResult),为以后扩充提供可能LPCWSTR SessionId; // 用于后台验证的token串LPCWSTR Sndaid; // 用户IDLPCWSTR IdentityState; // 是否成年标识,0未成年,1成年LPCWSTR Appendix; // 附加字段,保留}GhomeSDOLLoginResult;typedef struct GhomeLoginAreaMsg {LPCWSTR Userid;LPCWSTR Area;LPCWSTR Group;} GhomeLoginAreaMsg;// ======================== 回调函数类型 ========================typedef int (__cdecl *LPSDOLLOGINCALLBACKPROC)(int nErrorCode, const SDOLLoginResult* pLoginResult, int nUserData, int nReserved);typedef BOOL (__cdecl *LPPRIVATEAGREEMENTCALLBACKPROC)(int nErrorCode, const char* call_condition);typedef BOOL (__cdecl *LPGINITCALLBACKPROC)(int nErrorCode);typedef BOOL (__cdecl *LPGGETLOGINAREALISTCALLBACKPROC)(int nErrorCode, const char* json_msg);// ======================== DLL 导出函数 ========================GHOME_API int __cdecl GhomeSetOwnerWindow(HWND hWnd);GHOME_API int __cdecl GhomeShowLoginDialog(LPSDOLLOGINCALLBACKPROC fnCallback, int nUserData, int nReserved);GHOME_API int __cdecl GhomeCloseLoginDialog(void);GHOME_API int __cdecl GhomeMoveLoginDialog(int x, int y);GHOME_API int __cdecl GhomeLogout(void);GHOME_API int __cdecl GhomeSetLoginMode(int nLoginMode);GHOME_API int __cdecl GhomeGetTicket(BSTR* bstrTicket);GHOME_API int __cdecl GhomeOpenWindow(LPCWSTR pwcsWinType, LPCWSTR pwcsWinName, LPCWSTR pwcsSrc, int nLeft, int nTop, int nWidth, int nHeight, LPCWSTR pwcsMode);GHOME_API int __cdecl GetLoginedCompanyId(void);GHOME_API int __cdecl GhomeSetLoginDialogState(int nState);GHOME_API int __cdecl SetGameClientType(LPCWSTR szGameClientType);GHOME_API int __cdecl OpenActivityWindow(LPCWSTR pwcsWinType, LPCWSTR pwcsWinName, LPCWSTR pwcsSrc, int nLeft, int nTop, int nWidth, int nHeight, LPCWSTR pwcsMode);GHOME_API int __cdecl GhomeDoPrivacyAgreement(const char* appId, LPPRIVATEAGREEMENTCALLBACKPROC fnCallback);GHOME_API int __cdecl GhomeInitialize(const GhomeLAppInfo* pAppInfo);GHOME_API int __cdecl GhomeDoInit(const char* appId, LPGINITCALLBACKPROC fnCallback);GHOME_API int __cdecl GHomeTerminal();GHOME_API int __cdecl GhomeSetLoginArea(const GhomeLoginAreaMsg* loginArea);GHOME_API int __cdecl GhomeGetLoinAreaList(LPGGETLOGINAREALISTCALLBACKPROC fnCallback);#pragma pack(pop)#ifdef __cplusplus
}
#endif#endif // GHOME_H
- Ghome.cpp
#define GHOME_EXPORTS
#include "Ghome.h"
#include "stdafx.h"
#include <comutil.h>#include "SDOLInfo.h"
#include "GPlusManager.h"
#include "ModuleLoginSDK.h"
#include "IGMessageFilter.h"// ======================== 主要导出函数 ========================// 初始化
extern "C" GHOME_API int __cdecl GhomeInitialize(const GhomeLAppInfo* pAppInfo)
{return ModuleLoginSDK::GetInstance()->SdoInitialize(*pAppInfo) ? SDOL_ERRORCODE_OK : SDOL_ERRORCODE_FAILED;
}// 设置主窗口
extern "C" GHOME_API int __cdecl GhomeSetOwnerWindow(HWND hWnd)
{return ModuleLoginSDK::GetInstance()->SetOwnerWindow(hWnd) ? SDOL_ERRORCODE_OK : SDOL_ERRORCODE_FAILED;
}// 显示登录窗口
extern "C" GHOME_API int __cdecl GhomeShowLoginDialog(LPSDOLLOGINCALLBACKPROC fnCallback, int nUserData, int nReserved)
{return ModuleLoginSDK::GetInstance()->ShowLoginDialog(fnCallback, nUserData, nReserved) ? SDOL_ERRORCODE_OK : SDOL_ERRORCODE_FAILED;
}// 关闭登录窗口
extern "C" GHOME_API int __cdecl GhomeCloseLoginDialog(void)
{return ModuleLoginSDK::GetInstance()->CloseLoginDialog() ? SDOL_ERRORCODE_OK : SDOL_ERRORCODE_FAILED;
}// 移动登录窗口
extern "C" GHOME_API int __cdecl GhomeMoveLoginDialog(int x, int y)
{return ModuleLoginSDK::GetInstance()->MoveLoginDialog(x, y) ? SDOL_ERRORCODE_OK : SDOL_ERRORCODE_FAILED;
}// 用户注销
extern "C" GHOME_API int __cdecl GhomeLogout(void)
{return ModuleLoginSDK::GetInstance()->Logout() ? SDOL_ERRORCODE_OK : SDOL_ERRORCODE_FAILED;
}// 终止销毁接口
extern "C" GHOME_API int __cdecl GHomeTerminal()
{return ModuleLoginSDK::Destroy() == ShutdownSuccess ? SDOL_ERRORCODE_OK : SDOL_ERRORCODE_FAILED;
}// 设置登录模式
extern "C" GHOME_API int __cdecl GhomeSetLoginMode(int nLoginMode)
{return ModuleLoginSDK::GetInstance()->SetLoginMode(nLoginMode) ? SDOL_ERRORCODE_OK : SDOL_ERRORCODE_FAILED;
}// 获取登录票据
extern "C" GHOME_API int __cdecl GhomeGetTicket(BSTR* bstrTicket)
{std::string strTicket;std::string strSndaId;if (!ModuleLoginSDK::GetInstance()->GetTicket(strTicket, strSndaId)){return SDOL_ERRORCODE_FAILED;}*bstrTicket = _com_util::ConvertStringToBSTR(strTicket.c_str());return SDOL_ERRORCODE_OK;
}// 打开窗口
extern "C" GHOME_API int __cdecl GhomeOpenWindow(LPCWSTR pwcsWinType, LPCWSTR pwcsWinName, LPCWSTR pwcsSrc, int nLeft, int nTop, int nWidth, int nHeight, LPCWSTR pwcsMode)
{return ModuleLoginSDK::GetInstance()->OpenWindow(pwcsWinType, pwcsWinName, pwcsSrc, nLeft, nTop, nWidth, nHeight, pwcsMode) == 0 ? SDOL_ERRORCODE_OK : SDOL_ERRORCODE_FAILED;
}// 获取已登录公司ID
extern "C" GHOME_API int __cdecl GetLoginedCompanyId(void)
{return ModuleLoginSDK::GetInstance()->GetLoginedCompanyId();
}// 设置登录窗口状态
extern "C" GHOME_API int __cdecl GhomeSetLoginDialogState(int nState)
{if (nState != 1 && nState != 2){return SDOL_ERRORCODE_FAILED;}return ModuleLoginSDK::GetInstance()->SetLoginDialogState(nState) ? SDOL_ERRORCODE_OK : SDOL_ERRORCODE_FAILED;
}// 设置游戏客户端类型
extern "C" GHOME_API int __cdecl SetGameClientType(LPCWSTR szGameClientType)
{if (szGameClientType == NULL){return SDOL_ERRORCODE_FAILED;}ModuleLoginSDK::GetInstance()->SetGameClientType(StringHelper::UnicodeToANSI(szGameClientType));return SDOL_ERRORCODE_OK;
}// 游戏内打开活动窗口
extern "C" GHOME_API int __cdecl OpenActivityWindow(LPCWSTR pwcsWinType, LPCWSTR pwcsWinName, LPCWSTR pwcsSrc, int nLeft, int nTop, int nWidth, int nHeight, LPCWSTR pwcsMode)
{return ModuleLoginSDK::GetInstance()->OpenActivityWindow(pwcsWinType, pwcsWinName, pwcsSrc, nLeft, nTop, nWidth, nHeight, pwcsMode) == 0 ? SDOL_ERRORCODE_OK : SDOL_ERRORCODE_FAILED;
}// 处理隐私协议
extern "C" GHOME_API int __cdecl GhomeDoPrivacyAgreement(const char* appId, LPPRIVATEAGREEMENTCALLBACKPROC fnCallback)
{return ModuleLoginSDK::GetInstance()->doPrivacyAgreement(appId, fnCallback) ? SDOL_ERRORCODE_OK : SDOL_ERRORCODE_FAILED;
}// 获取隐私协议状态
extern "C" GHOME_API int __cdecl GetAgreementStatus(const char* appId)
{return ModuleLoginSDK::GetInstance()->getAgreementStatus(appId) ? SDOL_ERRORCODE_OK : SDOL_ERRORCODE_FAILED;
}// 执行初始化
extern "C" GHOME_API int __cdecl GhomeDoInit(const char* appId, LPGINITCALLBACKPROC fnCallback)
{return ModuleLoginSDK::GetInstance()->initialize(appId, fnCallback) ? SDOL_ERRORCODE_OK : SDOL_ERRORCODE_FAILED;
}// 设置登录区服
extern "C" GHOME_API int __cdecl GhomeSetLoginArea(const GhomeLoginAreaMsg* loginArea)
{return ModuleLoginSDK::GetInstance()->SetLoginArea(loginArea) ? SDOL_ERRORCODE_OK : SDOL_ERRORCODE_FAILED;
}// 获取区服列表
extern "C" GHOME_API int __cdecl GhomeGetLoinAreaList(LPGGETLOGINAREALISTCALLBACKPROC fnCallback)
{return ModuleLoginSDK::GetInstance()->GetLoginArea(fnCallback) ? SDOL_ERRORCODE_OK : SDOL_ERRORCODE_FAILED;
}
- sdk.def
LIBRARY sdologinsdk
EXPORTSGhomeInitializeGhomeSetOwnerWindowGhomeShowLoginDialogGhomeCloseLoginDialogGhomeMoveLoginDialogGhomeLogoutGHomeTerminalGhomeSetLoginModeGhomeGetTicketGhomeOpenWindowGetLoginedCompanyIdGhomeSetLoginDialogStateSetGameClientTypeOpenActivityWindowGhomeDoPrivacyAgreementGetAgreementStatusGhomeDoInitGhomeSetLoginAreaGhomeGetLoinAreaList
- 是的,直接使用 .def 文件指定导出函数名称 是最干净、最推荐的方法之一!🎯
- 📌 这样做的好处:
-
避免了调用约定 (__cdecl vs __stdcall) 影响导出名称:
- __stdcall 默认会在导出名称后加 @参数字节数,__cdecl 会前面加 _。
- .def 文件直接指定 你想要的导出名称,不管编译器怎么修饰符号,它都会按照 .def 里的导出名称使用。
-
导出名称更清晰,调用方容易匹配:
- 你用 dumpbin /exports sdologinsdk.dll 看到的导出名称就是 .def 里指定的,保证不会有 _ 或 @ 这种额外修饰。
-
兼容不同的调用约定:
- 即使某些函数是 __stdcall,某些是 __cdecl,都不会影响导出名称,调用者无需关心函数的调用约定。
-
- Linux/macOS:使用 nm 和 objdump:Linux 和 macOS 使用 nm 或 objdump 来查看 .so 共享库的导出符号。
- 方法 1:使用 nm:
nm -D your_library.so
- 输出示例:
0000000000001234 T exported_function
0000000000005678 T another_exported_function
- 带 T 标记的符号就是导出的函数。
2、Windows 调用约定(Calling Convention)导致的符号修饰(Name Mangling)
- 在 Windows 平台,调用约定(Calling Convention)决定了:
- 函数参数如何传递(寄存器还是栈)。
- 栈由谁来清理(调用者还是被调用者)。
- 编译器如何修饰(Mangle)函数名称。
2.1、 常见调用约定及其符号修饰
- Windows 下常见的调用约定有:
2.2、调用约定导致的符号修饰
在 Windows 下,导出的 C 语言函数名称会经过 符号修饰(Name Mangling),不同调用约定会导致不同的符号格式。
-
1️⃣ __cdecl(默认 C/C++ 约定):
-
规则:
- 参数从右到左压入栈。
- 调用者清理堆栈。
- 符号修饰:前面加 _ 。
-
示例:
extern "C" __cdecl int MyFunction(int a, int b);
编译后(dumpbin /exports):
- _MyFunction
注意: __cdecl 没有参数字节数,因为它由调用者清理堆栈,编译器不需要记录参数大小。
-
2️⃣ __stdcall(Windows API 默认,CALLBACK):
- 规则:
- 参数从右到左压入栈。
- 被调用者清理堆栈。
- 符号修饰:前面加 _,后面加 @参数字节数。
- 规则:
-
示例:
extern "C" __stdcall int MyFunction(int a, int b);
- 编译后(dumpbin /exports):
? _MyFunction@8
-
因为 int 类型参数各占 4 字节,所以 @8 代表 2 * 4 = 8 字节。
-
3️⃣ __fastcall(寄存器优化):
-
规则:
- 前两个参数放 ECX 和 EDX,其余从右到左入栈。
- 被调用者清理堆栈。
- 符号修饰:前面加 @,后面加 @参数字节数。
-
示例:
extern "C" __fastcall int MyFunction(int a, int b);
- 编译后(dumpbin /exports):
@MyFunction@8
- 4️⃣ __vectorcall(用于 SIMD 寄存器优化):
- 规则:
- 优先使用 SIMD/寄存器
- 被调用者清理堆栈
- 符号修饰:前面加 ?,后面加 @参数字节数
- 示例:
extern "C" __vectorcall int MyFunction(int a, int b);
- 编译后(dumpbin /exports):
MyFunction@@16
- 5️⃣ __thiscall(C++ 类成员函数默认调用约定):
- 规则
- this 指针通过 ECX 传递
- 其他参数从右到左入栈
- 被调用者清理堆栈
- 符号修饰:C++ 方式(如 _MethodName@8)
- 示例:
class MyClass {
public:int __thiscall MyMethod(int a, int b);
};
- 编译后(dumpbin /exports):
MyMethod@MyClass@8
- 如果 不是 extern “C”,C++ 还会加上类名。
2.3. 为什么 _GHomeTerminal 会多 _ 或 @16
- 如果 GHomeTerminal 使用 __cdecl,应该导出:
_GHomeTerminal
- 如果 GHomeTerminal 使用 __stdcall,会变成:
_GHomeTerminal@0
-
(因为没有参数,所以 @0)。
-
如果你的 dumpbin /exports 看到 _GHomeTerminal,但期望 GHomeTerminal:
-
你使用了 __cdecl,但 dllimport/dllexport 期望 __stdcall。
-
你应该 明确使用 __stdcall 或者 .def 文件控制导出名称。
2.4、解决导出名称问题
- ✅ 方法 1:在 .def 文件里指定名称:
- 在 sdologinsdk.def 里指定:
LIBRARY sdologinsdk
EXPORTSGHomeTerminal
-
这样不管调用约定是什么,导出的函数都会是 GHomeTerminal。
-
方法 2:确保 __cdecl 和 __stdcall 一致:
extern "C" __stdcall int GHomeTerminal();
-
如果你的代码用的是 __stdcall,但 dumpbin 里是 _GHomeTerminal,说明 dllimport/dllexport 期望的是 __stdcall。
-
✅ 方法 3:如果必须用 __cdecl,在 .def 里强制去掉 _:
- 如果 dumpbin /exports 里看到 _GHomeTerminal,但你想让导出的名称是 GHomeTerminal,可以在 .def 里这样写:
EXPORTSGHomeTerminal=_GHomeTerminal
- 这样 dll 里存的是 _GHomeTerminal,但外部调用者只看到 GHomeTerminal。