原理上没有什么新意,主要就是用CreateRectRgn、CreateRectRgn、CombineRgn和CreatePolygonRgn这 几个API,代码最大的特点就是高速,这个也是最重要的,你甚至可以用来做动画窗体。
代码用CB编写。
//创建图片形状的窗体,可以是任意颜色
//速度<30ms
//作者:cczlp
//
void __fastcall CreateWindowRgn(HWND hwnd, Graphics::TBitmap *SrcBitmap, TColor TransColor)

...{
register int x1, x2, y;
register int Left, Right;
int n, m;
int BmpW, BmpH;
int StartY;
int BytePerPix;
BOOL Flag;
BOOL Same;
POINT *pt, *pt1, *pt2;
HRGN WndRgn, tmpRgn;
BYTE *ptr;
Byte R, G, B;
Graphics::TBitmap *Bitmap;


//取图像尺寸
BmpW = SrcBitmap->Width;
BmpH = SrcBitmap->Height;

//只处理24位色和256色, 其它格式转为24位色
if (SrcBitmap->PixelFormat != pf24bit && SrcBitmap->PixelFormat != pf8bit)

...{
Bitmap = new Graphics::TBitmap;
Bitmap->Width = BmpW;
Bitmap->Height = BmpH;
Bitmap->PixelFormat = pf24bit;
Bitmap->Canvas->Draw(0, 0, SrcBitmap);
}
else

...{
Bitmap = SrcBitmap;
}

pt = new POINT[(BmpH << 1) + 1];

if (Bitmap->PixelFormat == pf24bit)

...{
//透明色分量
R = GetRValue(TransColor);
G = GetGValue(TransColor);
B = GetBValue(TransColor);

//每象素所占字节数
BytePerPix = 3;
}
else

...{
//取透明色在调色板的索引
PALETTEENTRY pal[256];

GetPaletteEntries(SrcBitmap->Palette, 0, 256, pal);
for (y = 0; y < 256; y++)

...{
if (TColor(RGB(pal[y].peRed, pal[y].peGreen, pal[y].peBlue)) == TransColor)

...{
break;
}
}

//每象素所占字节数
BytePerPix = 1;
}

//先建整个区域, 然后从中减去透明色的地方
WndRgn = CreateRectRgn(0, 0, BmpW, BmpH);

//使用指针, 加快访问速度
pt1 = pt;
pt2 = pt + (BmpH << 1) - 1;

//从左右扫描图像外部的边界点
//24bit
if (BytePerPix == 3)

...{
for (y = 0; y < BmpH; y++)

...{

//记录左面不透明色的起点
ptr = (Byte *)Bitmap->ScanLine[y];
for (x1 = 0; x1 < BmpW; x1++)

...{
if (*ptr != B || *(ptr + 1) != G || *(ptr + 2) != R)

...{
pt1->x = x1;
pt1->y = y;
pt1++;
break;
}
ptr += 3;
}

//记录右面不透明色的起点
ptr = (Byte *)Bitmap->ScanLine[y] + (BmpW - 1) * 3;
for (x2 = BmpW - 1; x2 >= x1; x2--)

...{
if (*ptr != B || *(ptr + 1) != G || *(ptr + 2) != R)

...{
pt2->x = x2 + 1;
pt2->y = y;
pt2--;

break;
}
ptr -= 3;
}
}
}
else //8bit, 对256色同样处理

...{
for (y = 0; y < BmpH; y++)

...{
ptr = (Byte *)Bitmap->ScanLine[y];

for (x1 = 0; x1 < BmpW; x1++)

...{
if ((*ptr != R)) //

...{
pt1->x = x1;
pt1->y = y;
pt1++;
break;
}
ptr++;
}

ptr = (Byte *)Bitmap->ScanLine[y] + (BmpW - 1);
for (x2 = BmpW - 1; x2 >= x1; x2--)

...{
if ((*ptr != R)) //

...{
pt2->x = x2 + 1;
pt2->y = y;
pt2--;
break;
}
ptr--;
}
}
}

//如果有整行都透明的, 去掉中间的空行
n = pt1 - pt;
m = pt2 - pt;
if (m - n > 0)

...{
memmove((char *)pt + n * sizeof(POINT),
(char *)pt + (m + 1) * sizeof(POINT),
n * sizeof(POINT));
}

//去除图像内部的或凹处的剩余的透明点
StartY = pt[0].y;
pt2 = pt + (n << 1) - 1;
for (y = StartY; y < StartY + n; y++)

...{
Flag = False;
ptr = (Byte *)Bitmap->ScanLine[y] + pt[y - StartY].x * BytePerPix;

//查找每行透明色的起始和结束点,并去掉透明的区域
for (x1 = pt[y - StartY].x; x1 < pt2->x; x1++)

...{
Same = BytePerPix == 3 ?
(*ptr == B) && (*(ptr + 1) == G) && (*(ptr + 2) == R) :
*ptr == R;

if (!Flag && Same)

...{
Left = x1;
Flag = TRUE;
}
else if (!Same && Flag)

...{
tmpRgn = CreateRectRgn(Left, y, x1, y + 1);
CombineRgn(WndRgn, WndRgn, tmpRgn, RGN_XOR);
DeleteObject(tmpRgn);
Flag = FALSE;
}
ptr += BytePerPix;
}
if (Flag && x1 >= pt2->x)

...{
tmpRgn = CreateRectRgn(Left, y, x1, y + 1);
CombineRgn(WndRgn, WndRgn, tmpRgn, RGN_XOR);
DeleteObject(tmpRgn);
}
pt2--;

}

//最后点与起始点相同
pt[n << 1] = pt[0];

//合并区域
tmpRgn = CreatePolygonRgn(pt, (n << 1) + 1, ALTERNATE);
CombineRgn(WndRgn, WndRgn, tmpRgn, RGN_AND);
DeleteObject(tmpRgn);
//设置区域
SetWindowRgn(hwnd, WndRgn, true);

if (Bitmap != SrcBitmap)

...{
delete Bitmap;
}
delete []pt;
}
//----------------------------------------------------------------------------------
感谢 ydlchina 提出修正建议。