托管C++中GDI+和GDI混合编程技术
3.2 数据封送
由于在 GDI API(在wingdi.h中列出)函数中所使用的数据类型和托管C++( .net Framework内置值类型)存在一些区别(如表1所示),虽然在托管C++中可以不通过平台调用中的数据封送来直接调用GDI API,但对于结构、数组和字符串数据类型来说,通过使用平台调用中的属性和方法来封送数据可以更好地实现自己的数据定制。
表1 数据类型
|
wtypes.h
|
C++
|
托管C++
|
.NET类名
|
说明
|
|
GDI句柄
|
void *
|
void *
|
IntPtr, UIntPtr
|
32 位
|
|
BYTE
|
unsigned char
|
unsigned char
|
Byte
|
8 位
|
|
SHORT
|
short
|
short
|
Int16
|
16 位
|
|
WORD
|
unsigned
|
short unsigned
|
short UInt16
|
16 位
|
|
INT
|
int
|
int
|
Int32
|
32 位
|
|
UINT
|
unsigned int
|
unsigned int
|
UInt32
|
32 位
|
|
LONG
|
long
|
long
|
Int32
|
32 位
|
|
BOOL
|
long
|
bool
|
Boolean
|
32 位
|
|
DWORD
|
unsigned long
|
unsigned long
|
UInt32
|
32 位
|
|
ULONG
|
unsigned long
|
unsigned long
|
UInt32
|
32 位
|
|
CHAR
|
char
|
char
|
Char
|
用 ANSI 修饰
|
|
LPSTR
|
char *
|
String * [in], StringBuilder * [in, out]
|
String [in], StringBuilder [in, out]
|
用 ANSI 修饰
|
|
LPCSTR
|
const char *
|
String *
|
String
|
用 ANSI 修饰
|
|
LPWSTR
|
wchar_t *
|
String * [in], StringBuilder * [in, out]
|
String [in], StringBuilder [in, out]
|
用 Unicode 修饰
|
|
LPCWSTR
|
const wchar_t *
|
String *
|
String
|
用 Unicode 修饰
|
|
FLOAT
|
float
|
float
|
Single
|
32 位
|
|
DOUBLE
|
double
|
double
|
Double
|
64 位
|
(1) 封送结构
在托管C++中,当调用的GDI API函数有内置结构时,需要对其使用StructLayout属性来进行封送。通过该属性类的构造函数来指定被封送的结构的数据成员在非托管内存中的排列方式。当为LayoutKind::Explicit时,则每个成员必须使用FieldOffset属性来指定该字段在类型中的位置。当为LayoutKind::Sequential时,则强制将成员按其出现的顺序进行顺序布局。例如:
namespace GDI32API
{
using namespace System;
using namespace System::Runtime::InteropServices;
typedef void* HDC;
[StructLayout(LayoutKind::Sequential)]
public __value struct RECT
{
public:
long left; // long或Int32
long top;
long right;
long bottom;
};
[DllImport("gdi32", EntryPoint="GetCliPBox")]
extern "C" int GetClipBox(HDC hDC, RECT* rect);
}
(2) 封送字符串和数组等
在托管C++中,使用MarshalAs属性类可以封送GDI API函数中的参数、内置结构的字段或返回值。MarshalAs属性通常需要指定UnmanagedType枚举来标识非托管数据的格式。
当需要封送String *字符串时,可指定UnmanagedType枚举中的LPStr、LPWStr或LPTStr来封送,这些类型分别对应于GDI API中的LPSTR、LPWSTR或LPTSTR字符串类型。例如:
[DllImport("gdi32", EntryPoint="TextOut")]
extern "C" bool TextOut(HDC hDC, int x, int y,
[MarshalAs(UnmanagedType::LPWStr)] String *str, int nNum);
若封送结构中的字符串成员,则需指定UnmanagedType::ByValTStr类型,并指定SizeConst值来确定要导入的字符串中的字符数。
当需要封送数组时,需指定UnmanagedType::LPArray类型,并指定SizeConst值来确定要导入的数组大小,根据需要也可用ArraySubType字段指定数组元素的数据类型。例如,若有DLL中有这样的非托管函数:
HRESULT New1(int ar[10]);
HRESULT New2(double ar[10][20]);
HRESULT New3(LPWSTR ar[10]);
则封送的托管代码如下:
void New1([MarshalAs(UnmanagedType::LPArray, SizeConst=10)] int ar __gc[]);
void New2([MarshalAs(UnmanagedType::LPArray, SizeConst=200)] double ar __gc[]);
void New2([MarshalAs(UnmanagedType::LPArray,
ArraySubType=UnmanagedType::LPWStr, SizeConst=10)] String[] ar);
0
相关文章