수색…
통사론
- [DllImport ( "Example.dll")] 정적 extern void SetText (string inString);
- [DllImport ( "Example.dll")] 정적 extern 무효 GetText (StringBuilder outString);
- [MarshalAs (UnmanagedType.ByValTStr, SizeConst = 32)] 문자열 텍스트;
- [MarshalAs (UnmanagedType.ByValArray, SizeConst = 128)] byte [] byteArr;
- [StructLayout (LayoutKind.Sequential)] 공용 구조체 PERSON {...}
- [StructLayout (LayoutKind.Explicit)] 공용 구조체 MarshaledUnion {[FieldOffset (0)] ...}
Win32 dll 함수 호출하기
using System.Runtime.InteropServices;
class PInvokeExample
{
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern uint MessageBox(IntPtr hWnd, String text, String caption, int options);
public static void test()
{
MessageBox(IntPtr.Zero, "Hello!", "Message", 0);
}
}
함수를 static extern
stting DllImportAttribute
로 선언하고 Value
속성을 .dll name으로 설정합니다. System.Runtime.InteropServices
네임 스페이스를 사용하는 것을 잊지 마십시오. 그런 다음이를 일반 정적 메서드라고 부릅니다.
플랫폼 호출 서비스 (Platform Invocation Services)는 .dll을로드하고 원하는 기능을 찾는다. 가장 간단한 경우 P / Invoke는 매개 변수를 마샬링하고 .dll과의 값을 반환합니다 (즉, .NET 데이터 유형을 Win32 데이터 유형으로 변환하거나 그 반대로 변환).
Windows API 사용
pinvoke.net을 사용하십시오.
코드에서 extern
Windows API 함수를 선언하기 전에 pinvoke.net 에서 해당 함수를 찾으십시오 . 그들은 이미 모든 지원 유형과 좋은 예를 가지고 적절한 선언을 이미 가지고 있습니다.
마샬링 배열
간단한 유형의 배열
[DllImport("Example.dll")]
static extern void SetArray(
[MarshalAs(UnmanagedType.LPArray, SizeConst = 128)]
byte[] data);
문자열 배열
[DllImport("Example.dll")]
static extern void SetStrArray(string[] textLines);
마샬링 구조체
단순한 구조체
C ++ 서명 :
typedef struct _PERSON
{
int age;
char name[32];
} PERSON, *LP_PERSON;
void GetSpouse(PERSON person, LP_PERSON spouse);
C # 정의
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct PERSON
{
public int age;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string name;
}
[DllImport("family.dll", CharSet = CharSet.Auto)]
public static extern bool GetSpouse(PERSON person, ref PERSON spouse);
알 수없는 크기의 배열 필드가있는 구조체입니다. 전달 중
C ++ 서명
typedef struct
{
int length;
int *data;
} VECTOR;
void SetVector(VECTOR &vector);
관리 코드에서 비 관리 코드로 전달되면이
data
배열은 IntPtr로 정의되어야하며 메모리는 Marshal.AllocHGlobal()
으로 명시 적으로 할당되어야합니다 Marshal.FreeHGlobal()
이후 Marshal.FreeHGlobal()
해제됩니다).
[StructLayout(LayoutKind.Sequential)]
public struct VECTOR : IDisposable
{
int length;
IntPtr dataBuf;
public int[] data
{
set
{
FreeDataBuf();
if (value != null && value.Length > 0)
{
dataBuf = Marshal.AllocHGlobal(value.Length * Marshal.SizeOf(value[0]));
Marshal.Copy(value, 0, dataBuf, value.Length);
length = value.Length;
}
}
}
void FreeDataBuf()
{
if (dataBuf != IntPtr.Zero)
{
Marshal.FreeHGlobal(dataBuf);
dataBuf = IntPtr.Zero;
}
}
public void Dispose()
{
FreeDataBuf();
}
}
[DllImport("vectors.dll")]
public static extern void SetVector([In]ref VECTOR vector);
알 수없는 크기의 배열 필드가있는 구조체입니다. 전수
C ++ 서명 :
typedef struct
{
char *name;
} USER;
bool GetCurrentUser(USER *user);
이러한 데이터가 비 관리 코드에서 전달되고 관리되지 않는 함수에 의해 메모리가 할당되면 관리되는 호출자는이를 IntPrt
변수로 받아 버퍼를 관리되는 배열로 변환해야합니다. 문자열의 경우 편리한 Marshal.PtrToStringAnsi()
메서드가 있습니다.
[StructLayout(LayoutKind.Sequential)]
public struct USER
{
IntPtr nameBuffer;
public string name { get { return Marshal.PtrToStringAnsi(nameBuffer); } }
}
[DllImport("users.dll")]
public static extern bool GetCurrentUser(out USER user);
노동 조합 마샬링
값 유형 필드 만
C ++ 선언
typedef union
{
char c;
int i;
} CharOrInt;
C # 선언
[StructLayout(LayoutKind.Explicit)]
public struct CharOrInt
{
[FieldOffset(0)]
public byte c;
[FieldOffset(0)]
public int i;
}
값 유형 및 참조 필드 혼합
하나의 값 유형으로 참조 값을 겹치게하면 허용되지 않으므로 단순히 ~을 위해 컴파일되지 않습니다. FieldOffset(0) text; FieldOffset(0) i;
typedef union
{
char text[128];
int i;
} TextOrInt;
일반적으로 사용자 지정 마샬링을 사용해야합니다. 그러나 이와 같은 단순한 기술과 같은 특별한 경우에는 다음을 사용할 수 있습니다.
[StructLayout(LayoutKind.Sequential)]
public struct TextOrInt
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
public byte[] text;
public int i { get { return BitConverter.ToInt32(text, 0); } }
}