2011-09-12 4 views
1

저는 C# 응용 프로그램을 작성 중이며 효율성을 높이기 위해 C++에 있어야합니다. C++의 기능은 다음과 같이 내 보낸 :배열이 C# 가상 머신에 의해 쓰기 금지되어 있습니다.

extern "C" __declspec(dllexport) int fastSegment(char*, int, int);

나는 다음과 같이 C#에서이 기능을 가져옵니다

내가 처리 할 이미지는 다음과 같이이라고
[DllImport(_dllname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] 
static private extern bool fastSegment(byte[] img, int width, int height); 

:

fastSegment(image, 640, 480); 

image은 올바른 크기입니다. 메모리를 낭비하고 새로운 배열을 할당하고 싶지 않기 때문에 배열을 C++ 함수에서 직접 수정했습니다.

어떻게됩니까? 죽음의 블루 스크린. 전에 Windows 7에서 본 적이 없었습니다.

내 기능은 테스트 목적으로 image[0], image[1]image[2]에만 기록했습니다.이 기능을 제거하면 모든 것이 정상입니다.

내 생각 엔 가상 머신이 메모리를 보호하지만 가상 머신이 단순히 예외를 throw하지 않는다는 것이 이상하다는 것을 알았습니다. 해당 버퍼의 보호를 해제 할 수있는 방법이 있습니까? 아니면 새 버퍼를 할당해야합니까?

편집 :

데이터를 쓸 때 프로그램이 실행됩니다. 이 갑작스런 충돌의 원인은 무엇일까요?

+1

NT 모드에서 BSOD을 트리거 할 수없는 사용자 모드 코드가 있어야합니다. 어떻게 든 win32k.sys를 충돌 처리 할 수 ​​있었는지 궁금합니다 ... windbg에서 커널 덤프 파일을 보면이 충돌에 대해 알려줄 것입니다. (자세한 내용은이 용어를 google을 참조하십시오.) – asveikau

답변

2

가비지 수집기에서 관리 데이터를 이동할 수 있습니다. 네이티브 코드가이를 감지 할 수 없기 때문에 잘못된 메모리 주소에 쓰는 것이 가능합니다. 그러나 .NET 런타임에서 배열을 이동하지 않도록 알릴 수 있습니다. 예 :

GCHandle handle = GCHandle.Alloc(image, GCHandleType.Pinned); 
try 
{ 
    fastSegment(handle.AddrOfPinnedObject(), 640, 480); 
} 
finally 
{ 
    // make sure to free the handle to avoid leaks! 
    handle.Free(); 
} 

편집 : 다음 GCHandle 클래스 이것은 하나의 방법이지만, 나는 그것이 문제를 보여줍니다 생각합니다. Marshaling between Managed and Unmanaged Code

+0

그 이유는 BSOD가 한 번만 발생했는데 다른 한 번은 발생하지 않았 음을 설명 할 수 있습니다. 감사합니다 :) 충돌이 순수 무작위이기 때문에이 버전이 작동하는지 테스트하는 것은 정말 어려울 것입니다. – wormsparty

2

당신은 그렇게 할 수 없습니다. 이 경우에는 배열이 읽기 전용이됩니다. C# 배열을 네이티브로 변경하려면 포인터를 마샬링해야합니다.
Microsoft의 example을 살펴보십시오.
이것이 필요한 이유에 대한 설명도 있습니다.

0

GC로 데이터를 이동할 가능성이 있습니다.하지만 애플리케이션을 실행할 때마다 크래시가 발생하는 경우는 거의 없습니다. 다음 중 하나를 시도하십시오.

[DllImport(_dllname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] 
private static extern bool fastSegment(IntPtr img, int width, int height); 
[ReliabilityContract(Consistency.MayCorruptProcess, Cer.None)] 
static void FastSegment(byte[] data, int width, int height) 
{ 
    var length = width * height; 
    var ptr = Marshal.AllocHGlobal(width * height); 
    try 
    { 
     Marshal.Copy(data, 0, ptr, length); 
     fastSegment(ptr, width, height); 
     Marshal.Copy(ptr, data, 0, length); 
    } 
    finally 
    { 
     Marshal.FreeHGlobal(ptr); 
    } 
} 
// ---- OR ---- 
[DllImport(_dllname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] 
private static extern bool fastSegment(IntPtr img, int width, int height); 
[ReliabilityContract(Consistency.MayCorruptProcess, Cer.None)] 
static void FastSegment(byte[] data, int width, int height) 
{ 
    var handle = GCHandle.Alloc(data, GCHandleType.Pinned); 
    try 
    { 
     fastSegment(handle.AddrOfPinnedObject(), width, height); 
    } 
    finally 
    { 
     handle.Free(); 
    } 
} 
// ---- OR ---- 
[DllImport(_dllname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] 
private static unsafe extern bool fastSegment(byte* img, int width, int height); 
[ReliabilityContract(Consistency.MayCorruptProcess, Cer.None)] 
static void FastSegment(byte[] data, int width, int height) 
{ 
    unsafe 
    { 
     fixed (byte* dataPinned = data) 
     { 
      fastSegment(dataPinned, width, height); 
     } 
    } 
} 
관련 문제