2011-04-19 3 views
2

다른 프로젝트에서 사용하기 위해 C/C++ 코드를 수신했습니다. DLL에 넣은 다음 C++ 테스트 장치에서 DLL을 호출했습니다. 코드가 함수 호출 일 때부터 결과가 일치했습니다.C++ 콘솔에서 호출 된 C++ DLL C# 콘솔에서 호출 된 응용 프로그램 스택 오버플로가 있습니다.

그러나 C# 응용 프로그램에서 작동하도록 DLL을 가져 오려고했습니다. 테스트 하네스를 변환하고 DLL 호출을 만들었지 만 스택 오버플로 예외를받습니다.

는 C++에서 저는 추가 :

#include "proxy_rec_02.h" 
#pragma comment(lib,"proxy_rec_02.lib") 

그리고이 같은 기능이라고 :

proxy_rec_main(simtime,mx$gl,mz$gl,ry,start_dig,blytarg_on,blytarg,spread_on,last_call,outputs); 

헤더가 포함 : C#에서 내가 사용

void DLL_EXPORT proxy_rec_main(double simtime, double mx$gl, double mz$gl, double ry, int start_dig, 
           int blytarg_on, double blytarg, int spread_on, int last_call, double *outputs); 

을 :

using System.Runtime.InteropServices; 
이 같은 함수 호출로
[DllImport("proxy_rec_02.dll")] 
unsafe static extern void proxy_rec_main(double simtime, double mxSgl, double mzSgl, double ry, int start_dig,   
            int blytarg_on, double blytarg, int spread_on, int last_call, ref double[] outputs); 

6,

: DLL 함수가 for 루프에서 여러 번 호출

proxy_rec_main(simtime,mxSgl,mzSgl,ry,start_dig,blytarg_on,blytarg,spread_on,last_call,ref outputs); 

. C++ 코드는 잘 실행됩니다. C# 코드에서 스택 오버플로 오류가 발생합니다. proxy_rec_main 함수에 디버그 statemaints를 추가하고 함수가 반환되기 전에 각 명령문에 충돌하는 것으로 보입니다. 하지만 그것은 함수에서 반환에서 오류를 던질 것으로 보인다. 모든 통찰력이 환영받을 것입니다.

감사합니다.

답변

1

ref 배열이 문제가있는 것 같습니다. [MarshalAs]를 추가하고 이중 배열이 아닌 IntPtr을 전달하십시오.

.net 배열은 C++ 에서처럼 포인터가 아닙니다.

C# 메서드를 private로 표시하고Marshal.Copy를 사용하는 public 메서드로 래핑하여 .net 배열에 반환 된 포인터를 전송합니다.

.NET 할당시 배열을 전달

예 : C# 1 측면 배열을 할당

[DllImport(EntryPoint="ExternalMethod"] 
private static void ExternalMethodInvoke(
    [MarshalAs(UnmanagedType.SysInt), Out] out IntPtr); 

[DllImport(EntryPoint="ExternalDeleteArray"] 
private static void ExternalDeleteArrayInvoke(
    [MarshalAs(UnmanagedType.SysInt), Out] out IntPtr); 

public void ManagedWrapper(ref double[] array) 
{ 
    IntPtr unmanagedMem; 
    ExternalMethodInvoke(out unmanagedMem); // use try finally for freeing 
    Marshal.Copy(unmanagedMem, array, 1, 1000); 
    ExternalDeleteArrayInvoke(unmanagedMem); 
} 

경우, 할당 및 할당 해제하는 것을 잊지 않는 :

[DllImport(EntryPoint="ExternalMethod"] 
private static void ExternalMethodInvoke(
    [MarshalAs(UnmanagedType.SysInt), In] IntPtr); 

public void ManagedWrapper(ref double[] array) 
{ 
    IntPtr unmanagedMem = Marshal.AllocHGlobal(1000); 
    Marshal.Copy(array, unmanagedMem, 0, 1000); 
    ExternalMethodInvoke(unmanagedMem); // use try finally for freeing 
    Marshal.Copy(unmanagedMem, array, 1, 1000); 
    Marshal.FreeHGlobal(unmanagedMem); 
} 

예 원시 할당 때 어레이를 전송 C#. (마샬의 (de) 할당 전역 메서드 사용)

C++에서 할당을 해제하려면 C++ 메서드를 호출하십시오.

+0

'IntPtr'을 원하셨습니까? –

+0

지독한 자동 수정 :-) –

+0

이러한 변경 방법은 잘 모르겠습니다. 배열을 관리되지 않는 배열로 정렬하고 IntPtr을 가져 왔습니다. 하지만 그것을 가져갈 인터페이스를 변경하는 방법을 잘 모르겠습니다. –

2

[DllImport] 선언에 CallingConvention 속성이 없습니다. C 선언에 __stdcall을 사용한다는 신호가 없으므로 CallingConvention.Cdecl이 필요할 수 있습니다. 이것은 실제로 SO를 일으킬 수 있으며, 스택이 정리되지 않습니다.

Debug + Windows + 호출 전후의 ESP 레지스터 값을 등록하고 관찰합니다. 동일해야합니다.PInvokeStackImbalance 관리 디버거 경고를 비활성화 한 경우 반드시 다시 켜야합니다. 이 경고를 무시하는 것은 좋은 생각이 아닙니다.

네이티브 코드를 디버그하고 전달 된 인수 값을 확인하십시오. 그 중 하나에 대한 하나의 나쁜 선언이 발을 쏠만큼 충분하다는 주장이 너무 많습니다.

+0

이것은 대개 클래스 멤버 메서드에 대한 문제입니다. –

0

접착제 코드가 맞다고 가정하면 DLL 함수가 많은 스택을 차지할 수 있습니다. 나는 비슷한 상황에 처하게되었고, C++ 스택에 할당 된 매우 큰 객체가 있음이 판명되었습니다. 네이티브 코드에서 호출 할 때 호출 전에 사용 된 비트 스택 만 있으므로 스택에 충분한 공간이 남아있었습니다. 관리 코드에서 호출 된 경우 많은 스택이 이미 소비되어 충분한 공간이 남아 있지 않습니다. 오버플로를 일으키는 C++ 함수를 살펴보면 스택에 큰 객체를 넣으려고하는 것을 볼 수 있습니다.

관련 문제