2011-01-21 7 views
3

관리되지 않는 Visual C++에서 DLL을 작성했으며 C# 및 C++ 응용 프로그램 모두에서 작동하도록 약간의 문제가 있습니다. 다음은 C++ DLL의 프로토 타입 모습입니다 같은 :관리 코드에서 관리되지 않는 DLL 함수 호출 오류

extern "C" __declspec(dllexport) int WINAPI ZBNConnect(UCHAR dev, LPARAM hWnd, ZBCallbackFn rfn, ZBCallbackFn nfn, int DevType, byte * DevAddr, ZBCallbackFn dfn); 

내 C# 응용 프로그램 함수, 아무 문제에 연결할 수 있지만,이 예외가 발생하는 함수를 호출 할 때 :

catch (Exception e) { /* ... */ } 

을 e.Message = "개체 참조가 개체의 인스턴스로 설정되지 않았습니다."

이상하게도 DLL의 프로토 타입에서 WINAPI을 가져 와서 다시 컴파일하면 C# 응용 프로그램이 아무 문제없이이 함수를 호출합니다. 불행하게도, WINAPI은 그 기능이 C++ 애플리케이션에서 정의되는 방법이기 때문에 남아 있어야합니다.

public delegate int ZBNConnectDelegate(uint dev, IntPtr hWnd, USBCallbackDelegate rfn, NotifyCallbackDelegate nfn, uint DevType, byte[] DevAddr, ZBdebugCallbackDelegate dfn); 
public ZBNConnectDelegate ZBNConnect; 

procName = "ZBNConnect"; 
fUintPtr = Kernel32.GetProcAddress(dllHandle, procName); 

if (fUintPtr == UIntPtr.Zero) 
{ 
    throw new ArgumentException(procName); 
} 

fIntPtr = unchecked((IntPtr)(long)(ulong)fUintPtr); 
ZBNConnect = (ZBNConnectDelegate)Marshal.GetDelegateForFunctionPointer(fIntPtr, typeof(ZBNConnectDelegate)); 

가 어떻게이 작업을 얻을 수있는 C# 응용 프로그램을 수정할 수 있습니다

기능

는 현재이 같은 C# 응용 프로그램에서 프로토 타입? 감사.

편집 : 추가 정보

은 정적 링크 ([DllImport...])가있는 하드웨어가 시스템에 장착 된 하드웨어가 런타임에로드를 지원하는 다른 DLL을 부착 따라 때문에 옵션이 아닙니다. 두 DLL은 모두 동일한 API 호출을 사용합니다.

+1

이 –

+0

당신이 프로토 타입에 통근을 넣어 시도해 봤어 완전히 다르다 DLL 지옥이 아니다? – bratao

+1

그럼, 어떻게'ZBNConnect'를 초기화하고 관리되지 않는 함수를 가리 키도록할까요? 서면으로, 그것은'null'이 될 것입니다. 왜 P/Invoke ('[DllImport] static extern')를 사용하지 않으시겠습니까? –

답변

0

WINAPI을 함수 선언 및 정의에 추가하면 DLL의 함수 이름이 맹 글링되는 것으로 나타났습니다. 안타깝게도 이미 배포 된 응용 프로그램과의 호환성을 유지하려면 WINAPI이 필요합니다. 수정은 링커에 추가 수출을 추가했다 :

#pragma comment(linker, "/EXPORT:[email protected]") 
3

기본적으로 잘못된 것이 있습니다. 함수가 콜백 인 것처럼 델리게이트를 선언했습니다. 콜백처럼 보이지는 않지만 [DllImport]로 선언해야하는 것과 같습니다. 당신이했던 것처럼 작동하도록하려면 LoadLibrary와 GetProcAddress()를 pinvoke해야합니다. 후드 아래 [DllImport]는 무엇을합니다. 나는 당신이 그것을 사용하는 것을 보지 못합니다.

+0

안녕 한스. OP에 몇 가지 추가 정보를 추가했습니다. –

+0

그래, 실제로 GetProcAddress를 사용한다. 음, 관리되지 않는 코드가 널 포인터로 코를 잠수하고 있습니다. 많은 수의 후보가 있으며 함수 인수는 모두 포인터입니다. 디버깅해야합니다. 관리되지 않는 코드를 디버깅하는 방법을 이미 알고 있다고 생각합니다. –

+0

나는 DLL을 밟아 보려고하지 않았지만'fIntPtr'와'ZBNConnect'가 관리 코드를 통해 단계를 밟을 때 NULL이 아닌 값이 할당됩니다. –

0

WINAPI 매크로는 호출 규칙을 변경합니다.

네이티브 전화를 걸 때

[UnmanagedFunctionPointer(CallingConvention = CallingConvention.StdCall] 
public delegate Int32 ZBNConnectDelegate(Byte dev, IntPtr hWnd, USBCallbackDelegate rfn, NotifyCallbackDelegate nfn, Int32 DevType, Byte[] DevAddr, ZBdebugCallbackDelegate dfn); 
0

extern "C" __declspec(dllexport) int WINAPI ZBNConnect(UCHAR dev, LPARAM hWnd, ZBCallbackFn rfn, ZBCallbackFn nfn, int DevType, byte * DevAddr, ZBCallbackFn dfn);

public delegate int ZBNConnectDelegate(uint dev, IntPtr hWnd, USBCallbackDelegate rfn, NotifyCallbackDelegate nfn, uint DevType, byte[] DevAddr, ZBdebugCallbackDelegate dfn);

C++ UCHARs (DEV) 당신은 스택을 4 부수고있어하는 1 바이트 값과 C#의 UINT 년대 있습니다 시도 , 그리고 무엇인가의 이유로, WINAPI는 당신이 그것을 버리도록 내버려두고 있습니다. 또한 일반적인 P/Invoke DllImport 대신 위임을 사용하면 문제가 발생할 가능성이 높습니다. 마샬링 된 방법을 사용자 지정할 수 없기 때문입니다. 당신은 C#을 측면에서 런타임에 올바른 DLL을 감지 할 수있는 경우

+1

기계 단어보다 작은 값 인수는 스택에 놓을 때 넓어집니다. –

+0

흠, 왜 WINAPI가 작동하는지 설명 하긴하지만, 100 % 보장받을 수 있다고 확신하지는 않습니다. 좋은 지적. –

0

, 나는이 같이 DllImport의 declaractions 사용합니다 :

[DllImport("Dll1.dll", CallingConvention = CallingConvention.StdCall, EntryPoint = "ZBNConnect")] 
extern static int ZBNConnect1(...) 
[DllImport("Dll2.dll", CallingConvention = CallingConvention.StdCall, EntryPoint = "ZBNConnect")] 
extern static int ZBNConnect2(...) 

public static int ZBNConnect(...) 
{ 
    if (UseDll1) 
     return ZBNConnect1(...); 
    return ZBNConnect2(...); 
} 

P를/호출은 동적 로딩으로 넘겨진다. 절대로 ZBNConnect1을 호출하지 않으면 Dll1.dll이로드되지 않고 그 반대의 경우도 마찬가지입니다.

같이 DllImport에

추가의 EntryPoint = 업데이트되었습니다.

관련 문제