2012-06-11 1 views
3

이 C 함수를 가정한다.P/Invoke에서 고정 문자열에 대해 전달할 대상은 무엇입니까?</p> <pre><code>void do_something(const char* str) </code></pre> <p>그것은 어딘가에 <em>위한 문자열 나중에 저장</em> 참조 :

  • 내가해야합니까 :이 방법으로 문자열을 전달할 때 어떻게해야합니까 지금

    [DllImport("NativeLib")] 
    static extern void do_something(string str); 
    

    :

    는 또한,이 함수를 호출하는 C#에서이 서명을 문자열 (GCHandle.Alloc())을 고정 시키십시오 (또는 마샬 러가 사본을 작성하고 있습니까)?

  • 고정해야하는 경우 '원래'문자열 (즉, GCHandle.Alloc()에 전달 된 문자열)을 전달합니까? 또는 반환 값 GCHandle.AddrOfPinnedObject()을 전달해야합니까?
  • 이 경우 올바른 데이터 형식 (do_something)이 string입니까? 또는 대신 IntPtr을 사용해야합니까?
+0

"어딘가에 문자열을 저장합니다"라고 말하면 문자열의 사본을 만들거나 포인터를 저장한다는 의미입니까? 그것은 당신의 질문에 대한 답에 큰 차이를 만듭니다. 포인터를 저장하는 중이라면 GCHandle.Alloc()을 사용해야합니다. 마샬 러는 그렇지 않으면 TEMPORARY 복사본을 만듭니다. –

+0

포인트를 직접 저장합니다 (사본이 아님). –

+0

interop 시그니처의 문자열 매개 변수를'IntPtr' 또는'byte *'로 대체해야합니다. – CodesInChaos

답변

4

interop 경계를 통해 포인터를 저장하는 것은 정말 나쁜 아이디어입니다. 대신 C 코드를 수정하여 문자열의 복사본을 만들 수있는 모든 작업을 수행하십시오.

upvoted 대답에서 제안 된대로 문자열을 고정하지 않으면 pinvoke marshaller가 문자열을 char *로 변환하고 변환 된 문자열을 네이티브 호출 후에 포인터를 무효화해야합니다. 너 스스로 문자열을 마샬링해야한다. 인수를 IntPtr로 선언하고 Marshal.StringToHGlobalAnsi()를 사용하여 포인터 값을 만듭니다.

또는 Marshal.StringToCoTaskMemAnsi()를 사용하면 COM 힙에서 할당됩니다. 당신의 진짜 문제는 문자열을 풀어내는 훌륭한 시나리오가 아닙니다. C 코드는 할당 방법을 모르기 때문에 문자열을 해제 할 수 없습니다. C 코드가 포인터로 완료되는시기를 알 수 없기 때문에 C# 코드는 문자열을 해제 할 수 없습니다. 그래서 문자열을 복사하는 것이 중요합니다. 이 전화를 몇 번만하면 메모리 누출이 발생할 수 있습니다.

0

비 관리 코드가 문자열을 복사하는 대신 포인터를 저장한다는 점을 감안할 때 GCHandle.Alloc()을 사용하여 수동으로 문자열 복사본을 만들어 IntPtr로 전달하는 것이 좋습니다.

그러면 전달 된 메모리 블록의 수명을 관리 할 수 ​​있습니다. 메모리 블록이 완료되면 GCHandle을 통해 메모리 블록을 해제합니다.

+0

당신이 뭘 제안하는지 분명하지 않습니다. 'GCHandle.Alloc'으로 문자열을 고정시키고 싶습니까? 그건 나쁜 생각이야. – CodesInChaos

+0

죄송합니다. 답변이 불완전합니다. GCHandle.Alloc()을 사용하여 문자열에 대한 메모리를 얻은 다음 Marshal.AllocHGlobal()을 사용하여 전역 메모리를 할당하고 Marshal.Copy()를 사용하여 문자열을 복사합니다. 그러나 한스 (Hans)는 StringToHGlobalAnsi를 제안했다. –