MFC/C++ 與 .NET 混合開發時,顏色值傳遞是常見痛點。Win32 COLORREF 採用 BGR 位元組序,.NET Color 結構 ToArgb() 回傳 AARRGGBB。本文詳細解析位元組序差異,提供雙向轉換標準程式碼。
| 項目 | Win32 COLORREF | .NET Color.ToArgb() |
|---|---|---|
| 大小 | 32 位元(實際用 24 位) | 32 位元 |
| 格式 | 0x00BBGGRR(BGR) | 0xAARRGGBB(ARGB) |
| Alpha 通道 | 無(最高位元組固定 0) | 有(AA,0-255) |
| 紅色分量位置 | 最低位元組(bits 0-7) | 第 3 位元組(bits 16-23) |
| 綠色分量位置 | 中間位元組(bits 8-15) | 第 2 位元組(bits 8-15) |
| 藍色分量位置 | 最高有效位元組(bits 16-23) | 最低位元組(bits 0-7) |
// 輸入:.NET Color 結構
Color clrColor = Color.FromArgb(123, 200, 12); // R=123, G=200, B=12
// 1. 取得 ARGB 整數
int argb = clrColor.ToArgb(); // 格式:AARRGGBB
// 2. 擷取各分量(注意:ToArgb 回傳 ARGB,紅在 bits 16-23)
int blue = argb & 0xFF; // bits 0-7
int green = (argb >> 8) & 0xFF; // bits 8-15
int red = (argb >> 16) & 0xFF; // bits 16-23
// 3. 重組為 BGR 格式(COLORREF)
int colorRef = (blue << 16) | (green << 8) | red; // 0x00BBGGRR
// 結果:colorRef 可直接傳給 Win32 API
// 輸入:Win32 COLORREF (0x00BBGGRR)
int colorRef = 0x000C0C7B; // 範例:B=12, G=200, R=123
// 1. 擷取 BGR 分量
int red = colorRef & 0xFF; // bits 0-7 = R
int green = (colorRef >> 8) & 0xFF; // bits 8-15 = G
int blue = (colorRef >> 16) & 0xFF; // bits 16-23 = B
// 2. 建立 .NET Color(忽略 Alpha,預設 255 不透明)
Color clrColor = Color.FromArgb(red, green, blue);
// 一行版
Color clr = Color.FromArgb(colorRef & 0xFF, (colorRef >> 8) & 0xFF, (colorRef >> 16) & 0xFF);
public static class ColorConverter
{
/// .NET Color 轉 Win32 COLORREF (BGR)
public static int ToColorRef(Color color)
{
int argb = color.ToArgb();
int b = argb & 0xFF;
int g = (argb >> 8) & 0xFF;
int r = (argb >> 16) & 0xFF;
return (b << 16) | (g << 8) | r;
}
/// Win32 COLORREF (BGR) 轉 .NET Color
public static Color FromColorRef(int colorRef)
{
int r = colorRef & 0xFF;
int g = (colorRef >> 8) & 0xFF;
int b = (colorRef >> 16) & 0xFF;
return Color.FromArgb(r, g, b);
}
/// 帶 Alpha 的 COLORREF 轉換(若 Win32 擴展支援 Alpha)
public static Color FromColorRefWithAlpha(int colorRef, int alpha = 255)
{
int r = colorRef & 0xFF;
int g = (colorRef >> 8) & 0xFF;
int b = (colorRef >> 16) & 0xFF;
return Color.FromArgb(alpha, r, g, b);
}
}
// 測試往返轉換
Color original = Color.FromArgb(123, 200, 12);
int colorRef = ColorConverter.ToColorRef(original);
Color converted = ColorConverter.FromColorRef(colorRef);
Console.WriteLine($"原始: R={original.R}, G={original.G}, B={original.B}");
Console.WriteLine($"COLORREF: 0x{colorRef:X8}");
Console.WriteLine($"轉回: R={converted.R}, G={converted.G}, B={converted.B}");
Console.WriteLine($"一致: {original.R == converted.R && original.G == converted.G && original.B == converted.B}");
原始: R=123, G=200, B=12
COLORREF: 0x000C0C7B
轉回: R=123, G=200, B=12
一致: True
Color.ToArgb() 傳給 Win32:錯誤!位元組序不符,顏色會錯亂(紅藍互換)COLORREF 無 Alpha,轉換時預設 255(不透明)int 為有號,位元運算需注意符號延伸,建議用 uint 或 & 0xFF 遮罩RGB() 宏:同樣產生 BGR 格式,RGB(r,g,b) = (r | (g << 8) | (b << 16))核心口訣:.NET 是 ARGB(紅在中間),Win32 是 BGR(紅在最右)。轉換時務必拆解分量、重新組裝,不可直接傳遞整數值。封裝工具類可避免重複造輪子與錯誤。