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;
}
링커가 이름에 밑줄 및 / 또는 숫자 (바이트 수?)를 추가하지 않도록하려고합니다.
나는 지원하지 않는으로 OK예요 dllimport
과 dllexport
같은 헤더를 사용. C ++ 클래스 메서드를 내보내는 데 대한 정보가 아니라 C 스타일 전역 함수 만 필요합니다.
최신 정보
호출 규칙을 포함하지 않고를 사용 extern "C"
하면 원하는대로 내보내기 이름이 제공되지만 그게 무슨 뜻입니까? 어떤 기본 호출 규칙이 내가 어떤 pinvoke (.NET), 선언 (vb6)을 얻고 있으며 GetProcAddress
예상합니까? ( GetProcAddress
호출자가 만든 함수 포인터에 따라 달라질 것입니다).
이 DLL이 헤더 파일없이 사용되기를 원하기 때문에 #defines
호출자가 헤더를 사용할 수 있도록 만드는 데는 많은 공상이 필요하지 않습니다 .
*.def
파일 을 사용해야한다는 대답은 괜찮습니다 .
답변
일반 C 내보내기를 원하면 C ++가 아닌 C 프로젝트를 사용하십시오. C ++ DLL은 모든 C ++ ism (네임 스페이스 등)에 대해 이름 변경에 의존합니다. C / C ++-> Advanced 아래의 프로젝트 설정으로 이동하여 코드를 C로 컴파일 할 수 있습니다. 컴파일러 스위치 / TP 및 / TC에 해당하는 “Compile As”옵션이 있습니다.
여전히 C ++를 사용하여 lib의 내부를 작성하고 싶지만 일부 함수를 C ++ 외부에서 사용하기 위해 얽 히지 않은 상태로 내보내려면 아래 두 번째 섹션을 참조하십시오.
VC ++에서 DLL 라이브러리 내보내기 / 가져 오기
정말로 원하는 것은 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 또는 Python / R의 FFI 등)에서 가져 오기 위해 필요한 경우 다음을 사용할 수 있습니다. extern "C"
dllexport와 함께 인라인을 하여 C ++ 컴파일러에 이름을 조작하지 않도록 지시 할 수 있습니다. 그리고 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())
);
}
다음은 Dumpbin / exports를 사용한 내보내기의 모습입니다.
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, 호출 규칙을 변경) 또한 이름을 장식하므로 둘 다 사용하면 다음을 얻을 수 있습니다.
extern "C" __declspec(dllexport) int WINAPI Test(void) --> dumpbin : _Test@0
extern "C"
기호가 장식되어 있기 때문에 의 이점 이 손실됩니다 (_ @bytes 포함).
참고이는 것을 단지 때문에 x86 아키텍처 발생
__stdcall
대회가 64 무시됩니다 ( MSDN : 가능하면 규칙에 의해 64 아키텍처에 인수 레지스터에 전달하고, 이후의 인수는 스택에 전달됩니다 .).
x86 및 x64 플랫폼을 모두 대상으로하는 경우 특히 까다 롭습니다.
두 가지 솔루션
-
정의 파일을 사용하십시오. 그러나 이렇게하면 def 파일의 상태를 유지해야합니다.
-
가장 간단한 방법 : 매크로 정의 ( msdn 참조 ) :
#define EXPORT 주석 (링커, “/ EXPORT :”__FUNCTION__ “=”__FUNCDNAME__)
그런 다음 함수 본문에 다음 pragma를 포함합니다.
#pragma EXPORT
전체 예 :
int WINAPI Test(void)
{
#pragma EXPORT
return 1;
}
이렇게하면 x86에 대한 __stdcall
규칙을 유지하면서 x86 및 x64 대상 모두에 대해 데코 레이팅되지 않은 함수를 내 보냅니다 . 가 __declspec(dllexport)
되지 않는 이 경우이 필요합니다.
답변
나는 정확히 같은 문제가 있었는데, 내 해결책은 __declspec(dllexport)
내보내기를 정의하는 대신 모듈 정의 파일 (.def)을 사용하는 것이 었습니다 ( http://msdn.microsoft.com/en-us/library/d91k01sh.aspx ). 왜 이것이 작동하는지 모르겠지만 작동합니다.
답변
_naked가 원하는 것을 얻을 수 있다고 생각하지만 컴파일러가 함수에 대한 스택 관리 코드를 생성하지 못하게합니다. extern “C”는 C 스타일 이름 장식을 발생시킵니다. 그것을 제거하면 _가 제거됩니다. 링커는 밑줄을 추가하지 않으며 컴파일러는 추가합니다. stdcall은 인수 스택 크기가 추가되도록합니다.
자세한 내용은 다음을 참조하십시오.
http://en.wikipedia.org/wiki/X86_calling_conventions
http://www.codeproject.com/KB/cpp/calling_conventions_demystified.aspx
더 큰 질문은 왜 그렇게 하시겠습니까? 이름이 엉망이 된 게 뭐가 문제 야?