技术开发 频道

托管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);
 
  若封送结构中的数组成员,则需指定UnmanagedType::ByValArray类型,并指定SizeConst值来确定要导入的数组大小。
0
相关文章