Chinaunix首页 | 论坛 | 博客
  • 博客访问: 128843
  • 博文数量: 44
  • 博客积分: 2500
  • 博客等级: 少校
  • 技术积分: 470
  • 用 户 组: 普通用户
  • 注册时间: 2009-12-07 23:06
文章分类

全部博文(44)

文章存档

2010年(6)

2009年(38)

我的朋友

分类:

2009-12-07 23:19:27

GDI+实际上是一组类的定义,封装了gdi+的几乎所有API,当然使用方法就要从这些“例子”里边寻找了:)本文正是尝试用GDI+写一个纯SDK的程序,语言自然是我最喜欢的语言WIN32ASM.这个程序很简单,就是用GDI+画了一条直线。算是抛砖引玉吧,感兴趣的可以自己探索其他函数的用法。
使用GDI+ API之前,必须先调用GdiplusStartup这个函数,作用是初始化GDI+函数库。这个函数在SDK中就有。函数的原型是:

  
Status GdiplusStartup(ULONG_PTR token *token,
const GdiplusStartupInput *input,
GdiplusStartupOutput *output
);
   

第一个参数是指向一个32位的无符号整型的指针,也就是指向一个汇编中的DWORD变量的指针,用于接受GDI+的TOKEN.TOKEN可以暂时理解成一个句柄,就像窗口的句柄类似。这个参数在调用GdiplusShutdown的时候用到。这个函数在结束GDI+编程后调用,起作用是释放GDI+的资源。
第二个以及第三个参数是指向两个结构体变量的指针。GdiplusStartupInput的定义如下:
struct GdiplusStartupInput
{
UINT32 GdiplusVersion;
DebugEventProc DebugEventCallback;
BOOL SuppressBackgroundThread;
BOOL SuppressExternalCodecs;

GdiplusStartupInput(
DebugEventProc debugEventCallback = NULL,
BOOL suppressBackgroundThread = FALSE,
BOOL suppressExternalCodecs = FALSE)
{
GdiplusVersion = 1;
DebugEventCallback = debugEventCallback;
SuppressBackgroundThread = suppressBackgroundThread;
SuppressExternalCodecs = suppressExternalCodecs;
}
};
这个定义看似复杂,实际就四个32位的变量,可以定义成如下的形式:
struct GdiplusStartupInput
{
UINT32 GdiplusVersion;
DebugEventProc DebugEventCallback;
BOOL SuppressBackgroundThread;
BOOL SuppressExternalCodecs;
}
一般这个结构体初始化成1,0,0,0即可,并且这时候这个函数的最后一个参数GdiplusStartupOutput可以忽略,直接用NULL就可以。

   
下面是MASM32的代码例子:

include windows.inc
include kernel32.inc
include user32.inc
include Comctl32.inc
include shell32.inc

includelib kernel32.lib
includelib user32.lib
includelib Comctl32.lib
includelib shell32.lib

include gdiplus.inc ;这是GDI+的MASM32格式的头文件,现在只是从现成的
;GDI+的库转换而来,没有整理其数据结构。
includelib gdiplus.lib ;GDI+的库文件,取自VC7.1

;上边包含的头文件以及库文件我会附在这篇文章上提供。
GdiplusStartupInput struct
GdiplusVersion dword ; // Must be 1
DebugEventCallback dword ; // Ignored on free builds
SuppressBackgroundThread dword ; // FALSE unless you're prepared to call
; // the hook/unhook functions properly
SuppressExternalCodecs dword ; // FALSE unless you want GDI+ only to use
GdiplusStartupInput ends
;上边是GdiplusStartupInput结构体的定义。
.data?

hInstance dd ?
gptoken dd ?;定义TOKEN的接收变量
.data
gpstart GdiplusStartupInput<1,0,0,0>;定义这个结构并初始化

接下来,就是在程序初始化和结束时调用GdiplusStartup跟GdiplusShutdown两个函数:
invoke GdiplusStartup,offset gptoken,offset gpstart,NULL
invoke DialogBoxParam,hInstance,IDD_DIALOG1,NULL,addr DlgProc,NULL
invoke GdiplusShutdown,gptoken
这里我选择在主窗口生成前跟销毁后调用这两个函数。
现在,在WM_PAINT里边就可以调用GDI+函数进行绘图了:
DlgProc proc hWin:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
LOCAL ps:PAINTSTRUCT
LOCAL dc:HDC
LOCAL gp
LOCAL ggg
mov eax,uMsg
.if eax==WM_INITDIALOG
.elseif eax==WM_PAINT
invoke BeginPaint,hWin,addr ps
mov dc,eax
invoke GdipCreateFromHDC,dc,addr gp
mov ggg,0
invoke GdipCreatePen1,0ffff00ffh,1,0,addr ggg
invoke GdipDrawLineI,gp,ggg,10,10,130,100
invoke GdipDeletePen,ggg
invoke GdipDeleteGraphics,gp
invoke EndPaint,hWin,addr ps

最前与最后的Begin/EndPaint()是gdi作图时常用的,不用我多说。首先,调用GdipCreateFromHDC产上一个Graphics的句柄,这个函数有两个参数看看微软提供的头文件里边的用法:
lastResult = DllExports::GdipCreateFromHDC(hdc, &graphics);
第一个参数是当前的dc,后一个则是存放Graphics句柄的指针。值得注意的是,GDI+函数的返回值一般是通过参数传递而不是eax了,eax在GDI+函数中往往返回错误代码。所以调试的时候如果执行了GDI+函数后如果返回0则说明调用成功,返回非零值一般是调用失败所致。
接下来调用GdipCreatePen1生成一个画笔对象,这个函数在微软的头文件中是这么用的:
Unit unit = UnitWorld;
nativePen = NULL;
lastResult = DllExports::GdipCreatePen1(color.GetValue(),
width, unit, &nativePen);
这个函数的第一个参数是画笔的颜色值,这是一个32位的颜色值,前8位估计是alpha通道,决定这个颜色的透明度,后边的24位以8位一组,分别代表红绿兰三原色。第二个从字面看是画笔宽度,不过我改了一下,好像并没有效果,可能是还不会用。第三个参数是一个枚举类型
enum Unit
{
UnitWorld, // 0 -- World coordinate (non-physical unit)
UnitDisplay, // 1 -- Variable -- for PageTransform only
UnitPixel, // 2 -- Each unit is one device pixel.
UnitPoint, // 3 -- Each unit is a printer's point, or 1/72 inch.
UnitInch, // 4 -- Each unit is 1 inch.
UnitDocument, // 5 -- Each unit is 1/300 inch.
UnitMillimeter // 6 -- Each unit is 1 millimeter.
};
UnitWorld是带表0的。
同样,最户一个参数是一个存放生成的画笔举柄的指针。Eax中返回值也是错误信息。
然后我们用GdipDrawLineI画一条直线,下边是微软头文件中的用法:
SetStatus(DllExports::GdipDrawLineI(nativeGraphics,
pen->nativePen,
x1,
y1,
x2,
y2));
前边两个参数分别是当前nativeGraphics的句柄跟Pen的句柄,后边则是两个坐标。
最后的两个函数GdipDeletePen与GdipDeleteGraphics是删除前边生成的画笔对象跟Graphics对象,只有一个参数,即对象的句柄。注意这两个函数的参数都是实际的地址而不是指针。   


类别:gdi/gdi+ 查看评论
阅读(1642) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~