[Back to WIN-OS2 SWAG index] [Back to Main SWAG index] [Original]
{
Here my tiny icofuncs unit for Windows. As I recall it, I also posted the C
version in windows.prog. Here my special translation for you Pascal users.
Note: the undocumented DumpIcon function I use, works 100% guaranteed in Win16.
Users of Win32 (NOT Win32s) should resort to the documented GetIconInfo. Now is
this code useful? I don't know. Perhaps if you want to convert your icons to
their monochrome equivalents. Well anyway, try it.
Bye, Alfons (2:500/121.6252 or a.hoogervorst@dosgg.nl)
{ icofuncs.pas.
Originally written in Pascal, then translated to C, reconverted to
Pascal, then again to C.
First posted in WINDOWS.PROG. Should have come to you through other
mail areas. Perhaps it's already translated to other languages.
But this one is authorized by me <g>.
No copyrights claimed: I donate the source to the public domain.
If you use it in your code, I won't mind my name appearing in any
credits. It's such a nice name :-).
Written by Alfons Hoogervorst
Internet E-mail <a.hoogervorst@dosgg.nl>
Fido E-mail <2:500/121.6252 (Alfons Hoogervorst)>
Only works with Win16. For Win32 users: use the GetIconInfo function.
}
unit icofuncs;
interface
uses
WinTypes;
type
HINSTANCE = THandle; { Clashes with System.hInstance :-) }
HGLOBAL = THandle;
{ When you resourcelock an HICON or HCURSOR you'll get a pointer to a
TCursorIconInfo structure. }
PCursorIconInfo = ^TCursorIconInfo;
TCursorIconInfo = record
ptHotSpot: TPoint;
wWidth, wHeight, wWidthBytes: Word;
byPlanes, byBitsPix: Byte;
end;
function DumpIcon(AInfo: PCursorIconInfo; var HeaderLen: Word;
var AndBits, XORMask: Pointer): LongInt;
function ColorToMonoIcon(hInst: HINSTANCE; hIconIn: HICON): HICON;
function IconToCursor(hInst: HINSTANCE; hIconIn: HICON; nHotSpotX,
nHotSpotY: Integer): HCURSOR;
implementation
uses
WinProcs;
const
COLORWHITE = $00FFFFFF;
COLORHALF = Longint(COLORWHITE div 2);
COLORBLACK = Longint(0);
COLORMAXDISTANCE = Longint(3 * Longint($ff * $ff));
COLORHALFDISTANCE = Longint(COLORMAXDISTANCE div 2);
{ In my C module the next x functions were macros. I could have created
some inline functions, but I didn't do this for the sake of
"portability" (whatever that means in PASCAL world)
}
{ What a pity Turbo Pascal doesn't support unsigned long integers }
function ColorDistance(r, g, b: Word): Longint; near;
begin
{ To get the real distance you should take the square root of
ColorDistance, but this is (ofcourse) unnecessary.
By the by: casting to Longint absolutely necessary. Try it without
the casts, and see what happens :-) }
ColorDistance := Longint(r * r) + Longint(g * g) + Longint(b * b)
end;
function Conv2Mono(r, g, b: Integer): Longint; near;
begin
if ColorDistance(r, g, b) > COLORHALFDISTANCE then
CONV2MONO := COLORWHITE
else CONV2MONO := COLORBLACK
end;
{ DumpIcon. This is a not documented function. Look in Undocumented Windows
what it's doing or how it works. Or mail me. }
function DumpIcon; external 'USER' index 459;
function ColorToMonoIcon(hInst: HINSTANCE; hIconIn: HICON): HICON;
label { For goto haters only <g> }
c2mi_unlockicon, c2mi_freebits;
var
hdcScreen, hdcSource, hdcResult: HDC;
hbmpSource, hbmpResult: HBITMAP;
lpIcon: PCursorIconInfo;
dwColor: Longint;
lpAnd, lpXor: PChar;
bmp: TBitmap;
begin
ColorToMonoIcon := 0;
lpIcon := PCursorIconInfo(LockResource(HGLOBAL(hIconIn)));
if (lpIcon = nil) then exit;
if (lpIcon^.byPlanes = $01) and (lpIcon^.byBitsPix = $01) then
goto c2mi_unlockicon;
{ Init. DCs. Icons Init DC's. Icons always seem to have device
dependent bitmaps. On a 4 bpp screen device, icon bitmaps have a
4 bpp DDB format. That's why a GetDIBits-conversion doesn't work.
So, the resulting mono icon is not real monochrome. It looks
monochrome, but it's just based on a device dependent bitmap }
hdcScreen := GetDC(0);
hdcSource := CreateCompatibleDC(hdcScreen);
hdcResult := CreateCompatibleDC(hdcScreen);
hbmpSource := CreateCompatibleBitmap(hdcScreen, lpIcon^.wWidth,
lpIcon^.wHeight);
hbmpResult := CreateCompatibleBitmap(hdcScreen, lpIcon^.wWidth,
lpIcon^.wHeight);
ReleaseDC(0, hdcScreen);
if (hdcSource = 0) or (hdcResult = 0) or (hbmpResult = 0) or
(hbmpSource = 0) then goto c2mi_freebits;
hbmpSource := SelectObject(hdcSource, hbmpSource);
hbmpResult := SelectObject(hdcResult, hbmpResult);
{ Draw & convert icon, OK not fast... First we need to black out
source (hbmResult will contain XOR-bitmap }
PatBlt(hdcSource, 0, 0, lpIcon^.wWidth, lpIcon^.wHeight, BLACKNESS);
DrawIcon(hdcSource, 0, 0, hIconIn);
for bmp.bmWidth := 0 to pred(lpIcon^.wWidth) do
for bmp.bmHeight := 0 to pred(lpIcon^.wHeight) do
begin
dwColor := GetPixel(hdcSource, bmp.bmWidth, bmp.bmHeight);
SetPixel(hdcResult, bmp.bmWidth, bmp.bmHeight, Conv2Mono(
GetRValue(dwColor), GetGValue(dwColor),
GetBValue(dwColor)))
end;
{ OK to restore old state of DC }
hbmpSource := SelectObject(hdcSource, hbmpSource);
hbmpResult := SelectObject(hdcResult, hbmpResult);
{ Now a starter's guide on creating icons. First we need a pointer
to our new data. We could use the data of lpIcon, but since this
struct is undocumented I've switched to paranoid level 100.
Win32 (not Win32s) offers the function GetIconInfo, so for
32-bits apps use GetIconInfo, not DumpIcon }
DumpIcon(lpIcon, Word(bmp.bmWidth), Pointer(lpAnd), Pointer(lpXor));
GetObject(hbmpResult, sizeof(TBitmap), @bmp);
dwColor := bmp.bmWidthBytes * bmp.bmHeight * bmp.bmPlanes;
{ Must allocate a little bit o' memory }
GetMem(lpXor, dwColor);
if (lpXor = nil) then goto c2mi_freebits;
GetBitmapBits(hbmpResult, dwColor, lpXor);
ColorToMonoIcon := CreateIcon(hInst, lpIcon^.wWidth, lpIcon^.wHeight,
lpIcon^.byPlanes, lpIcon^.byBitsPix, lpAnd, lpXor);
FreeMem(lpXor, dwColor);
{ Labels for goto haters only }
c2mi_freebits:
if (hbmpResult <> 0) then DeleteObject(hbmpResult);
if (hbmpSource <> 0) then DeleteObject(hbmpSource);
if (hdcSource <> 0) then DeleteDC(hdcSource);
if (hdcResult <> 0) then DeleteDC(hdcResult);
c2mi_unlockicon:
UnlockResource(HGLOBAL(hIconIn));
end;
function IconToCursor(hInst: HINSTANCE; hIconIn: HICON; nHotSpotX,
nHotSpotY: Integer): HCURSOR;
label
i2c_freebits, i2c_unlockicon;
var
hPseudoMonoIcon: HICON;
hdcScreen, hdcMonoIcon, hdcPseudoMonoIcon: HDC;
hbmpMonoIcon, hbmpPseudoMonoIcon: HBITMAP;
MonoIconBitmap: TBitmap;
lpXor, lpAnd: PChar;
lpIcon: PCursorIconInfo;
dummy: Longint;
begin
IconToCursor := 0;
hPseudoMonoIcon := ColorToMonoIcon(hInst, hIconIn);
if (hPseudoMonoIcon = 0) then exit;
lpIcon := PCursorIconInfo(LockResource(HGLOBAL(hIconIn)));
if lpIcon = nil then exit;
{ Create GDI objects }
hdcScreen := GetDC(0);
hdcMonoIcon := CreateCompatibleDC(hdcScreen);
hdcPseudoMonoIcon := CreateCompatibleDC(hdcScreen);
hbmpMonoIcon := CreateCompatibleBitmap(hdcMonoIcon, lpIcon^.wWidth,
lpIcon^.wHeight);
hbmpPseudoMonoIcon := CreateCompatibleBitmap(hdcScreen, lpIcon^.wWidth,
lpIcon^.wHeight);
ReleaseDC(0, hdcScreen);
{ Sanity checks }
if (hdcMonoIcon = 0) or (hdcPseudoMonoIcon = 0) or (hbmpMonoIcon = 0) or
(hbmpPseudoMonoIcon = 0) then goto i2c_freebits;
hbmpPseudoMonoIcon := SelectObject(hdcPseudoMonoIcon,
hbmpPseudoMonoIcon);
hbmpMonoIcon := SelectObject(hdcMonoIcon, hbmpMonoIcon);
{ Recreate Xor mask }
PatBlt(hdcPseudoMonoIcon, 0, 0, lpIcon^.wWidth, lpIcon^.wHeight,
BLACKNESS);
DrawIcon(hdcPseudoMonoIcon, 0, 0, hPseudoMonoIcon);
{ Convert to mono icon }
SetBkColor(hdcPseudoMonoIcon, COLORWHITE);
BitBlt(hdcMonoIcon, 0, 0, lpIcon^.wWidth, lpIcon^.wHeight,
hdcPseudoMonoIcon, 0, 0, SRCCOPY);
{ Reselect old bitmaps }
hbmpPseudoMonoIcon := SelectObject(hdcPseudoMonoIcon,
hbmpPseudoMonoIcon);
hbmpMonoIcon := SelectObject(hdcMonoIcon, hbmpMonoIcon);
{ Now we have a monochrome XOR bitmap. Time to get the XOR and
AND masks }
GetObject(hbmpMonoIcon, sizeof(TBitmap), @MonoIconBitmap);
DumpIcon(lpIcon, Word(dummy), Pointer(lpAnd), Pointer(lpXor));
dummy := MonoIconBitmap.bmWidthBytes * MonoIconBitmap.bmHeight *
MonoIconBitmap.bmPlanes;
GetMem(lpXor, dummy);
if (lpXor = nil) then goto i2c_freebits;
GetBitmapBits(hbmpMonoIcon, dummy, lpXor);
{ Create cursor }
IconToCursor := CreateCursor(hInst, nHotSpotX, nHotSpotY,
lpIcon^.wWidth, lpIcon^.wHeight, lpAnd, lpXor);
FreeMem(lpXor, dummy);
i2c_freebits:
if (hbmpPseudoMonoIcon <> 0) then DeleteObject(hbmpPseudoMonoIcon);
if (hbmpMonoIcon <> 0) then DeleteObject(hbmpMonoIcon);
if (hdcPseudoMonoIcon <> 0) then DeleteDC(hdcPseudoMonoIcon);
if (hdcMonoIcon <> 0) then DeleteDC(hdcMonoIcon);
i2c_unlockicon:
UnlockResource(HGLOBAL(hIconIn));
end;
function IconToBitmap(hIconIn: HICON): HBITMAP;
label itb_freebitmap, itb_freedc;
var
hbmpBitmap: HBITMAP;
hdcScreen, hdcBitmap: HDC;
x, y: Integer;
begin
IconToBitmap := 0;
x := GetSystemMetrics(SM_CXICON);
y := GetSystemMetrics(SM_CYICON);
hdcScreen := GetDC(0);
hdcBitmap := CreateCompatibleDC(hdcScreen);
hbmpBitmap := CreateCompatibleBitmap(hdcScreen, x, y);
ReleaseDC(0, hdcScreen);
if (hdcBitmap = 0) or (hbmpBitmap = 0) then goto itb_freebitmap;
hbmpBitmap := SelectObject(hdcBitmap, hbmpBitmap);
PatBlt(hdcBitmap, 0, 0, x, y, WHITENESS);
DrawIcon(hdcBitmap, 0, 0, hIconIn);
IconToBitmap := SelectObject(hdcBitmap, hbmpBitmap);
goto itb_freedc;
(* Are there any goto haters out there??? *)
itb_freebitmap:
if (hbmpBitmap = 0) then DeleteObject(hbmpBitmap);
itb_freedc:
if (hdcBitmap = 0) then DeleteDC(hdcBitmap);
end;
function CursorToIcon(hInst: HINSTANCE; hCursorIn: HCURSOR): HICON;
var
lpCursor: PCursorIconInfo;
wDummy: Word;
lpAnd, lpXor: POinter;
begin
CursorToIcon := 0;
lpCursor := PCursorIconInfo(LockResource(HGLOBAL(hCursorIn)));
if (lpCursor = nil) then exit;
if (DumpIcon(lpCursor, wDummy, lpAnd, lpXor) <> 0) then
CursorToIcon := CreateIcon(hInst, lpCursor^.wWidth,
lpCursor^.wHeight, 1, 1, lpAnd, lpXor);
UnlockResource(HGLOBAL(hCursorIn));
end;
end.
[Back to WIN-OS2 SWAG index] [Back to Main SWAG index] [Original]