dllexport를 사용하여 DLL에서 함수를 내보내십시오
-
22-08-2019 - |
문제
C ++ Windows DLL에서 함수를 내보내는 간단한 예를 원합니다.
헤더, CPP 파일 및 DEF 파일을보고 싶습니다 (절대적으로 필요한 경우).
내보내는 이름이 필요합니다 미색. 가장 표준 통화 컨벤션 (__stdcall?)을 사용하고 싶습니다. 나는 사용을 원한다 __declSpec (dllexport) DEF 파일을 사용할 필요가 없습니다.
예를 들어:
//header
extern "C"
{
__declspec(dllexport) int __stdcall foo(long bar);
}
//cpp
int __stdcall foo(long bar)
{
return 0;
}
나는 링커가 추가 된 밑줄 및/또는 숫자 (바이트 카운트?)를 이름에 피하려고 노력하고 있습니다.
동일한 헤더를 사용하여 dllimport 및 dllexport를 지원하지 않아도 괜찮습니다. C ++ 클래스 방법, C 스타일 글로벌 기능을 내보내는 것에 대한 정보를 원하지 않습니다.
업데이트
전화 규칙을 포함하지 않고 (및 외부 "C"를 사용하지 않음) 내가 좋아하는 수출 이름을 제공하지만 그 의미는 무엇입니까? 내가 Pinvoke (.NET), 선언 (vb6) 및 getProcaddress가 기대하는 기본 호출 컨벤션이 무엇이든? (getProcadDress의 경우 발신자가 만든 함수 포인터에 따라 다를 것입니다).
나는이 DLL이 헤더 파일없이 사용하기를 원하기 때문에 발신자가 헤더를 사용할 수 있도록 많은 멋진 #defines가 필요하지 않습니다.
나는 def 파일을 사용해야한다는 대답이 괜찮습니다.
해결책
일반 C 내보내기를 원한다면 C ++가 아닌 C 프로젝트를 사용하십시오. C ++ DLL은 모든 C ++ ISM (네임 스페이스 등)에 대한 이름 맨링에 의존합니다. C /C ++-> 고급 하의 프로젝트 설정으로 이동하여 코드를 C로 컴파일 할 수 있습니다. 컴파일러 스위치 /TP 및 /TC에 응답하는 "Compile"옵션이 있습니다.
VC ++에서 DLL LIBS 내보내기/가져 오기
당신이 정말로하고 싶은 것은 DLL 프로젝트의 모든 소스 파일에 포함될 헤더의 조건부 매크로를 정의하는 것입니다.
#ifdef LIBRARY_EXPORTS
# define LIBRARY_API __declspec(dllexport)
#else
# define LIBRARY_API __declspec(dllimport)
#endif
그런 다음 내보내고 싶은 함수에서 사용합니다. LIBRARY_API
:
LIBRARY_API int GetCoolInteger();
라이브러리 빌드 프로젝트에서 정의를 만듭니다 LIBRARY_EXPORTS
이로 인해 DLL 빌드에 대한 기능이 내보내게됩니다.
부터 LIBRARY_EXPORTS
DLL을 소비하는 프로젝트에서 정의되지 않으며, 해당 프로젝트에 라이브러리의 헤더 파일이 포함 된 경우 모든 기능이 대신 가져 오게됩니다.
라이브러리가 크로스 플랫폼이 되려면 Windows에 있지 않을 때 Library_api를 아무것도 정의 할 수 있습니다.
#ifdef _WIN32
# ifdef LIBRARY_EXPORTS
# define LIBRARY_API __declspec(dllexport)
# else
# define LIBRARY_API __declspec(dllimport)
# endif
#elif
# define LIBRARY_API
#endif
dllexport/dllimport를 사용하는 경우 DEF 파일을 사용할 필요가 없습니다. DEF 파일을 사용하면 dllexport/dllimport를 사용할 필요가 없습니다. 두 가지 방법은 동일한 작업을 다른 방식으로 달성합니다. Dllexport/Dllimport가 두 가지 중에서 권장되는 방법이라고 생각합니다.
loadlibrary/pinvoke에 대한 C ++ DLL에서 미지급 함수를 내보내기
loadlibrary 및 getProcaddress를 사용하거나 .NET에서 pinvoke를 사용하려면 이것이 필요하다면 사용할 수 있습니다. extern "C"
dllexport와 함께 인라인. 그리고 우리는 dllimport 대신 getProcaddress를 사용하고 있기 때문에 위에서 IFDEF 댄스를 할 필요가 없습니다. 간단한 dllexport입니다.
코드:
#define EXTERN_DLL_EXPORT extern "C" __declspec(dllexport)
EXTERN_DLL_EXPORT int getEngineVersion() {
return 1;
}
EXTERN_DLL_EXPORT void registerPlugin(Kernel &K) {
K.getGraphicsServer().addGraphicsDriver(
auto_ptr<GraphicsServer::GraphicsDriver>(new OpenGLGraphicsDriver())
);
}
그리고 여기에 덤프 빈 /내보내기로 수출이 어떻게 보이는지가 있습니다.
Dump of file opengl_plugin.dll
File Type: DLL
Section contains the following exports for opengl_plugin.dll
00000000 characteristics
49866068 time date stamp Sun Feb 01 19:54:32 2009
0.00 version
1 ordinal base
2 number of functions
2 number of names
ordinal hint RVA name
1 0 0001110E getEngineVersion = @ILT+265(_getEngineVersion)
2 1 00011028 registerPlugin = @ILT+35(_registerPlugin)
그래서이 코드는 잘 작동합니다.
m_hDLL = ::LoadLibrary(T"opengl_plugin.dll");
m_pfnGetEngineVersion = reinterpret_cast<fnGetEngineVersion *>(
::GetProcAddress(m_hDLL, "getEngineVersion")
);
m_pfnRegisterPlugin = reinterpret_cast<fnRegisterPlugin *>(
::GetProcAddress(m_hDLL, "registerPlugin")
);
다른 팁
C ++의 경우 :
방금 같은 문제에 직면했고 두 가지를 모두 사용할 때 문제가 발생한다고 언급 할 가치가 있다고 생각합니다. __stdcall
(또는 WINAPI
) 그리고 extern "C"
:
아시다시피 extern "C"
다음 대신 장식을 제거합니다.
__declspec(dllexport) int Test(void) --> dumpbin : ?Test@@YaHXZ
당신은 기호 이름을 얻지 못했습니다.
extern "C" __declspec(dllexport) int Test(void) --> dumpbin : Test
그러나, 그 _stdcall
(= 매크로 winapi, 호출 컨벤션을 변경하는 마크로 Winapi)는 또한 이름을 장식하여 우리가 모두 사용하면 다음을 얻습니다.
extern "C" __declspec(dllexport) int WINAPI Test(void) --> dumpbin : _Test@0
그리고의 이점 extern "C"
기호가 장식되어 있기 때문에 손실됩니다 (_ @bytes 포함)
이것에 주목하십시오 뿐 x86 아키텍처에 대해 발생합니다
__stdcall
X64에서 컨벤션이 무시됩니다 (MSDN : X64 아키텍처에서, 컨벤션에 의해, 가능하면 인수는 레지스터로 전달되며, 후속 인수는 스택에 전달됩니다..).
X86 및 X64 플랫폼을 모두 타겟팅하는 경우 특히 까다 롭습니다.
두 가지 솔루션
정의 파일을 사용하십시오. 그러나 이것은 DEF 파일의 상태를 유지해야합니다.
가장 간단한 방법 : 매크로 정의 (참조 MSDN) :
#define 내보내기 주석 (링커, "/내보내기 :"__function__ "="__funcdname__)
그런 다음 기능 본문에 다음 Pragma를 포함시킵니다.
#pragma EXPORT
Full Example :
int WINAPI Test(void)
{
#pragma EXPORT
return 1;
}
이것은 x86 및 x64 대상 모두에 대해 미개화 된 기능을 보존하면서 보존합니다. __stdcall
X86에 대한 협약. 그만큼 __declspec(dllexport)
아니다 이 경우에 필요합니다.
정확히 같은 문제가 있었는데 내 솔루션은 모듈 정의 파일 (.def)을 사용하는 것이 었습니다. __declspec(dllexport)
수출을 정의하려면 (http://msdn.microsoft.com/en-us/library/d91k01sh.aspx). 왜 이것이 작동하는지 모르겠지만
_naked는 원하는 것을 얻을 수 있다고 생각하지만 컴파일러가 기능의 스택 관리 코드를 생성하는 것을 방지합니다. 외부 "C"는 C 스타일 이름 장식을 일으 킵니다. 그것을 제거하면 _을 제거해야합니다. 링커는 밑줄을 추가하지 않습니다. 컴파일러는 컴파일러가합니다. STDCALL은 인수 스택 크기를 추가합니다.
자세한 내용은 다음을 참조하십시오.http://en.wikipedia.org/wiki/x86_calling_conventions http://www.codeproject.com/kb/cpp/calling_conventions_demystified.aspx
더 큰 질문은 왜 그렇게하고 싶습니까? 엉망인 이름에 무슨 문제가 있습니까?