光标函数简介,创建Color光标、Alpha光标、ShowCursor

来源:互联网 发布:本地telnet不通80端口 编辑:程序博客网 时间:2024/05/17 23:02

 转载请标明是引用于 http://blog.csdn.net/chenyujing1234    


以下给出了有关图标和指针的API函数

函    数                              说    明
CopyCursor                 复制指针,使用CopyIcon
CopyIcon                     复制图表。
CreateCursor              创建指针
CreateIcon                 创建图表
CreateIconIndirect      在一个ICONINFO结构的基础上创建一个图标
DestroyCursor            清除指针
DestroyIcon               清除图表
DrawIcon                    向指定设备场景绘制图标
DrawIconEx                用附加的选项描绘图标
ExtractIcon                 从一个可执行文件或DLL中载入图标
ExtractAssociatedIcon 载入指定文件内部或与它相关的一个图标
GetIconInfo                 取得关于图标的信息
LoadCursor                 从一个资源文件中载入指针,或者装载一个固有系统指针。
LoadCursorFromFile    通过读取标准指针文件(.cur)或动画指针(.ani)创建指针
LoadIcon                    从一个资源文件中载入图表,或载入一个固有系统图标。




CreateCursor


函数功能:该函数创建一个指定大小、位模式和热点的光标。
函数原型:HCURSOR CreateCursor(HINSTANCE htnst,int xHotSpot;int yHotSpot;int nWidth;int nHeight,CONST VOID *pvANDPlane,CONST VOID *pvXORPlane);
参数:
hlnst:创建光标的应用程序的当前事例句柄。
xHotSpot:指定光标热点的水平位置。
yHotSpot:指定光标热点的垂直位置。
nWidth:以像素为单位指定光标的宽度
nHeight:以像素为单位指定光标的高度。
pvANDPlane:指向一个字节数组的指针,该数组包含光标AND掩码的位值,就象设备相关的单色位图一样。
pvXORPlane:指向一个字节数组的指针,该数组包含光标XOR掩码的位值,就象设备相关的单色位图一样。
返回值:如果成功,返回光标的值;如果失败,返回值为NULL(空),若想获得更多错误信息,调用GetLastError函数。
备注:nWidth和nHeight参数必须指定一个当前显示驱动支持的宽度和高度,因为系统不能创建一个其他尺寸的光标,为了确定显示驱动所支持的宽度和高度,请使用GetSystemMetrics函数,指定SM_CXCUROR或SM_CYCURSOR值。在一个应用程序关闭之前,必须调用DestroyCursor函数来释放与光标有关的任何系统资源。

二、 VC6.0实现鼠标光标形状及大小的定制

用VC开发的Windows应用程序时,可以分四步对窗口上的鼠标光标进行定制:

手工编辑Cursor、定义Cursor变量、加载Cursor变量、控制Cursor行为。

每个步骤的详细说明如下:
(1)手工编辑Cursor。在资源编辑器里增加一个Cursor,VC会自动给它分配一个ID(比如:IDC_CURSOR1),然后手工编辑Cursor的形状,编辑好后保存一下。你会看到Cursor的属性框中,有一个File name项里标明了该Cursor资源的文件路径(res\cursor1.cur)
(2)定义Cursor变量。定义一个HCURSOR类型的变量myCursor,存放Cursor对象。
  HCURSOR myCursor;
(3)加载Cursor变量。在你需要改变鼠标光标的函数里添加Cursor的加载代码,将定义好的Cursor资源加载到前面的Cursor变量里,如果想程序一开始就自动显示个性化定制的鼠标光标,则在初始化函数(如:对话框初始化函数OnInitDialog)里加载Cursor。VC加载Cursor的办法很多,可以用CWinApp::LoadCursor加载,也可以用Windows API中的LoadCursor加载。但这两种办法都只能改变Cursor的形状,不能改变大小。如果需要改变大小就只能用LoadImage,代码如下:
   myCursor=(HCURSOR)LoadImage(NULL,"res/cursor1.cur",IMAGE_CURSOR,72,32,LR_LOADFROMFILE );
 这是一个比较复杂的Windows API函数,有六个参数。可以向内存中加载位图、ICON和Cursor。函数原型如下
HANDLE LoadImage(
HINSTANCE hinst,
| LPCTSTR lpszName, 
UINT uType, 
int cxDesired, 
int cyDesired, 
UINT fuLoad );

下面只解释与加载Cursor相关的参数用法:

  hinst:指向需加载该资源的module,(我还不太清楚module的确切函义,是一个程序,还是一个进程,还是一个库),不过一般可以将这个参数设为NUll。
  lpszName:标识要加载的资源,
如果fuLoad设为LR_LOADFROMFILE,则该参数为资源的文件名,如位图文件、ICON文件,当然也包括Cursor文件。
  uType:指明加载的资源类型,它的值可以是IMAGE_BITMAP. 加载位图;IMAGE_CURSOR. 加载cursor;IMAGE_ICON. 加载ICON
  cxDesired,光标的宽度,值是
以像素为单位的整数。
  cyDesired ,光标的长度,值是以像素为单位的整数。
  fuLoad,资源加载的方式,当值为LR_LOADFROMFILE时,指从文件加载

(4)控制Cursor行为。最终控制Cursor的行为要通过OnSetCursor函数来实现。用ClassWizard为你需要改变鼠标光标的窗口对象(CWin的子类),添加OnSetCursor函数来处理窗口的ON_WM_SETCURSOR消息。程序运行时,只要鼠标进入到该窗口的区域,Windows就会给该窗口对象发送ON_WM_SETCURSOR消息,并触发你的OnSetCursor函数。所以可以在OnSetCursor函数中增加控制鼠标光标的逻辑,如可以简单的显示你的个性化光标SetCursor(myCursor);也可以加入一些复杂的逻辑,比如在一定的区域内显示个性化光标,在其它区域显示标准光标,当然这就因实际需要而定了。

三、LoadCursorFromFile


四、CreateIconIndirect      
1.把icon放到resource-only的DLL中,然后在运行时LoadLibrary,读取DLL中的icon
2.在ico文件中存放了两幅位图and 和 mask,从文件中读出再用CreateIconIndirect生成就可以了

CreateIconIndirect函数定义:
This function creates an icon or cursor from an 
ICONINFO structure.
HICON CreateIconIndirect ( PICONINFO piconinfo );

This structure contains information about an icon.

typedef struct _ICONINFO { BOOL fIcon; DWORD xHotspot; DWORD yHotspot; HBITMAP hbmMask; HBITMAP hbmColor; } ICONINFO; 

Members

fIcon
Boolean that specifies whether this structure defines an icon or a cursor.
A value of TRUE specifies an icon; a value of FALSE specifies a cursor.
xHotspot
Specifies the x-coordinate of a cursor's hot spot. If this structure defines an icon,
the hot spot is always in the center of the icon, and this member is ignored.
yHotspot
Specifies the y-coordinate of the cursor's hot spot. If this structure defines an
icon,the hot spot is always in the center of the icon, and this member is ignored.
hbmMask
Specifies the icon bitmask bitmap. If this structure defines a black and white icon,
this bitmask is formatted so that the upper half is the icon AND bitmask and the lower
half is the icon XOR bitmask. Under this condition, the height should be an even mul
-tiple of two. If this structure defines a color icon, this mask only defines the AND
bitmask of the icon.
hbmColor
Handle to the icon color bitmap. This member can be optional if this structure defines
a black and white icon
. The AND bitmask of hbmMask is applied with the SRCAND flag to
the destination; subsequently, the color bitmap is applied (using XOR) to the
destination by using the SRCINVERT flag.

Remarks

If you are not using the Iconcurs component, the fIcon member must be set to TRUE.
The Microsoft® Windows® CE .NET Icon component does not support cursors. If you need mouse
cursor support in your application, use the Windows CE Iconcurs component rather than the
Windows CE Icon component.



四、合并两个ICON   
记得 Windows 里的快捷方式么,将你的程序拖到桌面上建立一个快捷方式,不论程序用的是什么IconMicrosoft都会在Icon左下脚加上一个小小的箭头,很好玩是不是?下面我提供两种方式来实现这种效果:

1. 直接利用HICON CreateIconIndirect ( PICONINFO piconinfo );
HICON CombineIcon(HICON hBaseIcon, //底层Icon,yi:xFc(`WDM教育N=yz"放在下面的那个HICON hTopIcon, //上层Icon,盖在上面的那个int iWidth, //Icon的宽度int iHeight, //Icon的高度COLORREF colorkey//透明色){HDC hdc = GetDC(NULL);//建立一个兼容DC,用于作图HDC memdc = CreateCompatibleDC(hdc);//注意,这里的参数dc不能为兼容dc,否则就是单色位图HBITMAP membmp = (HBITMAP)CreateCompatibleBitmap(hdc, 32, 32);HBITMAP oldbmp = (HBITMAP)SelectObject(memdc, membmp);HBRUSH br = (HBRUSH)GetStockObject(colorkey);    RECT rect;rect.left = 0;rect.right = 32;rect.top = 0;rect.bottom = 32;SelectObject(memdc, br);//填充透明色FillRect(memdc, &rect, br); DrawIconEx(memdc, 0, 0, hBaseIcon, iWidth, iHeight, 0, NULL, DI_NORMAL);  DrawIconEx(memdc, 0, 0, hTopIcon , iWidth, iHeight, 0, NULL, DI_NORMAL);//保持图片SelectObject(memdc, oldbmp);ICONINFO info;info.fIcon = true;info.hbmMask = CreateBitmap(32, 32, 1, 1, NULL);info.hbmColor = membmp;return CreateIconIndirect(&info);}

2. 利用ImageList.ExtractIcon 将bitmap 转化成Icon
HICON CombineIcon( HICON hBaseIcon, //底层Icon,yi:xFc(`WDM教育N=yz"放在下面的那个  HICON hTopIcon, //上层Icon,盖在上面的那个  int iWidth, //Icon的宽度  int iHeight, //Icon的高度  COLORREF colorkey//透明色  ){HBITMAP         bmp;HDC             dc;HBRUSH          br;RECT            rc;HDC             hdc = GetDC (NULL);//建立一个兼容DC,用于作图dc = CreateCompatibleDC(hdc);//生成一空白BMP图bmp = CreateCompatibleBitmap(hdc, iWidth, iHeight);//建立一个实色的刷子br = CreateSolidBrush(colorkey);//生成一个Icon大小的矩形rc.left = 0;rc.top = 0;rc.bottom = iHeight;rc.right = iWidth;//将空白BMP选入DC,HBITMAP  oldbmp = (HBITMAP)SelectObject(dc, bmp);//填充透明色FillRect(dc, &rc, br); // 在BMP上画底层IconDrawIconEx(dc, 0, 0, hBaseIcon, iWidth, iHeight, 0, NULL, DI_NORMAL);     //在BMP上画上层IconDrawIconEx(dc, 0, 0, hTopIcon, iWidth, iHeight, 0, NULL, DI_NORMAL);     //保存画好的BMPSelectObject(dc, oldbmp);// 注意参数使用ILC_COLORDDB,这样可以支持高彩Icon(256活256色以上)HIMAGELIST ImageList;ImageList_Create(ImageList, iWidth, iHeight, ILC_MASK|ILC_COLORDDB, 1, 0);//将画好的BMP存入image list,并设置透明色ImageList_Add(ImageList, bmp, colorkey);//从image list中获取Iconreturn  ImageList_ExtractIcon(0, ImageList, 0);}

3......
HICON MergeIcon (HICON iconlg, HICON iconsm, int width, int height){HDC hdc = GetDC(NULL);HBITMAP    colorbmp, oldbmp;   //生成color位图HDC tempdc = ::CreateCompatibleDC(NULL);colorbmp = CreateCompatibleBitmap(hdc, width, height);oldbmp = (HBITMAP)SelectObject(tempdc, colorbmp);HBRUSH hr = CreateSolidBrush(0);RECT rc;rc.left = 0;rc.top = 0; rc.right = width;rc.bottom = height;FillRect(tempdc, &rc,  hr);DrawIcon(tempdc, 0, 0, iconlg);DrawIcon(tempdc, 0, 0, iconsm);//保存color位图colorbmp = (HBITMAP)SelectObject(tempdc, oldbmp);    ////////////////////////////////////////////////////////////////////////////生成mask位图HDC maskdc = ::CreateCompatibleDC(NULL);HBITMAP maskbmp = CreateCompatibleBitmap(maskdc, width, height);oldbmp = (HBITMAP)SelectObject(maskdc, maskbmp);hr = CreateSolidBrush(0xffffff);FillRect(maskdc, &rc,  hr);DrawIcon(maskdc, 0, 0, iconlg);DrawIcon(maskdc, 0, 0, iconsm);//保存mask位图maskbmp = (HBITMAP)SelectObject(maskdc, oldbmp);    //方法一:HIMAGELIST ImageList = ImageList_Create(width, height, ILC_MASK|ILC_COLORDDB, 1, 0);//将画好的BMP存入image listImageList_Add(ImageList, colorbmp, maskbmp);//从image list中获取Iconreturn ImageList_ExtractIcon(0, ImageList, 0);//方法二:ICONINFO info;info.fIcon = true;info.hbmMask = maskbmp;info.hbmColor = colorbmp;return  CreateIconIndirect(&info);}

五、HICON与HBITMAP相互转换
转载自: http://blog.csdn.net/windows_nt/article/details/8470637
方法一、
HICON HICONFromCBitmap( CBitmap& bitmap){BITMAP bmp;bitmap.GetBitmap(&bmp);HBITMAP hbmMask = ::CreateCompatibleBitmap(::GetDC(NULL), bmp.bmWidth, bmp.bmHeight);ICONINFO ii = {0};ii.fIcon = TRUE;ii.hbmColor = bitmap;ii.hbmMask = hbmMask;HICON hIcon = ::CreateIconIndirect(&ii);//一旦不再需要,注意用DestroyIcon函数释放占用的内存及资源::DeleteObject(hbmMask);return hIcon;}

方法二、
#include <gdiplus.h>#pragma comment(lib,"GdiPlus.lib")HICON CreateIcon(HBITMAP hBitmap){Gdiplus::Bitmap* pTmpBitmap=Gdiplus::Bitmap::FromHBITMAP(hBitmap,NULL);HICON hIcon=NULL;pTmpBitmap->GetHICON(&hIcon);delete pTmpBitmap;return hIcon;}

HICON转HBITMAP

利用GetIconInfo函数获取ICONINFO信息, 再将其复制到位图当中去, 代码如下:

HBITMAP ConvertIconToBitmap(HICON  hIcon){ HBITMAP   hBmp; BITMAP   bmp; CDC   bmpDC; CDC   iconDC; ICONINFO         csII; int bRetValue   =   ::GetIconInfo(hIcon,   &csII); if   (bRetValue   ==   FALSE)   return   NULL; bmpDC.Attach(::GetDC(NULL)); iconDC.CreateCompatibleDC(&bmpDC); if   (::GetObject(csII.hbmColor,   sizeof(BITMAP),   &bmp)) { DWORD       dwWidth   =   csII.xHotspot*2; DWORD       dwHeight   =   csII.yHotspot*2; hBmp=   ::CreateBitmap(dwWidth,   dwHeight,   bmp.bmPlanes,   bmp.bmBitsPixel,   NULL);iconDC.SelectObject(csII.hbmColor); bmpDC.SelectObject(hBmp); bmpDC.BitBlt(0,0,dwWidth,dwHeight,&iconDC,0,0,SRCCOPY); return   hBmp; }return NULL;}

还有一种方法就是先创建一个兼容位图, 然后通过API函数::DrawIcon()复制上去, CopyImage函数可以用来替换创建兼容DC以后的那些骤了

六、SetCursor

  函数功能:该函数确定光标的形状

 

  函数原型:HCURSOR SetCursor(HCURSOR hCursor);

 

  参数:

 

  hCursor:光标的句柄,该光标由CreateCursor函数载入。如果该参数为NULL,则该光标从屏幕上移开。在Windows95中该光标的宽和高是GetSysfemMefirics 函数的返回值SM_CXCURSOR和SM_CYCURSOR,并且光标的位深必须和显示器的位深相匹配,或者光标是单色的。

 

  返回值:如果有前一个光标,则返回值是前光标的句柄;如果没有前光标,则返回值是NUL。

 

  备注:仅当新光标与前光标不同时,才设置该光标,不然的话,该函数立即返回。该光标是一个共享资源。一个窗口仅当光标在其客户区域,或者它正在捕捉鼠标输入时,它才设置光标的形状。在一个没有鼠标的系统中,该窗口在光标离开它的客户区域或它要把控制权交给其他窗口之前,它会恢复以前的光标。 

如果应用程序必须在窗口中设置光标,必须确保指定窗口类的类光标被设为NULL,如果类光标不是NULL,则每次移动鼠标时,系统都要恢复类光标。如果内部的光标显不计数值小于零,则光标不在屏幕上显示。当一个应用程序使用ShowCursor函数隐藏光标的次数多于显示光标的次数时,则会发生这种情况。

Windows CE:当一个目标平台不支持鼠标光标时,使用cursor光标组件,该光标组件仅支持等待光标,设置等待光标,使用如下的代码:SetCursor(LoadCursor(NULL,IDC_WAIT));当一个目标平台不支持鼠标光标时,使用mcursor光标组件。该组件不支持彩色光标。


七、Creating a color cursor from a bitmap

代码下载:请参考我的CSDN资源。



参考文章: http://www.codeproject.com/Articles/5220/Creating-a-color-cursor-from-a-bitmap


Introduction

本文研究从一个HBITMAP创建一个带颜色的光标。

首先它解释了windows在窗口上显示光标的步骤,且并为了创建光标,我们需要创建什么信息。

之后我们将解释转化一个颜色的HBITMAP到一个光标的步骤。

最后,我们展示一个组件类,它把HBITMAP转化为一个HCURSOR。

How Windows displays a cursor?

在Windows中,光标的透明是由两个mask的使用获得的。一个叫做AND mask,一个叫XOR mask。

为了在屏幕上显示光标,系统首先在屏幕上表现和AND mask的逻辑的AND操作。在这个处理中,屏幕上的像素对应到AND mask上是1 bits时,表明保持不变;而屏幕上的像素对应到AND mask上是0 bits时,表明会改变。

之后系统将会在屏幕上用XOR mask执行一个逻辑的XOR操作。在这个处理中,屏幕上的像素如果对应着的XOR mask上是0 bit,那么保持不变;而如果像素对应着的XOR mask上是1 bits,那么将会改变。

 



现在让我们认识以上的AND/XOR mask,这样系统能用这些mask显示光标。 首先让我们创建AND mask. 以下的光标在中心包含一个红色的矩形。所以其他的像素应该是透明的。假设光标的大小是8*8,且矩形的大小是4*4。这样我们应该定义的AND mask如下。 


In the above AND mask, the bits corresponding to the red rectangle are 0 and the rest of the bits are 1. This is because, we need only the red rectangle to be displayed as the cursor and the rest of the area should be transparent. When the system performs a logical AND operation of this mask to the screen, the pixels in the screen corresponding to the red rectangle becomes modified and the rest remains unchanged.

Now let us create the XOR mask for our cursor. As we need to display the red rectangle as cursor on the screen and the rest as transparent, we need to make the bits in the XOR mask corresponding to the red rectangle as Red (RGB (255,0,0)) and the rest as 0.





The R in the above XOR mask represents RGB (255,0,0). I.e., red color. When the system performs logical XOR of this XOR mask to the screen, the R pixels are updated in the screen and the pixels corresponding to the 0 bits remains unchanged.

So finally, after performing logical AND of the AND mask followed by logical XOR of the XOR mask to the screen, the screen under our cursor region look like as shown below.




这里S表现了原始屏幕像素。R表面了红色像素。

Converting HBITMAP to HCURSOR

现在让我们从一个HBITMAP中创建AND/XOR 。以下的代码将做这件事

void CColorCursor::GetMaskBitmaps(HBITMAP hSourceBitmap,               COLORREF clrTransparent,               HBITMAP &hAndMaskBitmap,               HBITMAP &hXorMaskBitmap){  HDC hDC        = ::GetDC(NULL);  HDC hMainDC      = ::CreateCompatibleDC(hDC);   HDC hAndMaskDC      = ::CreateCompatibleDC(hDC);   HDC hXorMaskDC      = ::CreateCompatibleDC(hDC);   //Get the dimensions of the source bitmap  BITMAP bm;  ::GetObject(hSourceBitmap,sizeof(BITMAP),&bm);    hAndMaskBitmap  = ::CreateCompatibleBitmap(hDC,bm.bmWidth,bm.bmHeight);  hXorMaskBitmap  = ::CreateCompatibleBitmap(hDC,bm.bmWidth,bm.bmHeight);  //Select the bitmaps to DC  HBITMAP hOldMainBitmap = (HBITMAP)::SelectObject(hMainDC,hSourceBitmap);  HBITMAP hOldAndMaskBitmap  = (HBITMAP)::SelectObject(hAndMaskDC,    hAndMaskBitmap);  HBITMAP hOldXorMaskBitmap  = (HBITMAP)::SelectObject(hXorMaskDC,    hXorMaskBitmap);  //Scan each pixel of the souce bitmap and create the masks  COLORREF MainBitPixel;  for(int x=0;x<bm.bmWidth;++x)  {    for(int y=0;y<bm.bmHeight;++y)    {      MainBitPixel = ::GetPixel(hMainDC,x,y);      if(MainBitPixel == clrTransparent)      {        ::SetPixel(hAndMaskDC,x,y,RGB(255,255,255));        ::SetPixel(hXorMaskDC,x,y,RGB(0,0,0));      }      else      {        ::SetPixel(hAndMaskDC,x,y,RGB(0,0,0));        ::SetPixel(hXorMaskDC,x,y,MainBitPixel);      }    }  }    ::SelectObject(hMainDC,hOldMainBitmap);  ::SelectObject(hAndMaskDC,hOldAndMaskBitmap);  ::SelectObject(hXorMaskDC,hOldXorMaskBitmap);  ::DeleteDC(hXorMaskDC);  ::DeleteDC(hAndMaskDC);  ::DeleteDC(hMainDC);  ::ReleaseDC(NULL,hDC);}

以上代码为AND/XOR mask创建了两个内存DC和两个内存bitmaps。 之后他检查源bitmap像素,并创建masks,就像我们在上面的理论部分讲的一样

现在我们需要的是使用这些masks,并用我们熟悉的CreateIconIndirect创建一个cursor。

ICONINFO iconinfo = {0};iconinfo.fIcon        = FALSE;iconinfo.xHotspot       = 0;iconinfo.yHotspot       = 0;iconinfo.hbmMask        = hAndMask;iconinfo.hbmColor       = hXorMask;HCURSOR hCursor = ::CreateIconIndirect(&iconinfo);


That's it. We have successfully created a color cursor from a bitmap.

Using the code

It is always better to create a utility class for doing these things for us. So I created one called CColorCursor having the following interfaces.


static void GetMaskBitmaps(HBITMAP hSourceBitmap,COLORREF clrTransparent,         HBITMAP &hAndMaskBitmap,HBITMAP &hXorMaskBitmap);static HCURSOR CreateCursorFromBitmap(HBITMAP hSourceBitmap,COLORREF          clrTransparent, DWORD   xHotspot,DWORD   yHotspot);

The first interface is called from the second one to create the masks. The first one is also made public because we can use it to get an idea of what is happening inside. I used the first interface in my test application to display the AND/XOR mask as shown in the first figure and the second one to create cursor directly.

Now we are approaching towards the end of this article. I will finish it by showing the usage of this utility class.

#include "ColorCursor.h"....HBITMAP hSourceBitmap  = c.HCURSOR hCursor = CColorCursor::CreateCursorFromBitmap(    hSourceBitmap,RGB(0,0,0),0,0);

应用:
从服务器端得到的光标的AND图为:  (32*32)   XOR图为:  (32*64)
可是当我用AND图的全部,XOR图的上半部分HBITMAP,然后调用CreateIconIndirect,可得到的却是一条小边的图形。
后来直接把AND图当成是源图,然后把图色区域当成要透明的部分,即RGB(0,0,0),用本工程介绍的方法去创建光标。
成功!!!!


八、About Cursors

Windows provides a set of standard cursors that are available for any application to use at any time. The SDK header files contain identifiers for the standard cursors—the identifiers begin with the IDC_ prefix.

Each standard cursor has a corresponding default image associated with it. The user or an application can replace the default image associated with any standard cursor at any time. An application replaces a default image by using theSetSystemCursor function. The following image shows several standard cursors from Windows Vista:


An application can use the GetIconInfo function to retrieve the current image for a cursor and can draw the cursor by using the DrawIconEx function.To draw the default image for a standard cursor, specify the DI_COMPAT flag in the call to DrawIconEx. If you do not specify the DI_COMPAT flag, DrawIconEx draws the standard cursor using the image that the user specified.

Custom cursors are designed for use in a specific application and can be any design the developer defines. The following illustration shows several custom cursors.


Cursors can be either monochrome or color, and either static or animated. The type of cursor used on a particular computer system depends on the system's display.Old displays such as VGA do not support color or animated cursors. New displays, whose display drivers use the device-independent bitmap (DIB) engine, do support them.

Cursors and icons are similar and can be used interchangeably in many situations. The only difference between them is thatan image specified as a cursor must be in the format that the display can support. For example,a cursor must be monochrome for a VGA display.

This overview provides information on the following topics:

  • The Hot Spot
  • The Mouse and the Cursor
  • Cursor Creation
  • Cursor Location and Appearance
  • Cursor Confinement
  • Cursor Destruction
  • Cursor Duplication
  • The Window Class Cursor

The Hot Spot

In the cursor, a pixel called the hot spot marks the exact screen location that is affected by a mouse event, such as clicking a mouse button. Typically, the hot spot is the focal point of the cursor. The system tracks and recognizes this point as the position of the cursor. For example, typical hot spots are the pixel at the tip of an arrow-shaped cursor and the pixel in the middle of a crosshair-shaped cursor. The following images shows two cursors from a drawing program, in which hot spots are associated with the tip of the brush and the crosshair of the paint can.


When a mouse input event occurs, the mouse driver translates the event into an appropriate mouse message that includesthe coordinates of the hot spot. The system sends the mouse message to the window that contains the hot spot or to the window that is capturing mouse input. For more information, see Mouse Input.

The Mouse and the Cursor

The system reflects the movement of the mouse by moving the cursor on the screen accordingly. As the cursor moves over different parts of windows or into different windows, the system (or an application) changes the appearance of the cursor. For example, when the cursor crosses over a hyperlink, the system changes the cursor from an arrow to a hand.


If the system does not have a mouse, the system displays and moves the cursor only when the user chooses certain system commands, such as those used to size or move a window. To provide the user with a method of displaying and moving the cursor when a mouse is not available, an application can use the cursor functions to simulate mouse movement. Given this simulation capability, the user can use the arrow keys to move the cursor.

Cursor Creation

Because standard cursors are predefined, it is not necessary to create them. To use a standard cursor, an application retrieves a cursor handle by using the LoadCursor or LoadImage function. A cursor handle is a unique value of theHCURSOR type that identifies a standard or custom cursor.

To create a custom cursor for an application, you typically use a graphics application and include the cursor as a resource in the application's resource-definition file. At run time, call LoadCursor to retrieve the cursor handle. Cursor resources contain data for several different display devices. The LoadCursor function automatically selects the most appropriate data for the current display device. To load a cursor directly from a .CUR or .ANI file, use the LoadCursorFromFilefunction.

You can also create a custom cursor at run time by using the CreateIconIndirect function, which creates a cursor based on the content of an ICONINFO structure. The GetIconInfo function fills this structure with hot spot coordinates and information concerning the associated mask and color.

Applications should implement custom cursors as resources and use LoadCursorLoadCursorFromFile, or LoadImage rather than create the cursor at run time. Using cursor resources avoids device dependence, simplifies localization, and enables applications to share cursor designs.

The CreateIconFromResourceEx function enables an application to create icons and cursors based on resource data.CreateIconFromResourceEx creates a cursor based on binary resource data from other executable (.exe) files or DLLs. It must be preceded by calls to the LookupIconIdFromDirectoryEx function, as well as several resource functions.LookupIconIdFromDirectoryEx identifies the most appropriate cursor data for the current display device. For more information about resource functions, see Resources.

Cursor Location and Appearance

The system automatically displays a cursor for the mouse and updates its position on the screen. You can obtain current screen coordinates of the cursor and move the cursor to any location on the screen by using the GetCursorPos andSetCursorPos functions, respectively.

You can also retrieve the handle to the current cursor by using the GetCursor function, and you can set the cursor by using the SetCursor function. After you call SetCursor, the appearance of the cursor does not change until either the mouse moves, the cursor is explicitly set to a different cursor, or a system command is executed.

When the user moves the mouse, the system redraws the cursor at the new location. The system automatically redraws the cursor design associated with the window to which the cursor is pointing.

You can hide and redisplay the cursor, without changing the cursor design, by using the ShowCursor function. This function uses an internal counter to determine when to hide or display the cursor. An attempt to show the cursor increments the counter; an attempt to hide the cursor decrements the counter. The cursor is visible only if this counter is greater than or equal to zero.

The GetCursorInfo function gets the following information for the global cursor: whether the cursor is hidden or shown, the handle to the cursor, and the coordinates of the cursor.

Cursor Confinement

You can confine the cursor to a rectangular area on the screen by using the ClipCursor function. This is useful for when the user must respond to a certain event within the confined area of the rectangle. For example, you might useClipCursor to confine the cursor to a modal dialog box, preventing the user from interacting with other windows until the dialog box is closed.

The GetClipCursor function retrieves the screen coordinates of the rectangular area to which the cursor is temporarily confined.When it is necessary to confine the cursor, you can also use this function to save the coordinates of the original area in which the cursor can move. Then, you can restore the cursor to the original area when the new confinement is no longer necessary.

Cursor Destruction

You can destroy the cursor handle and free the memory the cursor used by calling the DestroyCursor function. However, this function has no effect on a shared cursor. A shared cursor is valid as long as the module from which it was loaded remains in memory. The following functions obtain a shared cursor:

  • LoadCursor
  • LoadCursorFromFile
  • LoadImage (if you use the LR_SHARED flag)
  • CopyImage (if you use the LR_COPYRETURNORG flag and the hImage is a shared cursor)

When you no longer need a cursor you created by using the CreateIconIndirect function, you should destroy the cursor. The DestroyIcon function destroys the cursor handle and frees any memory the cursor used. Use this function only on cursors that were created with CreateIconIndirect.

Cursor Duplication

The CopyCursor function copies a cursor handle. This enables application or DLL code to retrieve the handle to a cursor owned by another module. Then, if the other module is freed, the module that copied the cursor can still use the cursor design.

For information on how to add, remove, or replace cursor resources in executable files, see Resources.

The Window Class Cursor

When you register a window class, using the RegisterClass function, you can assign it a default cursor, known as theclass cursor. After the application registers the window class, each window of that class has the specified class cursor.

To override the class cursor, process the WM_SETCURSOR message. You can also replace a class cursor by using theSetClassLong function. This function changes the default window settings for all windows of a specified class. For more information, see Class Cursor.

===============================================================

图标的颜色

图标的主要改进是 Microsoft Windows XP 支持高颜色和 alpha 通道的图标图标和光标在 Windows XP 中可以是任何颜色深度,为最大值的 32 位的每个像素 (BPP)。要包含 alpha 通道的图标,它必须是 32 BPP,其中 24 位用于颜色的红-绿-蓝 (RGB) 值,8 位用于存储的 alpha 通道

选择图标

加载图标时,系统执行下列操作:
  • 首先,系统咨询主监视器的颜色深度为目标颜色深度 (因为目前有没有 Api 可以依据提供显式颜色深度)。
  • 第二,系统会诊系统指标,来获取目标宽度和高度值。
  • 第三,将向每个候选系统分配图像图标资源中或文件基于图像活动即将从目标的程度的得分。
评分算法的假设如下:
  • 它不是压缩色一个好主意。频繁地减少色彩空间的机械过程产生了不良的后果,尤其是中低端的颜色空间。如果 8 BPP 彩色图像 (这是 256 色) 压缩为 4 BPP 表示形式 (16 色) 时,您可能要接收质量太差的结果。在这种情况下,具有较低的颜色深度的手动自定义的映像会效果更好。
  • 它不是一个好主意,以展开宽度和高度。压缩算法都经常比拉伸算法更大成功。
系统分配的分数后,系统可加载图标候选人的最低分数。以下几点介绍系统用于计算的图标值的公式:
  • 基本增量计算从差异中颜色深度 (以每像素位数),目标和候选人之间的高度和宽度中。
  • 宽度和高度的增量将再乘以 2 如果他们需要拉伸 (因此,需要将拉伸的图标被称为惩罚
  • 颜色深度增量总是乘以 2,要赋予其更多的重量。
  • 最后,添加了所有这些增量的绝对值在一起以产生最终得分。
注意与早期版本的 Windows 中,不同的是在 Windows XP 中的评分算法不拉伸 (或者,"惩罚") 如果涉及颜色压缩 2 倍的颜色深度。此更改是因为位深度进行隐式彩色压缩高颜色情况下除外。

请考虑下面的位深度: 2 位、 4 位和 8 BPP。这些都是连续的位深度和 BPP 2 和 4 的 BPP 之间的增量小于 4 位和 8 BPP 之间的增量。因此,系统将已选择较低的颜色深度。放松一下此惩罚允许用户自行选择 32 BPP 在 24 BPP 显示设备上,而不是选择 8 BPP 图标的图标。这是有必要的因为混合了 alpha 的图标,但 24 BPP 曲面的新用户界面优点通常比 32 BPP 曲面执行更好地执行。

光标的颜色

游标是只是一个图标具有系统用来解释您的意图,在屏幕上某点时的一个热点因此,游标是几乎完全与它们的文件格式中的图标相同之处在于一些由一个图标来存储的颜色信息用于存储的光标文件中的热点。类似这种文件格式限制游标,因为当 Windows XP 实现游标加载程序,假定游标的颜色深度为 1 位。

注意光标创作以任何颜色深度正确加载光标。但是,系统不能区分同一个光标文件或资源的差异仅在于其颜色深度的多个候选。图标,但是,完全支持多个具有不同颜色深度的图标候选。

注意虽然系统来检查实际撰写的光标候选人若要检索其实际颜色深度的限位 Windows 当前不这样。

过去,游标被低颜色,通常黑色和白色,尽管某些方案包含颜色版本。Windows XP 支持 32 BPP 游标,这虽然可能会降低性能,如果您的硬件不充分加速增加了供其使用,可能性。

注意如果游标具有 alpha 通道 (32 BPP),则忽略鼠标指针下方的阴影的系统设置

出于这些原因,Microsoft 建议游标集将创作只能在单个的颜色深度。尤其是在高 DPI 系统上可以使用游标,Microsoft 还建议使用的光标,在集中的多个大小。

光标大小

尽管在理论上,游标可以是任意大小,系统可以实施通过的 SM_CXCURSOR 和 SM_CYCURSOR 值公开的标准大小。这些指标都是只读的。在标准的 DPI 较低的系统上,这些指标都设置为 32 x 32 像素 (32 字节/行)。当系统通过标准的LoadCursor函数加载游标时,光标伸展到此维度。

大多数系统光标显示小于 32 x 32 和不使用某些光标周围的空间。超大的方案中的游标使用多个可用的 32x32 区域。Windows XP 中没有包含任何大于 32 × 32 的系统游标。(包括大游标时,它们会延伸到 32 x 32 标准 Api 加载游标时。)

对于高 DPI 的系统,Windows XP 已经调整为 64 x 64 像素的 SM_CXCURSOR 和 SM_CYCURSOR 的值。此大小调整是为了防止几乎消失,因为它太小,无法有效地使用鼠标指针。尽管与 DPI 扩展系统的其他方面,鼠标指针不会缩放。Microsoft 不会尝试强制实施 DPI 无关大小的鼠标指针。

系统还提供了可用来更改特定类别的系统光标的SetSystemCursor API 函数。可以使用此函数来设置任意大小的光标。但是,您必须以编程方式调用该函数,您仅可以使用它来设置用于特定类别的游标。不能用于使大小相同的系统上的所有游标。

对于想要在高 DPI 的系统上使用的游标集,Microsoft 建议 32 × 32 和 64 x 64 候选人与创作它们。加载,具体取决于系统的 DPI 期间,系统将选择适当的候选人。

光标比例问题

有时,系统必须能够扩展一个游标。默认情况下,系统执行最近的邻居拉伸。结果,尽管,迅速提供了非常失真;因此,半色调拉伸已经启用提供一些更好的结果。遗憾的是,半色调拉伸效果最佳源映像通常具有多种颜色和游标的使用具有很少的颜色。因此,拉伸算法有限结果可以显示方式令人满意。

大多数图标在 32 x 32 像素都并未参与创作,大多数系统不会拉伸图标因为它们 DPI 较低的系统。但是,高 DPI 系统伸展的默认系统光标。因为半色调拉伸产生更好的视觉效果比像素失真),半色调拉伸处于启用状态。

此外,拉伸算法通常以不同的方式对执行透明度蒙版和彩色图像,从而导致分歧。掩码是黑色和白色。因此,可以没有插值的颜色的相邻像素之间。彩色图像,但是,经常可以支持插值的颜色。频繁的结果是掩码形从您的预期稍有不同。这可能会导致为粗边框,并在某些情况下,沿边框的其他错误的视觉效果。包含 alpha 通道 (而不是透明屏蔽的游标没有这个问题,因为 alpha 通道隐式依赖于颜色信息。

最后,随着光标的拉伸、 热点 (它是的单个像素) 是更容易从它预定的位置移开。随着光标比例进行调整,都将调整热点,但具有更少的颜色信息比优化。

==========================================================================

Using Cursors

The following example creates two cursor handles: one for the standard hourglass cursor and one for a custom cursor included as a resource in the application's resource-definition file.

HINSTANCE hinst;            // handle to current instance HCURSOR hCurs1, hCurs2;     // cursor handles  // Create a standard hourglass cursor.  hCurs1 = LoadCursor(NULL, IDC_WAIT);  // Create a custom cursor based on a resource.  hCurs2 = LoadCursor(hinst, MAKEINTRESOURCE(240)); 

You should implement custom cursors as resources. Rather than create the cursors at run time, use the LoadCursor,LoadCursorFromFile, or LoadImage function to avoid device dependence, to simplify localization, and to enable applications to share cursor designs.

The following example uses the CreateCursor function to create a custom cursor at run time. The example is included here to illustrate how the system interprets cursor masks.

INSTANCE hinst;            // handle to current instance  HCURSOR hCurs1, hCurs2;     // cursor handles  HCURSOR hCurs3;             // cursor handle  // Yin-shaped cursor AND mask  BYTE ANDmaskCursor[] = {     0xFF, 0xFC, 0x3F, 0xFF,   // line 1     0xFF, 0xC0, 0x1F, 0xFF,   // line 2     0xFF, 0x00, 0x3F, 0xFF,   // line 3     0xFE, 0x00, 0xFF, 0xFF,   // line 4      0xF7, 0x01, 0xFF, 0xFF,   // line 5     0xF0, 0x03, 0xFF, 0xFF,   // line 6     0xF0, 0x03, 0xFF, 0xFF,   // line 7     0xE0, 0x07, 0xFF, 0xFF,   // line 8      0xC0, 0x07, 0xFF, 0xFF,   // line 9     0xC0, 0x0F, 0xFF, 0xFF,   // line 10     0x80, 0x0F, 0xFF, 0xFF,   // line 11     0x80, 0x0F, 0xFF, 0xFF,   // line 12      0x80, 0x07, 0xFF, 0xFF,   // line 13     0x00, 0x07, 0xFF, 0xFF,   // line 14     0x00, 0x03, 0xFF, 0xFF,   // line 15     0x00, 0x00, 0xFF, 0xFF,   // line 16      0x00, 0x00, 0x7F, 0xFF,   // line 17     0x00, 0x00, 0x1F, 0xFF,   // line 18     0x00, 0x00, 0x0F, 0xFF,   // line 19     0x80, 0x00, 0x0F, 0xFF,   // line 20      0x80, 0x00, 0x07, 0xFF,   // line 21     0x80, 0x00, 0x07, 0xFF,   // line 22     0xC0, 0x00, 0x07, 0xFF,   // line 23     0xC0, 0x00, 0x0F, 0xFF,   // line 24      0xE0, 0x00, 0x0F, 0xFF,   // line 25     0xF0, 0x00, 0x1F, 0xFF,   // line 26     0xF0, 0x00, 0x1F, 0xFF,   // line 27     0xF8, 0x00, 0x3F, 0xFF,   // line 28      0xFE, 0x00, 0x7F, 0xFF,   // line 29     0xFF, 0x00, 0xFF, 0xFF,   // line 30     0xFF, 0xC3, 0xFF, 0xFF,   // line 31     0xFF, 0xFF, 0xFF, 0xFF    // line 32 }; // Yin-shaped cursor XOR mask  BYTE XORmaskCursor[] = {     0x00, 0x00, 0x00, 0x00,   // line 1     0x00, 0x03, 0xC0, 0x00,   // line 2     0x00, 0x3F, 0x00, 0x00,   // line 3     0x00, 0xFE, 0x00, 0x00,   // line 4      0x0E, 0xFC, 0x00, 0x00,   // line 5     0x07, 0xF8, 0x00, 0x00,   // line 6     0x07, 0xF8, 0x00, 0x00,   // line 7     0x0F, 0xF0, 0x00, 0x00,   // line 8      0x1F, 0xF0, 0x00, 0x00,   // line 9     0x1F, 0xE0, 0x00, 0x00,   // line 10     0x3F, 0xE0, 0x00, 0x00,   // line 11     0x3F, 0xE0, 0x00, 0x00,   // line 12      0x3F, 0xF0, 0x00, 0x00,   // line 13     0x7F, 0xF0, 0x00, 0x00,   // line 14     0x7F, 0xF8, 0x00, 0x00,   // line 15     0x7F, 0xFC, 0x00, 0x00,   // line 16      0x7F, 0xFF, 0x00, 0x00,   // line 17     0x7F, 0xFF, 0x80, 0x00,   // line 18     0x7F, 0xFF, 0xE0, 0x00,   // line 19     0x3F, 0xFF, 0xE0, 0x00,   // line 20      0x3F, 0xC7, 0xF0, 0x00,   // line 21     0x3F, 0x83, 0xF0, 0x00,   // line 22     0x1F, 0x83, 0xF0, 0x00,   // line 23     0x1F, 0x83, 0xE0, 0x00,   // line 24      0x0F, 0xC7, 0xE0, 0x00,   // line 25     0x07, 0xFF, 0xC0, 0x00,   // line 26     0x07, 0xFF, 0xC0, 0x00,   // line 27     0x01, 0xFF, 0x80, 0x00,   // line 28      0x00, 0xFF, 0x00, 0x00,   // line 29     0x00, 0x3C, 0x00, 0x00,   // line 30     0x00, 0x00, 0x00, 0x00,   // line 31     0x00, 0x00, 0x00, 0x00    // line 32 }; // Create a custom cursor at run time.  hCurs3 = CreateCursor( hinst,   // app. instance              19,                // horizontal position of hot spot              2,                 // vertical position of hot spot              32,                // cursor width              32,                // cursor height              ANDmaskCursor,     // AND mask              XORmaskCursor );   // XOR mask 

To create the cursor, CreateCursor applies the following truth table to the AND and XOR masks.

For more information, see Bitmaps.

Before closing, you must use the DestroyCursor function to destroy any cursors you created with CreateCursor. It is not necessary to destroy cursors created by other functions.

Displaying a Cursor

The system automatically displays the class cursor (the cursor associated with the window to which the cursor is pointing). You can assign a class cursor while registering a window class. The following example illustrates this by assigning a cursor handle to the hCursor member of the WNDCLASS structure identified by the wc parameter.

WNDCLASS  wc;  // Fill the window class structure with parameters that // describe the main window.  wc.style = NULL;                        // class style(s) wc.lpfnWndProc = (WNDPROC) MainWndProc; // window procedure wc.cbClsExtra = 0;           // no per-class extra data wc.cbWndExtra = 0;           // no per-window extra data wc.hInstance = hinst;        // application that owns the class wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);     // class icon wc.hCursor = LoadCursor(hinst, MAKEINTRESOURCE(230)); // class cursor wc.hbrBackground = GetStockObject(WHITE_BRUSH); // class background wc.lpszMenuName =  "GenericMenu";               // class menu wc.lpszClassName = "GenericWClass"              // class name  // Register the window class.  return RegisterClass(&wc); 

When the window class is registered, the cursor identified by 230 in the application's resource-definition file is the default cursor for all windows based on the class.

Your application can change the design of the cursor by using the SetCursor function and specifying a different cursor handle. However, when the cursor moves, the system redraws the class cursor at the new location. To prevent the class cursor from being redrawn, you must process the WM_SETCURSOR message. Each time the cursor moves and mouse input is not captured, the system sends this message to the window in which the cursor is moving.

You can specify different cursors for different conditions while processing WM_SETCURSOR. For example, the following example shows how to display the cursor whenever the cursor moves over the icon of a minimized application.

case WM_SETCURSOR:      // If the window is minimized, draw the hCurs3 cursor.     // If the window is not minimized, draw the default     // cursor (class cursor).      if (IsIconic(hwnd))     {         SetCursor(hCurs3);         break;     } 

When the window is not minimized, the system displays the class cursor.

You can replace a class cursor by using the SetClassLong function. This function changes the default window settings for all windows of a specified class. The following example replaces the existing class cursor with the hCurs2 cursor.

// Change the cursor for window class represented by hwnd.  SetClassLong(hwnd,    // window handle     GCL_HCURSOR,      // change cursor     (LONG) hCurs2);   // new cursor 

For more information, see Window Classes and Mouse Input.

Confining a Cursor

The following example confines the cursor to the application's window and then restores the cursor to its previous window. The example uses the GetClipCursor function to record the area in which the cursor can move and theClipCursor function to confine and restore the cursor.

RECT rcClip;           // new area for ClipCursorRECT rcOldClip;        // previous area for ClipCursor // Record the area in which the cursor can move.  GetClipCursor(&rcOldClip);  // Get the dimensions of the application's window.  GetWindowRect(hwnd, &rcClip);  // Confine the cursor to the application's window.  ClipCursor(&rcClip);     //    // Process input from the confined cursor.    //  // Restore the cursor to its previous area.  ClipCursor(&rcOldClip); 

Icons and Cursors

Icons and cursors are like images, and you edit them in the same ways. However, icons and cursors have attributes that distinguish them from images. For example, each icon or cursor resource can contain multiple images for different display devices. In addition, a cursor has a “hot spot”: the location Windows uses to track its position.

When you create a new icon or cursor, the Graphics editor first creates an image for VGA. The image is initially filled with the “screen” (transparent) color. If the image is a cursor, the hot spot is initially the upper-left corner (coordinates 0,0).

By default, the graphics editor supports the creation of images for the devices shown in the following table.


You can create images for other devices by typing width, height, and color-count parameters into the Custom Device dialog box.





九、用VC++在基于对话框的程序中动态更改光标
 当用户将鼠标指针移到按钮上时,鼠标不被捕获,Windows发送一个WM_SETCURSOR消息到按钮。从上面OnSetCursor的代码中可以看到,它传递的第一个参数是窗口句柄(pWnd)-即鼠标指针所指的窗口,这里指的是按钮本身;OnSetCursor传递的第二个参数是nHitTest,这是一个鼠标点击测试代码(Mouse Hit-Test Codes),它以HTXXX开头,用于WM_NCHITTEST消息;OnSetCursor传递的第三个参数是触发事件的鼠标消息,例如它的值可以为WM_MOUSEMOVE。WM_SETCURSOR是专门用来设置鼠标指针的消息,当设置了鼠标指针以后,应该让它返回TRUE以防止Windows再作缺省处理。(在调试中发现当WM_SETCURSOR返回TRUE用,把鼠标放到非客户端时鼠标的开状不会还原为系统的。)

  WM_SETCURSOR的处理机制是这样的,如果有父窗口的话,缺省的窗口过程首先发送WM_SETCURSOR消息到父窗口,如果父窗口处理WM_SETCURSOR消息(即返回TRUE),则Windows不再作任何多余的事情,处理完消息便结束。如果父窗口不处理WM_SETCURSOR消息(即返回FALSE),Windows让子窗口来处理WM_SETCURSOR,如果子窗口也不做任何处理(返回FALSE),Windows使用全程光标指针,如果没有全程光标指针,则使用箭头指针。

  如果你在程序中要是使用动态光标指针,你必须决定是在子窗口处理WM_SETCURSOR消息还是在父窗口中处理WM_SETCURSOR消息。两种方法各有利弊,根据具体情况而定。一般总是让对象决定它们自己的行为属性-也就是说最好在子窗口中做处理。本例中的子窗口即静态控件。这就要派生一个新的CStatic类的子类,该类有自己的消息映射及其消息处理过程。

  CWnd::SetCursor()函数使用起来比较简单,只要将待选择的鼠标的句柄(装载鼠标函数为:LoadIcon())作为该函数的参数就可以了。





十一、调试过程中的总结
1、创建Alpha光标的方法
创建Alpha光标通道的图时没有XOR图,只有AND图
如WIN系统中自带的以下光标就是Alpha光标。

它得到的AND图为:

此图为32位的图。
(1)初步处理
参考文章: http://support.microsoft.com/kb/318876/zh-cn
Alpha图与单色光标的处理不一样,单色光标的处理是调用CreateCursor API函数;
而Alpha 图是调用CreateIconIndirect函数。因为CreateCursor最后一个参数为XOR的数组数据,而它不允许为空,一为空就会报错。
处理为:
// 32位Alpha图HBITMAP membmp;HBITMAP membmpMask;DWORD *lpdwPixel;lpdwPixel = (DWORD *)cursorBmp->data;for (int x=0;x<cursorBmp->width;x++){for (int y=0;y<cursorBmp->height;y++){// Clear the alpha bits*lpdwPixel &= 0x00FFFFFF;// Set the alpha bits to 0x9F (semi-transparent)*lpdwPixel |= 0x9F000000;lpdwPixel++;}}CreateBitmapInternalAlpha(cursorBmp, &membmp);//CreateBitmapInternal(maskBmp, &membmpMask);// Create an empty mask bitmap.membmpMask = CreateBitmap(cursorBmp->width,cursorBmp->height,1,1,NULL);ICONINFO info;  info.fIcon = FALSE;  info.xHotspot = xHotspot;info.yHotspot = yHotspot;info.hbmMask = membmpMask;   info.hbmColor = membmp;  return CreateIconIndirect(&info);

处理后得到的图标是:

解决方法:把下面这段代码去掉
DWORD *lpdwPixel;lpdwPixel = (DWORD *)cursorBmp->data;for (int x=0;x<cursorBmp->width;x++){for (int y=0;y<cursorBmp->height;y++){// Clear the alpha bits*lpdwPixel &= 0x00FFFFFF;// Set the alpha bits to 0x9F (semi-transparent)*lpdwPixel |= 0x9F000000;lpdwPixel++;}}
(2)其中有过出现如下的光标

解决方法:修改CreateBitmapInternalAlpha的实现。
本来的实现是:
HDCXSurfaceGDI::CreateBitmapInternalAlpha(BITMAP_T *bmp, HBITMAP *hBitmap){HDC memDC; HBITMAP memBM;memDC = CreateCompatibleDC(m_baseDC);if ( memDC == NULL ){XExit(XEXIT_CODE_GDI, "CreateCompatibleDC fail: %d\n", GetLastError());}memBM = CreateCompatibleBitmap(m_baseDC, bmp->width, bmp->height);if ( memBM == NULL ){XExit(XEXIT_CODE_GDI, "CreateCompatibleBitmap fail: %d\n", GetLastError());}SelectObject (memDC, memBM);if ( bmp->data != NULL ){int guiRet;BITMAPV5HEADER bmi = {0};ZeroMemory(&bmi,sizeof(BITMAPV5HEADER));bmi.bV5Size           = sizeof(BITMAPV5HEADER);bmi.bV5Width           = bmp->width;//bmi.bV5Height          = bmp->height;bmi.bV5Planes = 1;bmi.bV5BitCount = GetBitsFromBmpFormat(bmp->bitmapFormat);bmi.bV5Compression = BI_BITFIELDS;// The following mask specification specifies a supported 32 BPP// alpha format for Windows XP.bmi.bV5RedMask   =  0x00FF0000;bmi.bV5GreenMask =  0x0000FF00;bmi.bV5BlueMask  =  0x000000FF;bmi.bV5AlphaMask =  0xFF000000; bmi.bV5Height          = bmp->height;guiRet = StretchDIBits(memDC,0, 0, bmp->width, bmp->height, 0, 0, bmp->width, bmp->height, bmp->data, (BITMAPINFO *)&bmi, DIB_RGB_COLORS, SRCCOPY);if ( GDI_ERROR == guiRet ){XExit(XEXIT_CODE_GDI, "StretchDIBits fail\n");}}if ( hBitmap  ){*hBitmap = memBM;}else{DeleteObject(memBM);}return memDC;}

现在的实现改为:
HDCXSurfaceGDI::CreateBitmapInternalAlpha(BITMAP_T *bmp, HBITMAP *hBitmap){HDC memDC; HBITMAP memBM;memDC = CreateCompatibleDC(m_baseDC);if ( memDC == NULL ){XExit(XEXIT_CODE_GDI, "CreateCompatibleDC fail: %d\n", GetLastError());}memBM = CreateCompatibleBitmap(m_baseDC, bmp->width, bmp->height);if ( memBM == NULL ){XExit(XEXIT_CODE_GDI, "CreateCompatibleBitmap fail: %d\n", GetLastError());}SelectObject (memDC, memBM);if ( bmp->data != NULL ){int guiRet;BITMAPV5HEADER bmi = {0};ZeroMemory(&bmi,sizeof(BITMAPV5HEADER));bmi.bV5Size           = sizeof(BITMAPV5HEADER);bmi.bV5Width           = bmp->width;//bmi.bV5Height          = bmp->height;bmi.bV5Planes = 1;bmi.bV5BitCount = GetBitsFromBmpFormat(bmp->bitmapFormat);bmi.bV5Compression = BI_BITFIELDS;// The following mask specification specifies a supported 32 BPP// alpha format for Windows XP.bmi.bV5RedMask   =  0x00FF0000;bmi.bV5GreenMask =  0x0000FF00;bmi.bV5BlueMask  =  0x000000FF;bmi.bV5AlphaMask =  0xFF000000; if ( bmp->stride < 0 ){bmi.bV5Height          = bmp->height; }else{bmi.bV5Height          = 0 - bmp->height; }// Create the DIB section with an alpha channel. guiRet = StretchDIBits(memDC,0, 0, bmp->width, bmp->height, 0, 0, bmp->width, bmp->height, bmp->data, (BITMAPINFO *)&bmi, DIB_RGB_COLORS, SRCCOPY);if ( GDI_ERROR == guiRet ){XExit(XEXIT_CODE_GDI, "StretchDIBits fail\n");}}if ( hBitmap  ){*hBitmap = memBM;}else{DeleteObject(memBM);}return memDC;}
修改是当stride小于0时就把bmi.bV5Height设置为正数的高;而当stride大于等于0时高就设置为负的。
经过调试发现我们的alpha图的stride是128,所以是负的,这样光标方向就调正了。


2、
3、
4、