2010-12-09 5 views
2

어제 게시물을 올렸습니다. 원래 C++로 작성된 구조를 C#으로 작성합니까?C#에서 안전하지 않은 포인터를 초기화하고 바이트 []로 변환하는 방법?

답변 해 주셔서 감사합니다.

나는 WinCE 6.0 및 .NET Compact Framework 2.0을 실행하는 ARM 플랫폼에서 DeviceIOControl을 사용하려고 노력하고 있습니다. 달성하려는 것은 포트 핀을 제어하고 악몽이되고 있습니다.

[DllImport("coredll.dll", EntryPoint = "DeviceIoControl", SetLastError = true)] 
internal static extern bool DeviceIoControlCE(int hDevice, 
              int dwIoControlCode, 
              byte[] lpInBuffer, 
              int nInBufferSize, 
              byte[] lpOutBuffer, 
              int nOutBufferSize, 
              ref int lpBytesReturned, 
              IntPtr lpOverlapped); 

PInvoke를 선언 바이트 []를 단순히 전달 될 수 제안 다음

PInvoke를 선언한다. 구조체의 각 멤버에 값을 쓰고 바이트 배열로 변환하여 dll로 전달하는 것은 쉬운 일입니다.) (

[StructLayout(LayoutKind.Sequential)] 
    public struct pio_desc 
    { 
     unsafe byte* pin_name;  //Length??? 
     public uint pin_number;  //4 bytes 
     public uint default_value; //4 bytes 
     public byte attribute;  //1 byte 
     public uint pio_type;  //4 bytes 
    } 

pio_desc PA13 = 새로운 pio_desc;

나는 다음이

byte[] temp = BitConverter.GetBytes(PA13.pin_number); //uints are 4 bytes wide 
     byteArray[++NumberOfChars] = temp[0]; 
     byteArray[++NumberOfChars] = temp[1]; 
     byteArray[++NumberOfChars] = temp[2]; 
     byteArray[++NumberOfChars] = temp[3];  //Will need to check on Endianess 

질문 :

에서 바이트 []에

PA13.pin_number = AT91_PIN_PA13;  //Length 4 bytes 
PA13.default_value = 0;    //Length 4 bytes 
PA13.attribtue = PIO_DEFAULT;   //Length 1 byte 
PA13.pio_type = PIO_OUTPUT;   //Length 4 bytes 

및 변환 (예를 들어 pin_number) :

그래서 확실히 지금처럼 뭔가를하고의 문제 구조체 PA13, 안전하지 않은 포인터 인 pin_name을 초기화하는 방법은 무엇입니까? 운전자의 저자는 아마도 운전자가 사용하지 않았다고 기록합니다. Windows가이를 필요로할까요?

PA13.pin_name = ??????

그렇다면이 포인터를 DeviceIOControl에 전달할 바이트 [] 배열에 맞게 바이트로 변환하려면 어떻게해야합니까?

저는 포트 핀의 전압 레벨을 변경하는 것이 얼마나 어려운지에 대해 매우 실망하고 좌절했습니다. 지금이 문제로 고생하고 있습니다. 하드웨어 배경에서 왔기 때문에 다른 컨트롤러에서 IO 컨트롤을 구현하고 COM 포트를 통해 컨트롤 데이터를 전달하는 것이 더 쉽고 (덜 성숙한) 생각이납니다.

(단순한) 도움을 주셔서 다시 한번 감사드립니다.

+0

관리되지 않는 구조 정의를 붙여 넣을 수 있습니까? 구조체의 리터럴 포트가'char * pin_name'에서 왔을 것이기 때문에'pin_name'은 실제로 C 스타일의 문자열로 생각됩니다. 이 경우 struct에서 [MarshalAs (UnmanagedType.LPStr)] public string pin_name;을 사용할 수 있습니다. – cdhowie

+0

관심을 가져 주셔서 감사합니다! unmananged 구조체는 다음과 같습니다. struct pio_desc { \t const char * pin_name;/* 핀 이름 */ \t unsigned int pin_num;/* 핀 번호 */ \t 부호없는 정수 dft_value;/* 출력의 기본값 */ \t 부호없는 char 특성; \t enum pio_type 유형; }; 열거 형을 int 또는 byte 데이터 유형으로 바꾸려고합니다. 필자는이 구조체에 대한 기술 노트에 따르면 핀 이름이 사용되지 않는다고 말합니다. 그렇다면 그것을 포함하는 것이 이상 할 것 같지만, 핀을 참조하는 것이 숫자 대신 발생한다고 생각합니다. – Gary

답변

0

lpInBuffer 및 lpOutBuffer를 IntPtr로 선언하십시오. Marshal.AllocHGlobal을 사용하여 초기화하십시오 (Marshal.FreeHGlobal로 끝내는 것을 잊지 마십시오). 이 버퍼를 채우고 다른 Marshal.Copy 오버로드를 사용하여 읽습니다.

1

여기서 몇 가지 작업을 수행해야합니다.

unsafe byte* pin_name;  //Length??? 

와 :

[MarshalAs(UnmanagedType.LPStr)] public string pin_name; 

그럼 byte[]에서 IntPtr로 선언 호출 /를 P에/아웃 버퍼를 대체 우선,이 대체 부재.그런 다음 데이터를 변환하려면이 코드를 사용할 수 있습니다

pio_desc PA13; 
// Set the members of PA13... 

IntPtr ptr = IntPtr.Zero; 
try { 
    var size = Marshal.SizeOf(PA13); 
    ptr = Marshal.AllocHGlobal(size); 

    Marshal.StructureToPtr(PA13, ptr, false); 

    // Your P/Invoke call goes here. 
    // size will be the "nInBufferSize" argument 
    // ptr will be the "lpInBuffer" argument 
} finally { 
    if (ptr != IntPtr.Zero) { 
     Marshal.DestroyStructure(ptr, typeof(pio_desc)); 
     Marshal.FreeHGlobal(ptr); 
    } 
} 
+0

안녕하세요, 도움을 주셔서 감사합니다! 그러나이 코드를 구현했지만 int nInBufferSize 매개 변수로 전달할 대상은 무엇입니까? 나는 몇 가지를 시도했지만 아무도 작동하지 않습니다 : '지원되지 않는 예외'오류가 발생했습니다. – Gary

+0

'Marshal.SizeOf (PA13)'를 넘겨 줄 것입니다. 코드를 업데이트하겠습니다. 또한, 당신은 그 라인에서 예외를 얻을 수 있음을 명확히 할 수 있습니까? – cdhowie

+0

ptr = Marshal.AllocHGlobal (Marshal.SizeOf (PA13));에 예외가 발생합니다. 이 DeviceIOControl 함수로 너무 오래 전투를하는 것이 정상입니까? 이것에 대해 많은 사람들이 질문하는 것 같습니다. 내 밧줄이 끝날 때까지 도와 줘서 고마워. 작동하지 않는 다른 한 가지 : 내 PC의 메뉴에서 사용할 수있는 DestroyStructure 메소드가 없습니다. 나는 .NET Compact를 실행하고 있는데,이 모든 일에 문제가있을 수 있습니다. – Gary

1

당신은 [같이 DllImport] 선언에 대해 거짓말을하여이 훨씬 쉽게 만들 수 있습니다. lpInBuffer 인수를 구조체 유형으로 선언하면 pinvoke marshaller가이를 포인터로 변환합니다. 따라서 : 드라이버가 아마 아무것도 반환하지 않기 때문에 lpOutBuffer에 대한 IntPtr입니다 사용

[DllImport("coredll.dll", EntryPoint = "DeviceIoControl", SetLastError = true)] 
internal static extern bool SetOutputPin(IntPtr hDevice, 
              int dwIoControlCode, 
              ref pio_desc lpInBuffer, 
              int nInBufferSize, 
              IntPtr lpOutBuffer, 
              int nOutBufferSize, 
              out int lpBytesReturned, 
              IntPtr lpOverlapped); 

. IntPtr.Zero를 전달하십시오. 구조와 같은 아이디어. 필드가 다음 사용하지 않는 경우 단순히를 IntPtr로 선언 :

[StructLayout(LayoutKind.Sequential)] 
public struct pio_desc 
{ 
    public IntPtr pin_name;  // Leave at IntPtr.Zero 
    public uint pin_number;  //4 bytes 
    public uint default_value; //4 bytes 
    public byte attribute;  //1 byte 
    public uint pio_type;  //4 bytes 
} 

은 포장 속성에 대한주의, 그것 때문에 바이트 크기의 필드의 여기에 차이가 있습니다. 1이 필요할 수도 있지만 드라이버에 대해 알지 못하면 바로 추측입니다. C 코드를 사용하고 있다면 sizeof (pio_desc)의 값을 테스트하고 Marshal.SizeOf()와 비교하십시오. nInBufferSize 인수로 Marshal.SizeOf (typeof (pio_desc))를 전달합니다. C 선언을 게시했다면 정확하게 대답하는 것이 더 쉬울 것입니다.

+0

아아, 나를 훔 쳤어! :) –

+0

그 사람 !! 응답 주셔서 감사합니다! 나는이 함수를 사용하지 않으면 다음에해야 할 일을 결정할 때 이것도 살펴볼 것이다! – Gary

관련 문제