Mejor prueba esta revisión. Es prácticamente idéntica a la anteror pero incopora hEvent como miembro de la clase.
Código Delphi
[-]
unit _GifViewer;
interface
uses Windows, Messages, ActiveX;
function GdiplusStartup(var GdiToken: DWORD; Startup, Output: PBYTE): DWORD; stdcall external 'gdiplus';
function GdipLoadImageFromFile(lpFileName: PWideChar; var hImage: THANDLE): DWORD; stdcall external 'gdiplus';
function GdipLoadImageFromStream(pStream: IStream; var hImage: THANDLE): DWORD; stdcall external 'gdiplus';
function GdipDrawImageRectI(hGraphics, hImage: THANDLE; Left, Top, Width, Height: Integer): DWORD; stdcall external 'gdiplus';
function GdipCreateFromHDC(DC: HDC; var hGraphics: THANDLE): DWORD; stdcall external 'gdiplus';
function GdipImageSelectActiveFrame(hImage: THANDLE; DimensionID: PGUID; frameIndex: Integer): DWORD; stdcall external 'gdiplus';
function GdipImageGetFrameDimensionsList(hImage: THANDLE; dimensionIDs: PGUID; Count: Integer): DWORD; stdcall external 'gdiplus';
function GdipGetPropertyItemSize(hImage: THANDLE; dwPropId: Integer; var Size: UINT): Integer; stdcall external 'gdiplus';
function GdipGetPropertyItem(hImage: THANDLE; dwPropID, Size: Integer; lpBuffer: Pointer): DWORD; stdcall external 'gdiplus';
function GdipImageGetFrameCount(hImage: THANDLE; lpDimensionID: PGUID; out Count: UINT): DWORD; stdcall external 'gdiplus';
function GdipGetImageWidth(hImage: THANDLE; var Width: UINT): DWORD; stdcall external 'gdiplus';
function GdipGetImageHeight(hImage: THANDLE; var Height: UINT): DWORD; stdcall external 'gdiplus';
function GdipDeleteGraphics(hGraphics: THANDLE): DWORD; stdcall external 'gdiplus';
function GdipDisposeImage(hImage: THANDLE): DWORD; stdcall external 'gdiplus';
procedure GdiplusShutdown(GdiToken: DWORD); stdcall external 'gdiplus';
function SHCreateMemStream(pInit: PBYTE; cbInit: DWORD): Pointer; stdcall external 'shlwapi';
type
TGifViewer = class
private
Wnd: HWND;
OldWndProc: Pointer;
OldUserData: DWORD;
gdiplusToken: DWORD;
hThread: THANDLE;
hEvent: THandle;
hGdipImage: THANDLE;
Width: integer;
Height: integer;
Frames: UINT;
function WndProc(Handle: HWND; Msg: DWORD; WParam: DWORD; LParam: DWORD): DWORD; stdcall;
public
Center: boolean;
Left: integer;
Top: integer;
function GifView(Handle: HWND; FileName: PWCHAR; VCenter: boolean = false): boolean;
function GifViewFromResource(Handle: HWND; ID_GIF: PWCHAR; VCenter: boolean = false): boolean;
function SetHandle(Handle: THANDLE): boolean;
function LoadFile(FileName: PWCHAR): boolean;
function LoadFromResource(ID_GIF: PWCHAR): boolean;
function GetWidth: integer;
function GetHeight: integer;
function GetFrames: UINT;
function Start: boolean;
procedure Finish;
constructor Create;
destructor Destroy; override;
end;
PGifViewer = ^TGifViewer;
TPropertyItem = record
id: ULONG;
length: ULONG;
_type: WORD;
value: Pointer;
end;
PPropertyItem = ^TPropertyItem;
const
PropertyTagFrameDelay = $5100;
var
GDI: DWORD = 0;
implementation
function RePaintWindow(Wnd: HWND): boolean;
var
Rect: TRect;
begin
GetClientRect(Wnd, Rect);
Result:= RedrawWindow(Wnd, @Rect, 0, RDW_INVALIDATE or RDW_ERASE or RDW_UPDATENOW or RDW_ALLCHILDREN);
end;
function ThGif(GV: TGifViewer): DWORD; stdcall;
var
Wait: PIntegerArray;
Pi: PPropertyItem;
DC: HDC;
EvResult: DWORD;
hGdipGraphics: THANDLE;
nBytes, Frames, Index: UINT;
FrameDimensionTime: TGUID;
Left, Top: integer;
CR: TRect;
begin
Left:= GV.Left;
Top:= GV.Top;
if GV.hEvent <> 0 then EvResult:= WaitForSingleObject(GV.hEvent, INFINITE);
if (GV.hGdipImage <> 0) and (GV.Wnd <> 0) AND (EvResult = WAIT_OBJECT_0) then
begin
GdipGetPropertyItemSize(GV.hGdipImage, PropertyTagFrameDelay, nBytes);
Pi:= Pointer(LocalAlloc(LMEM_FIXED, nBytes));
GdipGetPropertyItem(GV.hGdipImage, PropertyTagFrameDelay, nBytes, Pi);
GdipImageGetFrameDimensionsList(GV.hGdipImage, @FrameDimensionTime, 1);
GdipImageGetFrameCount(GV.hGdipImage, @FrameDimensionTime, Frames);
Index:= 0;
Wait:= PIntegerArray(Pi.value);
if Pi._type = sizeof(DWORD) then
repeat
if GV.Center then
begin
GetClientRect(GV.Wnd, CR);
Left:= (CR.right - GV.Width) div 2;
Top:= (CR.bottom - GV.Height) div 2;
end;
DC:= GetDC(GV.Wnd);
GdipCreateFromHDC(DC, hGdipGraphics);
GdipImageSelectActiveFrame(GV.hGdipImage, @FrameDimensionTime, Index);
GdipDrawImageRectI(hGdipGraphics, GV.hGdipImage, Left, Top, GV.Width, GV.Height);
GdipDeleteGraphics(hGdipGraphics);
ReleaseDC(GV.Wnd, DC);
Sleep(Wait[Index] * 10);
Index:= (Index + 1) mod Frames;
until (GV.Wnd = 0) or (GV.hGdipImage = 0);
end;
LocalFree(HLOCAL(Pi));
Result:= 0;
end;
function DefWndProc(Handle: HWND; Msg: DWORD; WParam: DWORD; LParam: DWORD): DWORD; stdcall;
var
pGifViewer: TGifViewer;
begin
pGifViewer:= TGifViewer(GetWindowLong(Handle, GWL_USERDATA));
if pGifViewer <> nil then
begin
if ((Msg = WM_PAINT) or (Msg = WM_SHOWWINDOW)) and (pGifViewer.hEvent <> 0) then
SetEvent(pGifViewer.hEvent);
Result:= pGifViewer.WndProc(Handle, Msg, WParam, LParam)
end
else
Result:= DefWindowProc(Handle, Msg, WParam, LParam);
end;
function TGifViewer.WndProc(Handle: HWND; Msg: DWORD; WParam: DWORD; LParam: DWORD): DWORD; stdcall;
var
R: TRect;
begin
R.Left:= Left; R.Top:= Top; R.Right:= Left+Width; R.Bottom:= Top+Height;
if (Msg = WM_PAINT) and (hGdipImage <> 0) then
ValidateRect(Wnd, @R)
else if (Msg = WM_SIZE) and (hGdipImage <> 0) and Center then
begin
InvalidateRect(Wnd, @R, true);
CallWindowProc(OldWndProc, Wnd, WM_PAINT, 0, 0);
end;
Result:= CallWindowProc(OldWndProc, Handle, Msg, WParam, LParam);
end;
function TGifViewer.SetHandle(Handle: THANDLE): boolean;
begin
Result:= false;
if(Pointer(GetWindowLong(Handle, GWL_WNDPROC)) <> @DefWndProc) then
begin
SuspendThread(hThread);
if (Wnd <> 0) then
begin
SetWindowLong(Wnd, GWL_USERDATA, OldUserData);
SetWindowLong(Wnd, GWL_WNDPROC, LongInt(OldWndProc));
RePaintWindow(Wnd);
Wnd:= 0;
end;
if (Handle <> 0) and IsWindow(Handle) then
begin
Wnd:= Handle;
OldUserData:= SetWindowLong(Wnd, GWL_USERDATA, LongInt(self));
OldWndProc:= Pointer(SetWindowLong(Wnd, GWL_WNDPROC, LongInt(@DefWndProc)));
RePaintWindow(Wnd);
end;
Result:= true;
ResumeThread(hThread);
end;
end;
function TGifViewer.LoadFile(FileName: PWCHAR): boolean;
var
FrameDimensionTime: TGUID;
begin
Finish;
if GdipLoadImageFromFile(FileName, hGdipImage) = 0 then
begin
GdipGetImageWidth(hGdipImage, UINT(Width));
GdipGetImageHeight(hGdipImage, UINT(Height));
GdipImageGetFrameDimensionsList(hGdipImage, @FrameDimensionTime, 1);
GdipImageGetFrameCount(hGdipImage, @FrameDimensionTime, UINT(Frames));
end
else hGdipImage:= 0;
Result:= hGdipImage <> 0;
end;
function TGifViewer.LoadFromResource(ID_GIF: PWCHAR): boolean;
const
RT_RCDATAW: PWCHAR = MakeIntResourceW(10);
var
FrameDimensionTime: TGUID;
Res: HRSRC;
ResSize: DWORD;
ResData: HGLOBAL;
Stream: IStream;
begin
Finish;
Res:= FindResourceW(0, ID_GIF, RT_RCDATAW);
if Res <> 0 then
begin
ResSize:= SizeofResource(0, Res);
ResData:= LoadResource(0, Res);
Stream:= IStream(SHCreateMemStream(PBYTE(LockResource(ResData)), ResSize));
if GdipLoadImageFromStream(Stream, hGdipImage) = 0 then
begin
GdipGetImageWidth(hGdipImage, UINT(Width));
GdipGetImageHeight(hGdipImage, UINT(Height));
GdipImageGetFrameCount(hGdipImage, @FrameDimensionTime, UINT(Frames));
end
else hGdipImage:= 0;
Stream._Release;
end;
Result:= hGdipImage <> 0;
end;
function TGifViewer.GifView(Handle: HWND; FileName: PWCHAR; VCenter: boolean): boolean;
begin
Finish;
LoadFile(FileName);
SetHandle(Handle);
Center:= VCenter;
Result:= Start;
end;
function TGifViewer.GifViewFromResource(Handle: HWND; ID_GIF: PWCHAR; VCenter: boolean): boolean;
begin
Finish;
LoadFromResource(ID_GIF);
SetHandle(Handle);
Center:= VCenter;
Result:= Start;
end;
procedure TGifViewer.Finish;
begin
SetEvent(hEvent); if hGdipImage <> 0 then
begin
GdipDisposeImage(hGdipImage);
hGdipImage:= 0;
WaitForSingleObject(hThread, INFINITE); CloseHandle(hThread);
hThread:= 0;
end;
Left:= 0;
Top:= 0;
RePaintWindow(Wnd);
end;
function TGifViewer.Start(): boolean;
begin
if (Wnd <> 0) and (hGdipImage <> 0) and (hThread = 0) then
hThread:= CreateThread(nil, 0, @ThGif, self, 0, PDWORD(0)^);
Result:= hThread <> 0;
end;
function TGifViewer.GetWidth: integer;
begin
Result:= Width;
end;
function TGifViewer.GetHeight: integer;
begin
Result:= Height;
end;
function TGifViewer.GetFrames: UINT;
begin
Result:= Frames;
end;
constructor TGifViewer.Create;
var
GdiPlusStartupInput: array[0..2] of int64;
begin
FillChar(GdiPlusStartupInput, sizeof(GdiPlusStartupInput), 0);
GdiPlusStartupInput[0]:= 1;
if GdiplusStartup(gdiplusToken, @GdiPlusStartupInput, nil) = 0 then inc(GDI);
if hEvent = 0 then hEvent:= CreateEvent(nil, true, false, nil);
end;
destructor TGifViewer.Destroy;
begin
dec(GDI);
Finish;
CloseHandle(hEvent);
SetHandle(0);
if GDI = 0 then GdiplusShutdown(gdiplusToken);
inherited Destroy;
end;
end.
Saludos.