'GDI常用封装类，其它API 可以直接用 xx.m_Dc 调用API
'为了加速GDI 画画速度，增加了 内存DC 用来缓存，不然画太多东西屏幕会闪，
'调用中不需要知道内存DC，只是其它API操作，用 xx.m_Dc 内存DC来画

'WM_PAINT 消息里用  Dim gg As yGDI = yGDI(窗口句柄,GetSysColor(COLOR_WINDOW),True)
'其它地方画画用    Dim gg As yGDI = 窗口句柄
'GDI分为：笔、刷、字体、位图、

'注意：自绘状态下预防闪耀和鼠标移出检测要在 _CUSTOM 事件里加以下代码
'Dim entTrack As tagTRACKMOUSEEVENT
'Select Case wMsg
'Case WM_MOUSELEAVE   '鼠标出窗口
'If AnNiuID <> 0 Then
'AnNiuID = 0
'AnNiuZ = 0
'FF_Redraw(hWndForm) '重绘控件
'End If
'Case WM_NCHITTEST        '启用鼠标出窗口检查
'entTrack.cbSize = SizeOf(tagTRACKMOUSEEVENT)
'entTrack.dwFlags = TME_LEAVE
'entTrack.hwndTrack = hWndForm
'entTrack.dwHoverTime = HOVER_DEFAULT
'TrackMouseEvent @entTrack
'Case WM_ERASEBKGND
'Return True   '防止擦除背景
'End Select
#include Once "Afx/CGdiPlus/CGdiPlus.inc"

Type yGDI '勇芳GDI类
Private : 
   m_ps As PAINTSTRUCT    '绘画范围，就是排除被遮挡部分，系统处理，我们只要这么写就可以了。
   m_hBmp2 As HBITMAP     ' 内存DC的位图句柄
   tFont As HFONT      '字体句柄，要是替换，请先用 DeleteObject tFont
   nPen As HPEN        'GDI 画笔句柄，要是替换，请先用 DeleteObject nPen
   nBrush As HBRUSH    'GDI 刷子句柄，要是替换，请先用 DeleteObject nBrush
Public : 
   nGpPen As GpPen Ptr    'GDI+ 笔
   nGpBrush As GpBrush Ptr  'GDI+ 刷
   nGpimage As GpImage Ptr  'GDI+ 位图，用来画图，加载图片存在这里
   Declare Sub Redraw()      '立即刷新显示画面，不然要等销毁本类时才显示
   Declare Sub Cls(ByVal clrBkg As Long = -1)      '清除屏幕
   'GDI 画图
   Declare Sub Pen(ByVal cWidth As Long, ByVal crColor As Long, ByVal iStyle As Long = PS_SOLID) '设置笔，画框线用 {3.PS_NULL 无线.PS_SOLID 实线.PS_DASH 虚线.PS_DOT 点线.PS_DASHDOT 点划线.PS_DASHDOTDOT 点-点划线.PS_INSIDEFRAME 由椭圆、矩形、圆角矩形、饼图以及弦等生成的封闭对象框时，画线宽度向内扩展。如指定的准确RGB颜色不存在，就进行抖动处理}
   Declare Sub Brush(ByVal crColor As Long = -1) '设置刷子，用于填充颜色 -1为空刷子
   Declare Sub BrushHatch(fnStyle As Long, crColor As Long = 0) '设置 样式 刷子，用于填充 {1.HS_BDIAGONAL 从右到左45度 斜纹.HS_CROSS 十字线.HS_DIAGCROSS 45度十字线.HS_FDIAGONAL 从左到右45度 斜纹.HS_HORIZONTAL 水平纹.HS_VERTICAL 垂直纹}
   Declare Sub DrawLine(ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) '画线条，位置1到位置2
   Declare Sub DrawArc(ByVal X As Long, ByVal Y As Long, ByVal W As Long, ByVal H As Long, ByVal StartAngle As Single, ByVal EndAngle As Single) '画圆弧，x y w h 一个假想的圆，位置和宽度高度 , StartAngle 相对于x轴的起始角度（以度为单位）。0度为原的右边中部 , EndAngle 结束角度
   Declare Sub DrawFrame(ByVal X As Long, ByVal Y As Long, ByVal W As Long = 0, ByVal H As Long = 0) '画框 位置和宽度高度
   Declare Sub DrawCircleFrame(ByVal X As Long, ByVal Y As Long, ByVal W As Long, ByVal H As Long, ByVal wC As Long, ByVal hC As Long) '描绘一个圆角矩形，位置和宽度高度、宽圆和高度圆
   Declare Sub DrawEllipse(ByVal X As Long, ByVal Y As Long, ByVal W As Long, ByVal H As Long) '描绘一个椭圆，位置和宽度高度
   Declare Sub DrawPolygon(Points() As Point) '描绘多边形 顶点数必须大于或等于2。
   'GDI 文字
   Declare Sub Font(fName As CWSTR = "Microsoft YaHei", ByVal fSize As Long = 9, ByVal Bold As UByte = False, Italic As UByte = False, ByVal Underline As UByte = False, ByVal StrikeOut As UByte = False) '设置字体{3.True.False}{4.True.False}{5.True.False}{6.True.False}
   Declare Sub SetColor(ByVal tColor As Long, ByVal bColor As Long = -1) '设置文本颜色，字色和字的背景色，背景值-1为透明背景。
   Declare Sub DrawString(ByVal X As Long, ByVal Y As Long, nText As CWSTR) '描绘制指定的文本字符串
   Declare Sub DrawStringFC(ByVal X As Long, ByVal Y As Long, nText As CWSTR, tColor As Long, nName As CWSTR = "Microsoft YaHei", ByVal fSize As Long = 9, ByVal Bold As UByte = False) '描绘制指定的文本字符串，带字体和颜色
   Declare Function DrawTextS(X As Long, Y As Long, W As Long, H As Long, nText As CWSTR, uFormat As ULong = 0) As Long  '指定的矩形中绘制格式化的文本，样式为组合，见VFB帮助。
   Declare Function DrawTextFC(X As Long, Y As Long, W As Long, H As Long, nText As CWSTR, uFormat As ULong = 0, tColor As Long, nName As CWSTR = "Microsoft YaHei", ByVal fSize As Long = 9, ByVal Bold As UByte = False) As Long  '指定的矩形中绘制格式化的文本，带字体和颜色，样式为组合，见VFB帮助。
   Declare Sub DrawFrameStr(ByVal X As Long, ByVal Y As Long, nText As CWSTR) '描绘描边字，轮廓字，轮廓先设置笔，字为正常字
   Declare Sub DrawFrameStrR(ByVal X As Long, ByVal Y As Long, nText As CWSTR, bColor As Long) '绕写方式的轮廓字
   Declare Sub DrawFrameText(X As Long, Y As Long, W As Long, H As Long, nText As CWSTR, uFormat As ULong = 0) '描绘描边字，轮廓字，轮廓先设置笔，字为正常字
   Declare Sub DrawFrameTextR(X As Long, Y As Long, W As Long, H As Long, nText As CWSTR, bColor As Long, uFormat As ULong = 0) '绕写方式的轮廓字
   Declare Function GetTextWidth(nText as CWSTR) as Long '获取文本显示宽度，自动支持DPI感知，为 100% DPI 时的数字。假如 DPI比率=1 则是实际像素值
   Declare Function GetTextHeight(nText as CWSTR) as Long '获取文本显示高度，自动支持DPI感知，为 100% DPI 时的数字。假如 DPI比率=1 则是实际像素值
   'GDI 位图
   Declare Sub InvertPixels(X As Long, Y As Long, W As Long, H As Long) '将指定的矩形中像素颜色翻转
   Declare Function GetPixel(ByVal x As Long, ByVal y As Long) As Long  '获取像素点颜色
   Declare Function SetPixel(ByVal x As Long, ByVal y As Long, ByVal crColor As Long) As Long '设置像素点颜色
   
   Declare Sub DrawImgRes(hInst As HINSTANCE, ResName As CWSTR , X As Long, Y As Long, W As Long = 0, H As Long = 0, dimPercent As Long = 0, bGrayScale As Long = False) '直接画资源里的图片，必须是格式为.png，.jpg，.gif，.tiff的图 {8.True 转换成灰度.False}{7.0 调高亮度百分比.50 从1到99.99 最高99}
   Declare Sub DrawImgFile(FileName As CWSTR, X As Long, Y As Long, W As Long = 0, H As Long = 0, dimPercent As Long = 0, bGrayScale As Long = False) '直接画文件的图片 {7.True 转换成灰度.False}{6.0 调高亮度百分比.50 从1到99.99 最高99}
   Declare Sub DrawIcoRes(hInst As HINSTANCE, ResName As CWSTR, X As Long, Y As Long, W As Long = 0, H As Long = 0) '画资源里的图标
   Declare Sub LoadImgFile(FileName As CWSTR, dimPercent As Long = 0, bGrayScale As Long = False, clrBackground AS ARGB = 0) '加载文件图像到 m_bDc ，便于后面重复使用，再次加载将消耗前面加载的。 {3.True 转换成灰度.False}{2.0 调高亮度百分比.50 从1到99.99 最高99}
   Declare Sub LoadImgRes(hInst As HINSTANCE, ResName As CWSTR, dimPercent As Long = 0, bGrayScale As Long = False, clrBackground AS ARGB = 0) '加载资源图像到 m_bDc ，便于后面重复使用，再次加载将消耗前面加载的。 {4.True 转换成灰度.False}{3.0 调高亮度百分比.50 从1到99.99 最高99}
   Declare Sub LoadBmpRes(hInst As HINSTANCE, ResName As CWSTR, dimPercent As Long = 0, bGrayScale As Long = False) '加载资源中BMP图像到 m_bDc ，便于后面重复使用，再次加载将消耗前面加载的。 {4.True 转换成灰度.False}{3.0 调高亮度百分比.50 从1到99.99 最高99}
   Declare Sub DrawCopyImg(xDest As Long, yDest As Long, wDest As Long, hDest As Long, xSrc As Long, ySrc As Long, wSrc As Long, hSrc As Long, rop As DWord = SrcCopy) '描绘由LoadImg加载来的图,主要用来像画工具栏里的小按钮{9.SRCAND AND合并(光栅操作代码).SRCCOPY 直接拷贝.SRCERASE 目标取反合并.SRCINVERT Xor合并.SRCPAINT Or合并.WHITENESS 调色板1索引.BLACKNESS 调色板0索引.DSTINVERT 目标取反.MERGECOPY And源模式组合.MERGEPAINT Or反向源.NOTSRCCOPY 源取反拷贝 .NOTSRCERASE Or组合源，合成后取反.PATCOPY 模式拷贝.PATPAINT Or源取反与模式并.PATINVERT Xor源合并}
   Declare Sub DrawCopyImgAlpha(xDest As Long, yDest As Long, wDest As Long, hDest As Long, xSrc As Long, ySrc As Long, wSrc As Long, hSrc As Long, TeMeDu As Long) '半透明 描绘由LoadImg加载来的图，TeMeDu为透明度
   Declare Sub DrawCopyImgColor(xDest As Long, yDest As Long, wDest As Long, hDest As Long, xSrc As Long, ySrc As Long, wSrc As Long, hSrc As Long, tColor As Long) '扣色 描绘由LoadImg加载来的图
   'GDI+ 画图
   Declare Sub GpPen(ByVal nWidth As REAL, ByVal nColor As ARGB = &HFF000000) 'GDI+ 设置笔，画框线用 基本笔，颜色和笔粗 宽度=0 不画线
   Declare Sub GpArrowCap(W As REAL, H As REAL, isFilled As BOOL,W2 As REAL=0, H2 As REAL=0) 'GDI+ 给笔设置终点(w h) 起点(w2 h2) 的键帽，宽高和填充， 先设置笔后才能设置键帽{3.True 填充箭头.False 不填充箭头}
   Declare Sub GpBrush(ByVal nColor As ARGB = 0) 'GDI+ 设置纯色刷子，用于填充颜色 0为空刷子
   Declare Sub GpBrushGradient(X1 As Long, Y1 As Long, X2 As Long, Y2 As Long, Color1 As ARGB, Color2 As ARGB, WrapMode As Long) 'GDI+ 渐变刷子 {7.WrapModeTile =0 平铺而不翻转.WrapModeTileFlipX =1 平铺水平翻转.WrapModeTileFlipY =2 平铺垂直翻转.WrapModeTileFlipXY =3 平铺垂直翻转，平铺水平翻转.WrapModeClamp =4 不进行平铺}
   Declare Sub GpDrawLine(X1 As Single, Y1 As Single, X2 As Single, Y2 As Single) 'GDI+ 画线
   Declare Sub GpDrawArc(X As Single, Y As Single, W As Single, H As Single, StartAngle As Single, sweepAngle As Single) 'GDI+ 画圆弧，x y w h 一个假想的圆，位置和宽度高度 , StartAngle 相对于x轴的起始角度（以度为单位）。0度为原的右边中部 , EndAngle 结束角度
   Declare Sub GpDrawFrame(X As Single, Y As Single, W As Single, H As Single) 'GDI+ 画框
   Declare Sub GpDrawCircleFrame(X As Single, Y As Single, W As Single, H As Single, wC As Single, hC As Single) 'GDI+ 描绘一个圆角矩形，位置和宽度高度、宽圆和高度圆
   Declare Sub GpDrawEllipse(X As Single, Y As Single, W As Single, H As Single) 'GDI+ 描绘一个椭圆
   Declare Sub GpDrawPolygon(Points() As Point,fillMode As Long=0) 'GDI+ 描绘一个多边形 顶点数必须大于或等于2。封闭区域填充模式 {2.0 指定根据偶数奇偶校验规则填充区域.1 指定根据非零绕组规则填充区域}  
   
   Declare Sub GpDrawFrameStr(X As Single, Y As Single, nText As CWSTR, hFont As CWSTR = "Microsoft YaHei", hSize As Long = 9) '描绘描边字，轮廓字，轮廓先设置笔，字为正常字，默认9号字
   
   
   Declare Function GpLoadImgFile(FileName As CWSTR) As Long '加载文件图像到 nGpimage ，便于后面重复使用，再次加载将消耗前面加载的。
   Declare Function GpLoadImgRes(hInst As HINSTANCE, ResName As CWSTR) As Long '加载资源图像到 nGpimage ，便于后面重复使用，再次加载将消耗前面加载的。
   Declare Sub GpDrawCopyImg(xDest As Single, yDest As Single, wDest As Single, hDest As Single, xSrc As Single, ySrc As Single, wSrc As Single, hSrc As Single) '描绘由LoadImg加载来的图,主要用来像画工具栏里的小按钮
   
   Declare Function SaveBitmap(ByRef wszFileName As CWSTR, ByRef wszMimeType As CWSTR = "image/bmp") As Long ' {2."image/bmp" Bitmap图像格式(bmp)."image/gif" = GIF图像格式(gif)."image/jpeg" = JPEG图像格式(jpg)."image/png" = PNG图像格式(png)."image/tiff" = TIFF图像格式(tiff)}
   Declare Constructor(ByVal hWndForm As hWnd = 0, clrBkg As Long = -1, ByVal YN_WM_PAINT As Long = False, x As Long = 0, y As Long = 0, w As Long = 0, h As Long = 0, win As Long = 0)
   Declare Constructor(nDC As hDC, nDpi As Long = 0, x As Long = 0, y As Long = 0, w As Long = 0, h As Long = 0)
   Declare Destructor
   
   m_Bmp As HBITMAP         ' yGDI的位图句柄
   m_Dc As hDC              ' yGDI的主DC
   m_bDc As hDC             ' 辅助DC 加载文件或资源里的图像画到这DC，用于拷贝到主DC
   m_nDC As hDC             ' 目标DC，与控件或窗口关联的DC，一般不使用
   m_GpDC As GpGraphics Ptr ' 主DC 的 GDI+句柄
   m_WndForm As hWnd        ' 目标控件或窗口的句柄
   m_Width  As Long         ' 目标控件或窗口的客户区画画矩形的大小
   m_Height As Long         ' 目标控件或窗口的客户区画画矩形的大小
   m_X  As Long             ' 目标控件或窗口的开始画画位置
   m_Y As Long              ' 目标控件或窗口的开始画画位置
   m_YN As Long             ' 是绘图消息还是普通的画画
   m_DpiX As Single         ' DPI比率，AfxScaleX(1)，默认支持高DPI，画画时按100%写，自动转换支持高DPI，设置 =1 不支持
   m_DpiY As Single         ' DPI比率，AfxScaleY(1)，
   m_ImgWidth as long	     ' 加载GDI图像后，图像的尺寸
   m_ImgHeight as long	     ' 加载GDI图像后，图像的尺寸
   
End Type


'--------------------------------------------------------------------------------
Private Constructor yGDI(ByVal hWndForm As hWnd = 0, clrBkg As Long = -1, ByVal YN_WM_PAINT As Long = False, x As Long = 0, y As Long = 0, w As Long = 0, h As Long = 0, win As Long = 0)
   'hWndForm     窗口句柄
   'clrBkg       初始底色
   'YN_WM_PAINT  是否 WM_PAINT 消息里
   'x,y,w,h      画画范围，画时按 X=0 Y=0 画，最后输出到这个 x y , w h 未指定将使用原来大小
   'win          客户区和非客户区，=0只是客户区，<>0 包含非客户区
   m_DpiX = 1 : m_DpiY = 1
   If IsWindow(hWndForm) Then
      m_WndForm = hWndForm
      Dim rc As Rect
      m_YN = YN_WM_PAINT
      If YN_WM_PAINT Then
         m_nDC = BeginPaint(hWndForm, @m_ps) '获取需要绘画DC，推荐此方法，绘图效率高
      Else
         If win = 0 Then m_nDC = GetDC(hWndForm) Else m_nDC = GetWindowDC(hWndForm)
      End If
      m_X = x
      m_Y = y
      If w > 0 And h > 0 Then
         m_Width = w  ' +1 是像素个数，画图是 0,0 -- w,h
         m_Height = h
      Else
         If win = 0 Then Getclientrect(hWndForm, @rc) Else GetWindowRect(hWndForm, @rc)
         m_Width = (rc.Right - rc.Left) + 1 - x  ' +1 是像素个数，画图是 0,0 -- w,h
         m_Height = (rc.Bottom - rc.Top) + 1 - y
      End If
      '// 创建一个兼容的位图
      m_Bmp = CreateCompatibleBitmap(m_nDC, m_Width, m_Height)
      '// 创建兼容的设备上下文
      m_Dc = CreateCompatibleDC(m_nDC)
      '// 将位图选择到兼容的设备上下文中
      If m_Dc Then DeleteObject SelectObject(m_Dc, m_Bmp)
      
      '// 绘制位图的背景
      If clrBkg = -1 Then
         m_hBmp2 = CreateCompatibleBitmap(m_nDC, m_Width, m_Height)
         If m_hBmp2 Then
            m_bDc = CreateCompatibleDC(m_Dc)
            DeleteObject SelectObject(m_bDc, m_hBmp2)
         End If
         
         BitBlt m_bDc, 0, 0, m_Width, m_Height, m_nDC, m_X, m_Y, SrcCopy '将原内容获取到内存DC
         BitBlt m_Dc, 0, 0, m_Width, m_Height, m_nDC, m_X, m_Y, SrcCopy '将原内容获取到内存DC
      Else
         This.Cls clrBkg
      End If
      SetBkMode m_Dc, 1  '设置这个后，画上的字是透明的
      GdipCreateFromHDC(m_Dc, @m_GpDC)
      GdipSetSmoothingMode m_GpDC, SmoothingModeAntiAlias
      m_DpiX = GetDeviceCaps(m_nDC, LOGPIXELSX) / 96
      m_DpiY = GetDeviceCaps(m_nDC, LOGPIXELSY) / 96
      This.Font("Microsoft YaHei")
      
   End If
   This.GpPen(1) '设置默认笔
   'This.Brush(-1) '默认不填充
End Constructor
Private Constructor yGDI(nDC As hDC, nDpi As Long = 0, x As Long = 0, y As Long = 0, w As Long = 0, h As Long = 0)
   'nDpi  0：自动响应DPI  1：不响应DPI
   'x y w h  画画范围，画时按 X=0 Y=0 画，最后输出到这个 x y , w h 未指定将使用原来大小
   m_WndForm = 0
   Dim rc As Rect
   
   m_nDC = nDC
   m_X = x
   m_Y = y
   If w > 0 And h > 0 Then
      m_Width = w  ' +1 是像素个数，画图是 0,0 -- w,h
      m_Height = h
   Else
      m_Bmp = GetCurrentObject(m_nDC, OBJ_BITMAP)
      Dim bb As BITMAP
      GetObject(m_Bmp, SizeOf(BITMAP), @bb)
      m_Width = bb.bmWidth - x  ' +1 是像素个数，画图是 0,0 -- w,h
      m_Height = bb.bmHeight - y
      'Print "m_Bmp=" & m_Bmp, m_Width, m_Height
   End If
   '// 创建一个兼容的位图
   m_Bmp = CreateCompatibleBitmap(m_nDC, m_Width, m_Height)
   '// 创建兼容的设备上下文
   m_Dc = CreateCompatibleDC(m_nDC)
   '// 将位图选择到兼容的设备上下文中
   If m_Dc Then DeleteObject SelectObject(m_Dc, m_Bmp)
   BitBlt m_Dc, 0, 0, m_Width, m_Height, m_nDC, m_X, m_Y, SrcCopy '复制原图
   SetBkMode m_Dc, 1  '设置这个后，画上的字是透明的
   GdipCreateFromHDC(m_Dc, @m_GpDC)
   GdipSetSmoothingMode m_GpDC, SmoothingModeAntiAlias
   If nDpi = 0 Then
      m_DpiX = GetDeviceCaps(m_nDC, LOGPIXELSX) / 96
      m_DpiY = GetDeviceCaps(m_nDC, LOGPIXELSY) / 96
   Else
      m_DpiX = 1 : m_DpiY = 1
   End If
   This.Font("Microsoft YaHei")
   This.GpPen(1) '设置默认笔
   This.Brush( -1) '默认不填充
End Constructor
Destructor yGDI
   'Print "销毁GDI"
   This.Redraw
   If IsWindow(m_WndForm) Then
      If m_YN Then
         EndPaint(m_WndForm, @m_ps) '完成绘图
      Else
         ReleaseDC m_WndForm, m_nDC
      End If
   End If
   
   '// 销毁位图和内存设备上下文
   If m_Bmp Then DeleteObject m_Bmp
   If m_hBmp2 Then DeleteObject m_hBmp2
   If m_Dc Then DeleteDC m_Dc
   If m_bDc Then DeleteDC m_bDc
   If tFont Then DeleteObject tFont
   If nPen Then DeleteObject nPen    '画笔
   If nBrush Then DeleteObject nBrush
   If m_GpDC Then GdipDeleteGraphics(m_GpDC)
   If nGpPen Then GdipDeletePen nGpPen
   If nGpBrush Then GdipDeleteBrush nGpBrush 'GDI+ 刷
   If nGpimage Then GdipDisposeImage nGpimage
End Destructor

'--------------------------------------------------------------------------------
Private Sub yGDI.Redraw()
   BitBlt m_nDC, m_X, m_Y, m_Width, m_Height, m_Dc, 0, 0, SrcCopy '将内存DC，输出到控件
End Sub
'--------------------------------------------------------------------------------
Private Sub yGDI.Cls(ByVal clrBkg As Long = -1)      '清除屏幕
   
   If clrBkg = -1 Then
      
      BitBlt m_Dc, 0, 0, m_Width, m_Height, m_bDc, 0, 0, SrcCopy '将原内容获取到内存DC
   Else
      Dim coord As RECT
      SetRect(@coord, 0, 0, m_Width, m_Height)
      
      Dim hBrush As HBRUSH = CreateSolidBrush(clrBkg)
      If hBRush Then
         FillRect(m_Dc, @coord, hBrush)
         DeleteObject hBrush
      End If
   End If
   
End Sub
'--------------------------------------------------------------------------------
Private Sub yGDI.Pen(ByVal cWidth As Long, ByVal crColor As Long = 0, ByVal iStyle As Long = PS_SOLID) '设置笔，画框线用
   'nPenStyle ------ Long，指定画笔样式，可以是下述常数之一
   'PS_SOLID        画笔画出的是实线
   'PS_DASH         画笔画出的是虚线（nWidth必须不大于1）
   'PS_DOT          画笔画出的是点线（nWidth必须不大于1）
   'PS_DASHDOT      画笔画出的是点划线（nWidth必须不大于1）
   'PS_DASHDOTDOT   画笔画出的是点-点-划线（nWidth必须不大于1）
   'PS_NULL         画笔不能画图
   'PS_INSIDEFRAME  由椭圆、矩形、圆角矩形、饼图以及弦等生成的封闭对象框时，画线宽度向内扩展。如指定的准确RGB颜色不存在，就进行抖动处理
   Dim hOldPen As HGDIOBJ
   If cWidth = 0 Then iStyle = PS_NULL
   nPen = CreatePen(iStyle, cWidth * m_DpiX, crColor) '创建新画笔
   hOldPen = SelectObject(m_Dc, nPen)    '画笔存入DC
   DeleteObject hOldPen    '销毁旧的画笔
End Sub
'--------------------------------------------------------------------------------
Private Sub yGDI.Brush(ByVal crColor As Long) '设置刷子，用于填充颜色
   'crColor 颜色，=-1 创建空画刷子，才能画出空心来
   Dim hOldBrush As HGDIOBJ
   If crColor = -1 Then
      nBrush = GetStockObject(HOLLOW_BRUSH) '创建空画刷子，才能画出空心来
   Else
      nBrush = CreateSolidBrush(crColor)
   End If
   hOldBrush = SelectObject(m_Dc, nBrush)
   DeleteObject hOldBrush
End Sub
'--------------------------------------------------------------------------------
Private Sub yGDI.BrushHatch(fnStyle As Long, crColor As Long = 0) '设置 样式 刷子，用于填充
   'fnStyle
   'HS_BDIAGONAL     从右到左45度 斜纹
   'HS_CROSS         十字线
   'HS_DIAGCROSS    45度十字线
   'HS_FDIAGONAL     从左到右45度 斜纹
   'HS_HORIZONTAL   水平纹
   'HS_VERTICAL     垂直纹
   'crColor 颜色
   Dim hOldBrush As HGDIOBJ
   nBrush = CreateHatchBrush(fnStyle, crColor)
   hOldBrush = SelectObject(m_Dc, nBrush)
   DeleteObject hOldBrush
End Sub

'--------------------------------------------------------------------------------
Private Sub yGDI.DrawLine(ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long)
   Dim nP(1) As Point
   'MoveToEx m_Dc,X1,Y1,@lpPoint             '设置起点
   'LineTo m_Dc,X2,Y2                      '画到终点
   nP(0).x = x1 * m_DpiX
   nP(0).y = y1 * m_DpiY
   nP(1).x = x2 * m_DpiX
   np(1).y = y2 * m_DpiY
   Polyline m_Dc, @nP(0), 2
End Sub
'--------------------------------------------------------------------------------
Private Sub yGDI.DrawArc(ByVal X As Long, ByVal Y As Long, ByVal W As Long, ByVal H As Long, ByVal StartAngle As Single, ByVal EndAngle As Single) '画圆弧
   'x y w h 一个假象的圆，位置和宽度高度
   'StartAngle  相对于x轴的起始角度（以度为单位）。0度为原的右边中部，
   'EndAngle    结束角度
   '
   Dim As Long nXStartArc, nYStartArc, nXEndArc, nYEndArc
   Dim pi As Double = 3.1415926535897932
   Dim As Long zx, zy
   'x=中心x + w半径 * Cos(角度)
   'y=中心y + h半径 * Sin(角度)
   zx = (x + w / 2)
   zy = (y + h / 2)
   nXStartArc = zx + (w / 2) *Cos(StartAngle * pi / 180)
   nYStartArc = zy + (h / 2) *Sin(StartAngle * pi / 180)
   nXEndArc = (x + w / 2) + (w / 2) *Cos(EndAngle * pi / 180)
   nYEndArc = (y + h / 2) + (h / 2) *Sin(EndAngle * pi / 180)
   
   Arc m_Dc, x * m_DpiX, y * m_DpiY, (x + w) * m_DpiX, (y + h) * m_DpiY, nXStartArc, nYStartArc, nXEndArc, nYEndArc
   'AngleArc m_Dc, x, y, x+w,y+h, nXStartArc, nYStartArc,nXEndArc,nYEndArc
   
End Sub
'--------------------------------------------------------------------------------
Private Sub yGDI.DrawFrame(ByVal X As Long, ByVal Y As Long, ByVal W As Long = 0, ByVal H As Long = 0)
   If w = 0 And h = 0 Then
      Rectangle m_Dc, X * m_DpiX, Y * m_DpiY, m_Width -1, m_Height -1
   Else
      Rectangle m_Dc, X * m_DpiX, Y * m_DpiY, (X + W) * m_DpiX, (Y + H) * m_DpiY
   End If   
End Sub
'--------------------------------------------------------------------------------
Private Sub yGDI.DrawEllipse(ByVal X As Long, ByVal Y As Long, ByVal W As Long, ByVal H As Long)
   Ellipse m_Dc, X * m_DpiX, Y * m_DpiY, (X + W) * m_DpiX, (Y + H) * m_DpiY
End Sub
'--------------------------------------------------------------------------------
Private Sub yGDI.DrawCircleFrame(ByVal X As Long, ByVal Y As Long, ByVal W As Long, ByVal H As Long, ByVal wC As Long, ByVal hC As Long) '描绘一个圆角矩形
   RoundRect m_Dc, X * m_DpiX, Y * m_DpiY, (X + W) * m_DpiX, (Y + H) * m_DpiY, wC * m_DpiX, hC * m_DpiY
End Sub
Private Sub yGDI.DrawPolygon(Points() As Point) 'GDI+ 描绘一个多边形
   Dim i As Long, u As Long
   u = UBound(Points)
   ReDim gppp(u) As Point
   For i = 0 To U
      gppp(i).x = Points(i).x *m_DpiX
      gppp(i).y = Points(i).y *m_Dpiy
   Next
   Polygon m_Dc, @gppp(0), U + 1
End Sub
'--------------------------------------------------------------------------------
Private Sub yGDI.Font(fName As CWSTR = "Microsoft YaHei", ByVal fSize As Long = 9, ByVal Bold As UByte = False, Italic As UByte = False, ByVal Underline As UByte = False, ByVal StrikeOut As UByte = False)
   
   Dim oFont As HGDIOBJ
   Dim nDPI As Long, nBold As Long
   If m_DpiX = 1 Then nDPI = 96 Else nDPI = -1
   If Bold Then nBold = FW_BOLD Else nBold = FW_NORMAL
   tFont = AfxCreateFont(**fName, fSize, nDPI, nBold, Italic, Underline, StrikeOut)
   oFont = SelectObject(m_Dc, tFont)
   DeleteObject oFont '销毁老字体
   
End Sub

Private Sub yGDI.DrawStringFC(ByVal X As Long, ByVal Y As Long, nText As CWSTR, tColor As Long, nName As CWSTR = "Microsoft YaHei", ByVal fSize As Long = 9, ByVal Bold As UByte = False) '描绘制指定的文本字符串，带字体和颜色
   This.SetColor tColor
   This.Font nName, fSize, Bold
   This.DrawString X, Y, nText
End Sub
Private Sub yGDI.DrawString(ByVal X As Long, ByVal Y As Long, wText As CWSTR) '描绘制指定的文本字符串

   TextOutW m_Dc, X * m_DpiX, Y * m_DpiY, **wText, Len(wText)

End Sub

'--------------------------------------------------------------------------------
Private Function yGDI.DrawTextFC(X As Long, Y As Long, W As Long, H As Long, nText As CWSTR, uFormat As ULong = 0, tColor As Long, nName As CWSTR = "Microsoft YaHei", ByVal fSize As Long = 9, ByVal Bold As UByte = False) As Long  '指定的矩形中绘制格式化的文本，带字体和颜色，样式为组合，见VFB帮助。
   This.SetColor tColor
   This.Font nName, fSize, Bold
   Function = This.DrawTexts(X, Y, w, h, nText, uFormat)
End Function
Private Function yGDI.DrawTexts(X As Long, Y As Long, W As Long, H As Long, nText As CWSTR, uFormat As ULong = 0) As Long  '指定的矩形中绘制格式化的文本
   'uFormat 指定格式化文本的方法。
   'DT_BOTTOM  将文本对齐到矩形的底部。该值仅与DT_SINGLELINE值一起使用。
   'DT_LEFT    将文本对准左侧。(默认)
   'DT_RIGHT   将文本对齐到右侧。
   'DT_TOP     将文本对齐到矩形的顶部。(默认)
   'DT_CENTER  在矩形中居中文字。
   
   'DT_CALCRECT     返回格式化文本的高度，但不绘制文本。
   'DT_EDITCONTROL  复制多行编辑控件的文本显示特性。具体而言，以与编辑控件相同的方式计算平均字符宽度，并且该函数不显示部分可见的最后一行。
   'DT_END_ELLIPSIS 如果字符串的末尾不适合矩形，则会被截断，并添加省略号。
   'DT_HIDEPREFIX   忽略文本中的＆符号（&）前缀字符。
   'DT_NOPREFIX     关闭前缀字符的处理。
   'DT_INTERNAL     使用系统字体来计算文本度量。
   'DT_MODIFYSTRING 修改指定的字符串以匹配显示的文本。
   'DT_PATH_ELLIPSIS 对于显示的文本，用椭圆替换字符串中间的字符，以使结果符合指定的矩形。
   'DT_RTLREADING   右向左阅读顺序布局
   'DT_SINGLELINE   仅在一行上显示文字。
   'DT_TABSTOP      设置制表位。
   'DT_VCENTER      纵向中心文本。该值仅与DT_SINGLELINE值一起使用。
   'DT_WORDBREAK    自动换行
   'DT_WORD_ELLIPSIS 截断任何不适合矩形的单词并添加省略号。
   
   Dim rr As rect
   rr.Left = x *m_DpiX
   rr.top = y * m_DpiY
   rr.Right = (x + w) *m_DpiX
   rr.bottom = (y + h) * m_DpiY
   Function = DrawTextW (m_Dc, **nText, -1, @rr, uFormat)
End Function

'--------------------------------------------------------------------------------
Private Sub yGDI.DrawFrameStr(ByVal X As Long, ByVal Y As Long, nText As CWSTR) '描绘描边字，轮廓字，轮廓先设置笔，字为正常字
   BeginPath(m_Dc) ';//开始轨迹
   TextOutW  m_Dc, X * m_DpiX, Y * m_DpiY, **nText, Len(nText)
   'FlattenPath(m_Dc) ';//用直线封闭轨迹
   EndPath(m_Dc) ';//结束轨迹
   StrokePath(m_Dc) ' ;  //画出轨迹
   'FillPath(gg.m_Dc) ' ;  //画出轨迹
   TextOutW  m_Dc, X * m_DpiX, Y * m_DpiY, **nText, Len(nText) '再画字
End Sub
'--------------------------------------------------------------------------------
Private Sub yGDI.DrawFrameStrR(ByVal X As Long, ByVal Y As Long, nText As CWSTR, ByVal bColor As Long) '绕写方式的轮廓字
   
   Dim xi As Long, yi As Long, tColor As Long
   Dim As Long tX, tY
   tx = X * m_DpiX
   ty = Y * m_DpiY
   tColor = GetTextColor(m_Dc)
   SetTextColor m_Dc, bColor
   For xi = -1 To 1
      For yi = -1 To 1
         TextOutW  m_Dc, tx + xi, ty + yi, **nText, Len(nText) '再画字
      Next
   Next
   SetTextColor m_Dc, tColor
   TextOutW  m_Dc, tX, tY, **nText, Len(nText) '再画字
   
End Sub
'--------------------------------------------------------------------------------
Private Sub yGDI.DrawFrameText(X As Long, Y As Long, W As Long, H As Long, nText As CWSTR, uFormat As ULong = 0) '描绘描边字，轮廓字，轮廓先设置笔，字为正常字
   Dim rr As rect
   SetRect @rr, x *m_DpiX, y * m_DpiY, (x + w) *m_DpiX, (y + h) * m_DpiY
   BeginPath(m_Dc) ';//开始轨迹
   DrawTextW  m_Dc, **nText, Len(nText), @rr, uFormat
   'FlattenPath(m_Dc) ';//用直线封闭轨迹
   EndPath(m_Dc) ';//结束轨迹
   StrokePath(m_Dc) ' ;  //画出轨迹
   'FillPath(gg.m_Dc) ' ;  //画出轨迹
   DrawTextW  m_Dc, **nText, Len(nText), @rr, uFormat '再画字
End Sub
'--------------------------------------------------------------------------------
Private Sub yGDI.DrawFrameTextR(X As Long, Y As Long, W As Long, H As Long, nText As CWSTR, bColor As Long, uFormat As ULong = 0) '绕写方式的轮廓字
   Dim rr As rect
   Dim xi As Long, yi As Long, tColor As Long
   Dim As Long tX, tY, nX, nY
   tx = X * m_DpiX
   ty = Y * m_DpiY
   nx = (x + w) *m_DpiX
   ny = (y + h) * m_DpiY
   tColor = GetTextColor(m_Dc)
   SetTextColor m_Dc, bColor
   For xi = -1 To 1
      For yi = -1 To 1
         SetRect @rr, tx + xi, ty + yi, nx + xi, ny + yi
         DrawTextW  m_Dc, **nText, Len(nText), @rr, uFormat '画字
      Next
   Next
   SetTextColor m_Dc, tColor
   SetRect @rr, tx, ty, nx, ny
   DrawTextW  m_Dc, **nText, Len(nText), @rr, uFormat '再画字
End Sub
'--------------------------------------------------------------------------------
Private Sub yGDI.SetColor(ByVal tColor As Long, ByVal bColor As Long = -1)
   'bColor=-1  文字背景不设置，画字是透明的。
   SetTextColor m_Dc, tColor
   If bColor = -1 Then
      SetBkMode m_Dc, TRANSPARENT  '背景保持不变,设置这个后，画上的字是透明的
   Else
      SetBkMode m_Dc, OPAQUE  '在绘制文本，阴影画笔或钢笔之前，背景填充当前的背景颜色。
      SetBkColor m_Dc, bColor
      
   End If
End Sub
'--------------------------------------------------------------------------------
Private Sub yGDI.InvertPixels(X As Long, Y As Long, W As Long, H As Long) '将指定的矩形中像素颜色翻转
   Dim rr As rect
   SetRect @rr, x *m_DpiX, y * m_DpiY, (x + w) *m_DpiX, (y + h) * m_DpiY
   InvertRect m_Dc, @rr
   
End Sub
'--------------------------------------------------------------------------------
Private Function yGDI.GetPixel(ByVal x As Long, ByVal y As Long) As Long
   Function = .GetPixel(m_Dc, x, y)
End Function
'--------------------------------------------------------------------------------
Private Function yGDI.SetPixel(ByVal x As Long, ByVal y As Long, ByVal crColor As Long) As Long
   Function = .SetPixel(m_Dc, x, y, crColor) '返回原来像素点的颜色
End Function
'--------------------------------------------------------------------------------
Private Sub yGDI.DrawImgRes(hInst As HINSTANCE, ResName As CWSTR, X As Long, Y As Long, W As Long = 0, H As Long = 0, dimPercent As Long = 0, bGrayScale As Long = False) '画资源里的图片
   'ResName  图像库中图像的名称。只有嵌入为原始数据（RCDATA类型）的图像才有效。 必须是格式为.png，.jpg，.gif，.tiff的图
   'dimPercent     [in] 调光的百分比 (1-99)
   'bGrayScale     [in] True 或 False. 转换成灰度.
   Dim nWidth As Long, nHeight As Long, bm As BITMAP
   '将图像加载为位图
   Dim hbmp As HICON = AfxGdipIconFromRes(hInst, **ResName, dimPercent, bGrayScale)
   If hbmp Then
      DrawIconEx m_Dc, x *m_DpiX, y * m_DpiY, hbmp, w *m_DpiX, h * m_DpiY, Null, Null, DI_NORMAL
      DestroyIcon hbmp
   End If
   
End Sub
'--------------------------------------------------------------------------------
Private Sub yGDI.DrawImgFile(FileName As CWSTR, X As Long, Y As Long, W As Long = 0, H As Long = 0, dimPercent As Long = 0, bGrayScale As Long = False) '画资源里的图片
   'FileName  文件的绝对路径 必须是格式为.png，.jpg，.gif，.tiff的图
   'dimPercent     [in] 调光的百分比 (1-99)
   'bGrayScale     [in] True 或 False. 转换成灰度.
   Dim nWidth As Long, nHeight As Long, bm As BITMAP
   '将图像加载为位图
   Dim hbmp As HICON = AfxGdipIconFromFile(**FileName, dimPercent, bGrayScale)
   If hbmp Then
      DrawIconEx m_Dc, x *m_DpiX, y * m_DpiY, hbmp, w *m_DpiX, h * m_DpiY, Null, Null, DI_NORMAL
      DestroyIcon hbmp
   End If
   
End Sub
'--------------------------------------------------------------------------------
Private Sub yGDI.DrawIcoRes(hInst As HINSTANCE, ResName As CWSTR, X As Long, Y As Long, W As Long = 0, H As Long = 0) '画资源里的图标
   'ResName  图像库中图标的名称。 必须是格式为.ico
   Dim nICON As HICON = LoadIconW (hInst, ResName.vptr)
   DrawIconEx m_DC, x *m_DpiX, y * m_DpiY, nICON, w *m_DpiX, h * m_DpiY, Null, Null, DI_NORMAL
   DestroyIcon nICON
End Sub
'========================================================================================
'将位图保存到文件。
'参数:
'- wszFileName = 要保存的图像的路径名称。
'- wszMimeType = MIME类型 (默认: "image/bmp").
'"image/bmp" = Bitmap (.bmp)
'"image/gif" = GIF (.gif)
'"image/jpeg" = JPEG (.jpg)
'"image/png" = PNG (.png)
'"image/tiff" = TIFF (.tiff)
'返回值:
'如果方法成功，则返回Ok，它是Status枚举的一个元素。
'如果方法失败，它将返回Status枚举的其他元素之一。
'========================================================================================
Private Function yGDI.SaveBitmap(ByRef wszFileName As CWSTR, ByRef wszMimeType As CWSTR = "image/bmp") As Long
   Function = AfxGdipSaveHBITMAPToFile(m_Bmp, **wszFileName, **wszMimeType)
End Function
'--------------------------------------------------------------------------------
Private Sub yGDI.LoadImgRes(hInst As HINSTANCE, ResName As CWSTR, dimPercent As Long = 0, bGrayScale As Long = False, clrBackground AS ARGB = 0) '加载图像到 m_bDc ，便于后面重复使用，再次加载将消耗前面加载的。
   'FileName  文件的绝对路径 必须是格式为.png，.jpg，.gif，.tiff的图
   'dimPercent     [in] 调光的百分比 (1-99)
   'bGrayScale     [in] True 或 False. 转换成灰度.
   Dim bm As BITMAP
   '将图像加载为位图
   If m_hBmp2 Then DeleteObject m_hBmp2
   If m_bDc Then DeleteDC m_bDc
   
   m_hBmp2 = AfxGdipBitmapFromRes(hInst, **ResName, dimPercent, bGrayScale, clrBackground)
   If m_hBmp2 Then
      '检索位图的宽度和高度
      If GetObject(m_hBmp2, SizeOf(BITMAP), @bm) Then
         m_ImgWidth = bm.bmWidth
         m_ImgHeight = bm.bmHeight
      End If
      m_bDc = CreateCompatibleDC(m_Dc)
      DeleteObject SelectObject(m_bDc, m_hBmp2)
   End If
End Sub
Private Sub yGDI.LoadBmpRes(hInst As HINSTANCE, ResName As CWSTR, dimPercent As Long = 0, bGrayScale As Long = False) '加载图像到 m_bDc ，便于后面重复使用，再次加载将消耗前面加载的。
   'FileName  文件的绝对路径 必须是格式为.png，.jpg，.gif，.tiff的图
   'dimPercent     [in] 调光的百分比 (1-99)
   'bGrayScale     [in] True 或 False. 转换成灰度.
   Dim bm As BITMAP
   '将图像加载为位图
   If m_hBmp2 Then DeleteObject m_hBmp2
   If m_bDc Then DeleteDC m_bDc
   m_hBmp2 = LoadImageW(hInst, **ResName, IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR or LR_DEFAULTSIZE or IIf(bGrayScale, LR_MONOCHROME, 0))
     If m_hBmp2 Then
      '检索位图的宽度和高度
      If GetObject(m_hBmp2, SizeOf(BITMAP), @bm) Then
         m_ImgWidth = bm.bmWidth
         m_ImgHeight = bm.bmHeight
      End If
      m_bDc = CreateCompatibleDC(m_Dc)
      DeleteObject SelectObject(m_bDc, m_hBmp2)
   End If
End Sub
'--------------------------------------------------------------------------------
Private Sub yGDI.LoadImgFile(FileName As CWSTR, dimPercent As Long = 0, bGrayScale As Long = False, clrBackground AS ARGB = 0) '加载图像到 m_bDc ，便于后面重复使用，再次加载将消耗前面加载的。
   'FileName  文件的绝对路径 必须是格式为.png，.jpg，.gif，.tiff的图
   'dimPercent     [in] 调光的百分比 (1-99)
   'bGrayScale     [in] True 或 False. 转换成灰度.
   Dim bm As BITMAP
   '将图像加载为位图
   If m_hBmp2 Then DeleteObject m_hBmp2
   If m_bDc Then DeleteDC m_bDc
   m_hBmp2 = AfxGdipBitmapFromFile(**FileName, dimPercent, bGrayScale, clrBackground)
   If m_hBmp2 Then
      '检索位图的宽度和高度
      If GetObject(m_hBmp2, SizeOf(BITMAP), @bm) Then
         m_ImgWidth = bm.bmWidth
         m_ImgHeight = bm.bmHeight
      End If
      'print "检索位图的宽度和高度", m_ImgWidth,m_ImgHeight
      m_bDc = CreateCompatibleDC(m_Dc)
      DeleteObject SelectObject(m_bDc, m_hBmp2)
   End If
End Sub
'--------------------------------------------------------------------------------
Private Sub yGDI.DrawCopyImg(xDest As Long, yDest As Long, wDest As Long, hDest As Long, xSrc As Long, ySrc As Long, wSrc As Long, hSrc As Long, rop As DWord = SrcCopy) '描绘由LoadImg加载来的图
   'xywh Dest 目标  xywh Src 源
   'rop 光栅操作代码
   'BLACKNESS：表示使用与物理调色板的索引0相关的色彩来填充目标矩形区域，（对缺省的物理调色板而言，该颜色为黑色）。
   'DSTINVERT：表示使目标矩形区域颜色取反。
   'MERGECOPY：表示使用布尔型的And（与）操作符将源矩形区域的颜色与特定模式组合一起。
   'MERGEPAINT：通过使用布尔型的Or（或）操作符将反向的源矩形区域的颜色与目标矩形区域的颜色合并。
   'NOTSRCCOPY：将源矩形区域颜色取反，于拷贝到目标矩形区域。
   'NOTSRCERASE：使用布尔类型的Or（或）操作符组合源和目标矩形区域的颜色值，然后将合成的颜色取反。
   'PATCOPY：将特定的模式拷贝到目标位图上。
   'PATPAINT：通过使用布尔Or（或）操作符将源矩形区域取反后的颜色值与特定模式的颜色合并。然后使用Or（或）操作符将该操作的结果与目标矩形区域内的颜色合并。
   'PATINVERT：通过使用Xor（异或）操作符将源和目标矩形区域内的颜色合并。
   'SRCAND：通过使用And（与）操作符来将源和目标矩形区域内的颜色合并。
   'SRCCOPY：将源矩形区域直接拷贝到目标矩形区域。
   'SRCERASE：通过使用And（与）操作符将目标矩形区域颜色取反后与源矩形区域的颜色值合并。
   'SRCINVERT：通过使用布尔型的Xor（异或）操作符将源和目标矩形区域的颜色合并。
   'SRCPAINT：通过使用布尔型的Or（或）操作符将源和目标矩形区域的颜色合并。
   'WHITENESS：使用与物理调色板中索引1有关的颜色填充目标矩形区域。（对于缺省物理调色板来说，这个颜色就是白色）。
   SetStretchBltMode m_Dc, HALFTONE  'COLORONCOLOR
   StretchBlt(m_Dc, xDest *m_DpiX, yDest *m_DpiY, wDest *m_DpiX, hDest *m_DpiY, m_bDc, xSrc, ySrc, wSrc, hSrc, rop)
End Sub
'--------------------------------------------------------------------------------
Private Sub yGDI.DrawCopyImgAlpha(xDest As Long, yDest As Long, wDest As Long, hDest As Long, xSrc As Long, ySrc As Long, wSrc As Long, hSrc As Long, TeMeDu As Long) '半透明 描绘由LoadImg加载来的图
   'xywh Dest 目标  xywh Src 源
   'TeMeDu 透明度，百分比， 0 不透明 100 完成透明
   'Dim nAlpha As Long = (100-TeMeDu)*2.55
   Dim ftn As BLENDFUNCTION
   ftn.BlendOp = 0       '这个参数必须也只能为AC_SRC_OVER(0x00),意思就是把源图片覆盖到目标之上.
   ftn.BlendFlags = 0     '必须为0
   ftn.SourceConstantAlpha = (100 - TeMeDu) * 2.55 '简写为SCA,指定源图片的透明度,这个值是会和源图片的Alpha通道值合并计算的.，0为完全透明，255为完全不透明
   ftn.AlphaFormat = 0  '可以填两种,一种是0x00,一种是AC_SRC_ALPHA(0x01).
   AlphaBlend(m_Dc, xDest *m_DpiX, yDest *m_DpiY, wDest *m_DpiX, hDest *m_DpiY, m_bDc, xSrc, ySrc, wSrc, hSrc, ftn)
End Sub
'--------------------------------------------------------------------------------
Private Sub yGDI.DrawCopyImgColor(xDest As Long, yDest As Long, wDest As Long, hDest As Long, xSrc As Long, ySrc As Long, wSrc As Long, hSrc As Long, tColor As Long) '扣色 描绘由LoadImg加载来的图
   'xywh Dest 目标  xywh Src 源
   'tColor 将源位图中的RGB颜色视为透明，扣除此色
   TransparentBlt(m_Dc, xDest *m_DpiX, yDest *m_DpiY, wDest *m_DpiX, hDest *m_DpiY, m_bDc, xSrc, ySrc, wSrc, hSrc, tColor)
End Sub

'--------------------------------------------------------------------------------
Private Sub yGDI.GpPen(ByVal nWidth As REAL, ByVal nColor As ARGB = &HFF000000) 'GDI+ 设置笔，画框线用 基本笔，颜色和笔粗
   '宽度=0 不画线
   If nGpPen Then GdipDeletePen nGpPen
   If nWidth < 1 Then
      nGpPen = 0
   Else
      GdipCreatePen1 nColor, nWidth *m_DpiX, 2, @nGpPen
   End If
End Sub
'--------------------------------------------------------------------------------
Private Sub yGDI.GpArrowCap(W As REAL, H As REAL, isFilled As BOOL, W2 As REAL = 0, H2 As REAL = 0) 'GDI+ 给笔设置起点或终点的箭头键帽，宽高和填充，
   If nGpPen Then
      Dim As GpCustomLineCap Ptr sGpCap,eGpCap  '创建键帽
      if w2 > 0 and h2 > 0 then
         GdipCreateAdjustableArrowCap w2, h2, isFilled, Cast(Any Ptr, @sGpCap)
         GdipSetPenCustomStartCap nGpPen, sGpCap
         GdipDeleteCustomLineCap sGpCap
      end if
      if w > 0 and h > 0 then
         GdipCreateAdjustableArrowCap w, h, isFilled, Cast(Any Ptr, @eGpCap)
         GdipSetPenCustomEndCap nGpPen, eGpCap
         GdipDeleteCustomLineCap eGpCap
      end if
   End If
End Sub


'--------------------------------------------------------------------------------
Private Sub yGDI.GpBrush(ByVal nColor As ARGB = 0) 'GDI+ 设置刷子，用于填充颜色 0为空刷子
   '当nColor=0 空刷子,取消填充,就是不填充
   If nGpBrush Then GdipDeleteBrush nGpBrush 'GDI+ 纯色刷
   
   If nColor Then
      'If nGpBrush Then
      'GdipSetSolidFillColor Cast(GpSolidFill Ptr, nGpBrush), nColor
      'Else
      GdipCreateSolidFill nColor, Cast(GpSolidFill Ptr Ptr, @nGpBrush)
      'End If
   Else
      
      nGpBrush = 0
   End If
   'Print "填充颜色"
End Sub
'--------------------------------------------------------------------------------
Private Sub yGDI.GpBrushGradient(X1 As Long, Y1 As Long, X2 As Long, Y2 As Long, Color1 As ARGB, Color2 As ARGB, WrapMode As Long = WrapModeTileFlipXY) 'GDI+ 渐变
   '从 XY1 到 XY2 渐变，颜色是 Color1 到 Color2，当不够填充目标时，WrapMode 设置平铺方式
   'WrapMode 平铺
   'WrapModeTile        =0 平铺而不翻转
   'WrapModeTileFlipX   =1 平铺水平翻转
   'WrapModeTileFlipY   =2 平铺垂直翻转
   'WrapModeTileFlipXY  =3 平铺垂直翻转，平铺水平翻转
   'WrapModeClamp       =4 不进行平铺
   If nGpBrush Then GdipDeleteBrush nGpBrush 'GDI+ 刷
   Dim As GpPointF point1, point2
   point1.x = x1 *m_DpiX
   point1.y = y1 *m_DpiY
   point2.x = x2 *m_DpiX
   point2.y = y2 *m_DpiY
   GdipCreateLineBrush @point1, @point2, Color1, Color2, WrapMode, Cast(GpLineGradient Ptr Ptr, @nGpBrush)
End Sub
'--------------------------------------------------------------------------------
Private Sub yGDI.GpDrawLine(X1 As Single, Y1 As Single, X2 As Single, Y2 As Single) 'GDI+ 画线
   If nGpPen Then GdipDrawLine m_GpDC, nGpPen, X1 *m_DpiX, Y1 *m_DpiY, X2 *m_DpiX, Y2 *m_DpiY
End Sub
'--------------------------------------------------------------------------------
Private Sub yGDI.GpDrawArc(X As Single, Y As Single, W As Single, H As Single, StartAngle As Single, sweepAngle As Single) 'GDI+ 画圆弧
   'x y w h 一个假象的圆，位置和宽度高度
   'StartAngle  相对于x轴的起始角度（以度为单位）。0度为圆的右边中部，
   'sweepAngle  指定弧线起始点和终点之间的角度。
   '
   If nGpBrush Then GdipFillPie m_GpDC, nGpBrush, X *m_DpiX, Y *m_DpiY, W *m_DpiX, H *m_DpiY, StartAngle, sweepAngle
   If nGpPen Then GdipDrawArc m_GpDC, nGpPen, X *m_DpiX, Y *m_DpiY, W *m_DpiX, H *m_DpiY, StartAngle, sweepAngle
End Sub
'--------------------------------------------------------------------------------
Private Sub yGDI.GpDrawFrame(X As Single, Y As Single, W As Single, H As Single)
   If nGpBrush Then GdipFillRectangle m_GpDC, nGpBrush, X *m_DpiX, Y *m_DpiY, W *m_DpiX, H *m_DpiY
   If nGpPen Then GdipDrawRectangle m_GpDC, nGpPen, X *m_DpiX, Y *m_DpiY, W *m_DpiX, H *m_DpiY
End Sub
'--------------------------------------------------------------------------------
Private Sub yGDI.GpDrawCircleFrame(X As Single, Y As Single, W As Single, H As Single, wC As Single, hC As Single) 'GDI+ 描绘一个圆角矩形
   'wC hC 是圆角半径，像素
   
   If nGpBrush Then
      '填充2个直角矩形
      GdipFillRectangle m_GpDC, nGpBrush, X *m_DpiX, (Y + hC) *m_DpiY -1, W *m_DpiX, (H - hC * 2) *m_DpiY + 2
      GdipFillRectangle m_GpDC, nGpBrush, (X + wc) *m_DpiX -1, Y *m_DpiY, (W - wC * 2) *m_DpiX + 2, H *m_DpiY
      '填充四个角上的扇形区
      '填充左上角扇形
      GdipFillPie m_GpDC, nGpBrush, X *m_DpiX, Y *m_DpiY, Wc * 2 *m_DpiX, hc * 2 *m_DpiY, 180, 90
      '填充右下角的扇形
      GdipFillPie m_GpDC, nGpBrush, (X + w - wC * 2) *m_DpiX, (Y + h - hc * 2) *m_DpiY, Wc * 2 *m_DpiX, hc * 2 *m_DpiY, 360, 90
      '填充右上角的扇形
      GdipFillPie m_GpDC, nGpBrush, (X + w - wC * 2) *m_DpiX, Y *m_DpiY, Wc * 2 *m_DpiX, hc * 2 *m_DpiY, 270, 90
      '填充左下角的扇形
      GdipFillPie m_GpDC, nGpBrush, X *m_DpiX, (Y + h - hc * 2) *m_DpiY, Wc * 2 *m_DpiX, hc * 2 *m_DpiY, 90, 90
   End If
   '画矩形上面的边
   This.GpDrawLine(x + wc, y, w - wc + x, y)
   '画矩形下面的边
   This.GpDrawLine(x + wC, y + h, W - wC + x, y + h)
   '画矩形左面的边
   This.GpDrawLine(x, y + hC, x, y + h - hC)
   '画矩形右面的边
   This.GpDrawLine(x + w, y + hc, x + w, y + h - hC)
   '画矩形左上角的圆角
   This.GpDrawArc(x, y, wC * 2, hC * 2, 180, 90)
   '画矩形右下角的圆角
   This.GpDrawArc(x + w - wC * 2, y + h - hC * 2, wC * 2, hC * 2, 360, 90)
   '画矩形右上角的圆角
   This.GpDrawArc(x + w - wC * 2, y, wC * 2, hC * 2, 270, 90)
   '画矩形左下角的圆角
   This.GpDrawArc(x, y + h - hC * 2, wC * 2, hC * 2, 90, 90)
End Sub
'--------------------------------------------------------------------------------
Private Sub yGDI.GpDrawEllipse(X As Single, Y As Single, W As Single, H As Single) 'GDI+ 描绘一个椭圆
   If nGpBrush Then GdipFillEllipse m_GpDC, nGpBrush, X *m_DpiX, Y *m_DpiY, W *m_DpiX, H *m_DpiY
   If nGpPen Then GdipDrawEllipse m_GpDC, nGpPen, X *m_DpiX, Y *m_DpiY, W *m_DpiX, H *m_DpiY
End Sub
'--------------------------------------------------------------------------------
Private Sub yGDI.GpDrawPolygon(Points() As Point,fillMode As  Long=0) 'GDI+ 描绘一个多边形
   Dim i As Long, u As Long
   u = UBound(Points)
   ReDim gppp(u) As GpPoint
   For i = 0 To U
      gppp(i).x = Points(i).x *m_DpiX
      gppp(i).y = Points(i).y *m_Dpiy
   Next
   If nGpBrush Then GdipFillPolygonI m_GpDC, nGpBrush, @gppp(0), U + 1,fillMode
   If nGpPen Then GdipDrawPolygonI m_GpDC, nGpPen, @gppp(0), U + 1
End Sub
'--------------------------------------------------------------------------------
Private Function yGDI.GpLoadImgFile(FileName As CWSTR) As Long '加载文件图像到 nGpimage ，便于后面重复使用，再次加载将消耗前面加载的。
   If nGpimage Then GdipDisposeImage nGpimage

   Function = GdipLoadImageFromFile(**FileName, @nGpimage)
   '成功 返回=0  ，失败
   'Print nGpimage
End Function
'--------------------------------------------------------------------------------
Private Function yGDI.GpLoadImgRes(hInst As HINSTANCE, ResName As CWSTR) As Long '加载资源图像到 nGpimage ，便于后面重复使用，再次加载将消耗前面加载的。
   If nGpimage Then GdipDisposeImage nGpimage
   Dim hRes As HRSRC, pResData As HRSRC, wID As WORD, dwID As DWord, imageSize As DWord
   Dim pImageStream As IStream Ptr, hGlobal As HGLOBAL, pGlobalBuffer As LPVOID
   '找资源
   If Left(**ResName, 1) = "#" Then
      wID = Val(Mid(**ResName, 2))
      dwID = MAKELONG(wID, 0)
      hRes = FindResourceW(hInst, Cast(LPCWSTR, MAKEINTRESOURCEW(dwID)), Cast(LPCWSTR, RT_RCDATA))
   Else
      hRes = FindResourceW(hInst, ResName.vptr, Cast(LPCWSTR, RT_RCDATA)) '查找资源
   End If
   Function = 1
   If hRes Then '检索图像的大小
      imageSize = SizeofResource(hInst, hRes) '获取长度
      If imageSize Then
         '加载资源并获取指向资源数据的指针。
         pResData = LockResource(LoadResource(hInst, hRes))
         If pResData Then
            hGlobal = GlobalAlloc(GMEM_MOVEABLE, imageSize) '分配内存以保存图像
            If hGlobal Then
               pGlobalBuffer = GlobalLock(hGlobal) '锁定内存
               If pGlobalBuffer Then
                  CopyMemory(pGlobalBuffer, pResData, imageSize) '将图像从二进制字符串文件复制到全局内存
                  If CreateStreamOnHGlobal(hGlobal, False, @pImageStream) = S_OK Then '在全局内存中创建一个流
                     If pImageStream Then
                        Function = GdipCreateBitmapFromStream(pImageStream, Cast(GpBitmap Ptr Ptr, @nGpimage)) '根据流中包含的数据创建一个位图
                        pImageStream->lpVtbl->Release(pImageStream)
                     End If
                  End If
                  GlobalUnlock pGlobalBuffer '解锁内存
               End If
               GlobalFree hGlobal '释放内存
            End If
         End If
      End If
   End If
   '成功 返回=0  ，失败
   'Print nGpimage
   
End Function
'--------------------------------------------------------------------------------
Private Sub yGDI.GpDrawCopyImg(xDest As Single, yDest As Single, wDest As Single, hDest As Single, xSrc As Single, ySrc As Single, wSrc As Single, hSrc As Single) '描绘由LoadImg加载来的图
   GdipDrawImageRectRect m_GpDC, nGpimage, _
      xDest *m_DpiX, yDest *m_DpiY, wDest *m_DpiX, hDest *m_DpiY, _
      xSrc, ySrc, wSrc, hSrc, _
      2, Null, Null, Null
   'srcunit  [in]单位枚举的元素，用于指定图像的度量单位。默认值为UnitPixel.
   'imageAttributes  [in]指向ImageAttributes结构的指针，用于指定要绘制的图像的颜色和大小属性。默认值为NULL。
   'callback        [in]用于取消正在进行的绘图的回调函数。默认值为NULL。
   'callbackData     [in]指向由回调参数指定的函数使用的附加数据的指针。默认值为NULL。
   '如果函数成功，则返回Ok，它是状态枚举的一个元素
   
End Sub
'--------------------------------------------------------------------------------
Private Sub yGDI.GpDrawFrameStr(X As Single, Y As Single, nText As CWSTR, hFont As CWSTR = "Microsoft YaHei", hSize As Long = 9) '描绘带轮廓文本字符串
   'hSize GDI+里的度量与 GDI的字体不同，9号字大概等于 12 emSize
   'emSize= lp* 1.5208
   'lp=emSize/1.5208
   Dim nPath As GpPath Ptr
   Dim fontFamily As GpFontFamily Ptr
   Dim rc As Rect
   rc.Left = x *m_DpiX
   rc.top = y *m_DpiY
   rc.Right = x *m_DpiX + m_Width
   rc.bottom = y *m_DpiY + m_Height

   GdipCreateFontFamilyFromName **hFont, Null, @fontFamily '创建一个基于指定的字体系列的FontFamily对象
   'Dim nFormat As GpStringFormat Ptr
   'GdipCreateStringFormat(0, 0, @nformat) '创建一个基于字符串的格式标志和语言的 StringFormat 对象
   'GdipSetStringFormatAlign(nformat, StringAlignmentNear)  '设置文本对齐方式
   
   GdipCreatePath FillModeAlternate, @nPath '创建路径

   '把文字植入路径里
   GdipAddPathStringi(nPath,**nText, Len(nText), fontFamily, FontStyleRegular, hSize * 1.5208, Cast(Any Ptr, @rc), Null)
   If nGpPen Then GdipDrawPath(m_GpDC, nGpPen, nPath)
   If nGpBrush Then GdipFillPath m_GpDC, nGpBrush, nPath
   
   'GdipDeleteStringFormat(nFormat) '销毁指定StringFormat对象，释放资源
   GdipDeleteFontFamily(fontfamily) '销毁指定FontFamily对象，释放资源
   GdipDeletePath nPath
End Sub
Private Function yGDI.GetTextWidth(nText as CWSTR) as Long '获取文本显示宽度，自动支持DPI感知，为 100% DPI 时的数字。假如 DPI比率=1 则是实际像素值
   Dim s As SIZE
   GetTextExtentPoint32W m_Dc, **nText, Len( nText), @s
   if m_DpiX = 1 Then
      Function = s.cx
   Else
      Function = AfxUnscaleX(s.cx)
   end if
End Function
Private Function yGDI.GetTextHeight(nText as CWSTR) as Long '获取文本显示高度，自动支持DPI感知，为 100% DPI 时的数字。假如 DPI比率=1 则是实际像素值
   Dim s As SIZE
   GetTextExtentPoint32W m_Dc, **nText, Len(nText), @s
   if m_DpiX = 1 Then
      Function = s.cy
   Else
      Function = AfxUnscaleX(s.cy)
   end if
End Function
