문제

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 플랫폼을 모두 타겟팅하는 경우 특히 까다 롭습니다.


두 가지 솔루션

  1. 정의 파일을 사용하십시오. 그러나 이것은 DEF 파일의 상태를 유지해야합니다.

  2. 가장 간단한 방법 : 매크로 정의 (참조 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

더 큰 질문은 왜 그렇게하고 싶습니까? 엉망인 이름에 무슨 문제가 있습니까?

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top