2012-05-24 2 views
2

네이티브 (관리되지 않는) dll C 함수로 작업하려면 ICustomMarshaler를 구현하는 자체 마샬 러를 사용하고 있습니다.ICustomMarshaler :: MarshalNativeToManaged 네이티브 dll에서 올바른 데이터를 받으면 반환하는 개체가 "looses"

MarshalNativeToManaged 함수에서 dll 측에서 올 Y 른 결과가 표시됩니다. 문제는 MarshalNativeToManaged가 반환하는 개체가 "사용되지"않는다는 것입니다. (In, Out) param이있는 호출 함수의 객체는 변경되지 않습니다. C#: Object with custom marshaller not containing data after PInvoke call

간단한 클래스 :

[StructLayout(LayoutKind.Sequential)] 
    class CMA { 
     public int a; 
     char b; 
     public char get_b() { return b; } 
    } 
:

는 ("사용자 지정 마샬이 PInvoke를 호출 한 후 데이터를 포함하지 않는 객체를 C 번호"가와 previosly 여기서 논의 정확히 같은 문제 것 같습니다) 함수의

서명은 다음과 같습니다

어딘가에 내가 생처럼 전화를 주에서
[DllImport("first.dll", EntryPoint = "hack")] 
    public static extern int hack([In, Out, MarshalAs(UnmanagedType.CustomMarshaler, 
              MarshalTypeRef=typeof(ZMarshal))] CMA cma); 

s :

int retcode = hack(cma); 

MarshalNativeToManaged에서 dll 함수 호출로 올바른 결과가 표시됩니다.

public object MarshalNativeToManaged(IntPtr pNativeData) 
    { 
     // everything is fine with pNativeData; 
     // but let us even say I ignore it 
     // and return the object in the following way: 
     CMA cma = new CMA(); 
     cma.a = 999; 
     return cma; // this will be lost. I mean cma object in the main will not be changed 
    } 

내가 뭘 잘못하고 있니? 그냥 빨리 노트 : 내가하지 "주변에 다른 방법으로"하는 CustomMarshaler를 사용하여 처리하는 방법을 알고 싶어 :)

답변

1

C# 언어는 당신이 그것을 허용하는 밖으로 심판 또는 으로 인수를 선언해야합니다 새 값을 반환합니다. 수정 :

[DllImport("first.dll", EntryPoint = "hack")] 
public static extern int hack(
    [In, Out] 
    [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(ZMarshal))] 
    ref CMA cma); 
+0

도움을 주셔서 감사합니다. 이것은 이것을 처리하는 방법 중 하나입니다.나는 여기서 무슨 일이 벌어지는 지 알 것 같아. 나는 내 자신의 질문에 이미 대답했다. 언제 시간이 있다면 (그리고있는 경우) 좀 보시고 의견/수정 사항을 추가하십시오. – AlexZJP

+0

흠, 아니오, 전역 변수는 처리하지 않는 * 방법입니다. –

+0

전역 변수가 아니며 ZMarshal 클래스의 멤버 변수입니다. BTW 우리가 사용하는 마샬 러 클래스 자체의 인스턴스를 어떻게 제어 할 수 있습니까? – AlexZJP

1

좋아, 지금 무슨 일이 일어나고 있는지 알 것 같습니다.

트릭은 Object를 다루는 동안 실제로 포인터를 다루는 것입니다 (아무리 어려운 C#이 사실을 숨기려해도). 단계별로 단계별로 설명합니다. 1) 해킹 (CMA * pCMA); 2) MarshalManagedToNative (무효 * PCMA는) // C# 우리가 여기 해킹에 전달 된 포인터를 전달 3) 무효 * MarshalNativeToManaged (무효 * _some_PTR_to_memory_visible_to_managed_and_unmanaged_area) 그리고 여기가 .NET이 함수가이 무효의 *의 PTR로합니까 어떤 질문입니다 보고? ref를 사용하지 않으면 해킹에서 객체를 변경할 방법이 없습니다 (cma). 이 포인터는 어디에서도 사용되지 않습니다. 이 함수는 무효가 될 수있었습니다. 우리가 (CMA REF)이 해킹 같은 심판을 사용하면 MarshalNativeToManaged

public object MarshalNativeToManaged(IntPtr pNativeData) 
    { 

     // some code that deals with the pNativeData really 
     // but for our example only let us say we simply ignore what we just got 
     // from the unmanaged world and simply change our object 

     ((CMA)oo).a = 999; 
     return oo; // this will not be lost now :) 

에서

public class ZMarshal : System.Runtime.InteropServices.ICustomMarshaler 
{ 
    static ZMarshal static_instance; 
    object oo; 
    public IntPtr MarshalManagedToNative(object o) 
    { 
     if (!(o is CMA)) 
      throw new System.Runtime.InteropServices.MarshalDirectiveException("Blabala"); 
     oo = o; 

그리고 나중에; // 이전 답 감사 BTW 이 경우에는 해킹 (CMA ** pp)이며 .NET에서는 MarshalNativeToManaged * pp = oo에서 반환 한 포인터를 사용합니다.

최종선은 포인터를 유지하고 포인터가 가리키는 메모리 값을 변경하거나 (ref를 사용하여) 포인터에 포인터를 전달하고 포인터의 값을 변경해야합니다. 그 자체.

관련 문제