首页 > 代码库 > 使用Unity3d做异形窗口

使用Unity3d做异形窗口

  项目马上上线,因为之前的登录器是使用VS2010的MFC做的,在很多电脑上会提示缺失mfcXXXX.dll,中间找寻这种解决方案,最后确定将vcredist2010_x86和我的程序打包到安装包里面,每次安装的时候默认先安装vcredist2010_x86。

  由此,经常被杀毒软件阻止,而且还有x64 or x86的区别。

  同时,甲方想要一个精灵,类似于QQ宠物,于是PL决定使用精灵模型+异形窗口做一个桌面宠物。于是,异形窗口成了此物的基础。

 

  首先,我们需要了解的是,异形窗口是什么。简单来说,即将窗口形状变成由一张不规则(一般由透明色决定)图片所决定的形状。

  然后,需要知道的是窗口的形状是由什么决定。在MSDN上我发现,普通的窗口形状由一个简单的Rectangular Region决定。经查询之后,要实现异形窗口主要要靠这几个函数:

  a. 创建一个矩形区域

?
1
2
3
4
5
6
7
//The CreateRectRgn function creates a rectangular region. <br>
HRGN CreateRectRgn(
  int nLeftRect,   // x-coordinate of upper-left corner
  int nTopRect,    // y-coordinate of upper-left corner
  int nRightRect,  // x-coordinate of lower-right corner
  int nBottomRect  // y-coordinate of lower-right corner
);

  b. 结合n个矩形区域

?
1
2
3
4
5
6
7
8
9
//The CombineRgn function combines two regions and stores the result in a third region.
//The two regions are combined according to the specified mode.
 
int CombineRgn(
  HRGN hrgnDest,      // handle to destination region
  HRGN hrgnSrc1,      // handle to source region
  HRGN hrgnSrc2,      // handle to source region
  int fnCombineMode   // region combining mode
);

  c. 将窗口显示出来

?
1
2
3
4
5
6
7
8
9
//The SetWindowRgn function sets the window region of a window.
//The window region determines the area within the window where the system permits drawing.
//The system does not display any portion of a window that lies outside of the window region
 
int SetWindowRgn(
  HWND hWnd,     // handle to window
  HRGN hRgn,     // handle to region
  BOOL bRedraw   // window redraw option
);

  d. 去掉窗口标题栏(主要窗口截图只能截到窗口边框内)

?
1
2
3
4
5
6
7
//This function changes an attribute of the specified window.
//SetWindowLong also sets a 32-bit (LONG) value at the specified offset into the extra window memory of a window.<br>
LONG SetWindowLong(
  HWND hWnd,
  int nIndex,
  LONG dwNewLong
);

  

  最后,在unity里面调用user32.dll 和 Gdi32.dll 两个动态链接库,结合unity界面截图,得到最后的处理结果。贴上部分处理代码:

 1 /// <summary>
 2     /// use the screen shot image to cut the window.
 3     /// </summary>
 4     private void updateWindow() {
 5         System.IntPtr hRgn = WinAPI.CreateRectRgn(0, 0, 0, 0);
 6 
 7         Debug.Log(" width: " + winTex2d.width + " height: " + winTex2d.height);
 8         
 9         for (int h = 0; h < winTex2d.height; ++h) {//int h = tex2d.height - 1; h > tex2d.height/2; --h
10             //Debug.Log(tex2d.GetPixel(h, h));
11             int w = 0;
12             do {
13                 while (w < winTex2d.width && (winTex2d.GetPixel(w, winTex2d.height - h) == Color.clear
14                     || winTex2d.GetPixel(w, h) == Color.black
15                     )) {
16                     ++w;
17                     //Debug.Log(tex2d.GetPixel(w, h));
18                 }
19                 int iLeftX = w;
20                 while (w < winTex2d.width && (winTex2d.GetPixel(w, winTex2d.height - h) != Color.clear
21                     //|| tex2d.GetPixel(w, h) != Color.black
22                     )) {
23                     ++w;
24                     //Debug.Log(tex2d.GetPixel(w, h));
25                 }
26                 //Debug.Log("ileftX: " + iLeftX + "w: " + w + h);
27 
28                 WinAPI.CombineRgn(hRgn, hRgn, WinAPI.CreateRectRgn(iLeftX, h, w, h + 1), 2);
29             }//end do{}
30             while (w < winTex2d.width);
31         }//end for(h);
32 
33         Debug.Log("setWindowRgn: " + WinAPI.SetWindowRgn(WinAPI.GetActiveWindow(), hRgn, true));
34     }//end updateWindow();
View Code

  PS:这种处理方式当图形透明区域特别多的时候,会出现整个处理过程有些卡顿,后期可能要加入线程进行处理。

 

感谢您的阅读,如果您有好的建议,望不吝赐教!