• Welcome to Powerbasic Museum 2020-B.
 

News:

Forum in repository mode. No new members allowed.

Main Menu

Layered or DWM Composited Spinner

Started by Patrice Terrier, January 07, 2014, 11:02:08 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

James C. Fuller

Patrice,
  I know what your command lines are I retrieved then from the VS project and modified them to those shown.

I was looking more for your comments on my notes.

James

Patrice Terrier

#16
James--

QuoteWould you please address the needed? items
also how about /Oi. msdn says it may create larger exe.

I did check all the settings and as long as faster parameters do not produce larger EXE, i keep using them.
But this must be customized for each application.

For example in the case of DWMspinner the /Ox (full optimization) and /Ot (in favor of faster code) do not produce larger EXE, thus they could be kept.

...
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

Patrice Terrier

#17
The new optimized LAYERED versions are attached to this post.

And the new winner is C++ 64-bit with 10240 bytes, while PB is 11264 bytes.

Note: Starting with Windows 8, the WS_EX_LAYERED extended style can also be used with child Windows.

...
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

James C. Fuller

Patrice,
  I noticed you changed to __cdecl from __stdcall .
Was this the only change you made for the current size reduction?

James

James C. Fuller

Patrice,
  On closer examination of the source I would think getting the procedure address of the gdiplus functions  every time they are called would be very time consuming?

James

Patrice Terrier

#20
James--

Using either __cdecl or __stdcall wouldn't make any difference on the resulting size.

QuoteI would think getting the procedure address of the gdiplus functions  every time they are called would be very time consuming?
No, because using GetProcAddress, is always used under the hood by the languages specific encapsulations.
Using a global proc array or static variables to save the procedure addresses, would produce larger code and probably little speed gain. What could make a difference is the use of ordinal, but then you need to use a LIB file.

Dixit MSDN:
Calling GetProcAddress with an export ordinal, as opposed to the function name, is slightly faster if the DLL has many exported functions because the export ordinals serve as indexes into the DLL's export table. With an export ordinal, GetProcAddress can locate the function directly as opposed to comparing the specified name to the function names in the DLL's export table. However, you should call GetProcAddress with an export ordinal only if you have control over assigning the ordinals to the exported functions in the .DEF file.
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

Patrice Terrier

James--

Here is the version using static zProc hProc; to call GetProcAddress only once per session

//+--------------------------------------------------------------------------+
//|                                                                          |
//|                               PNG spinner                                |
//|                                                                          |
//|                       layered spinner annimation                         |
//|                                                                          |
//+--------------------------------------------------------------------------+
//|                                                                          |
//|                         Author Patrice TERRIER                           |
//|                            copyright(c) 2014                             |
//|                           www.zapsolution.com                            |
//|                        pterrier@zapsolution.com                          |
//|                                                                          |
//+--------------------------------------------------------------------------+
//|                  Project started on : 01-05-2013 (MM-DD-YYYY)            |
//|                        Last revised : 01-13-2013 (MM-DD-YYYY)            |
//+--------------------------------------------------------------------------+

#include <windows.h>
#include <WinBase.h>
#include <Dwmapi.h>

#define TIMER_DELAY   30
#define TIMER_SPINNER -1

// GDIPLUS Flat API
#ifndef _GDIPLUS_H
#define _GDIPLUS_H
struct IDirectDrawSurface7;
typedef signed   short  INT16;
typedef unsigned short  UINT16;
#include <pshpack8.h>   // set structure packing to 8
namespace DllExports {
#include "GdiplusMem.h"
};
#include "GdiplusBase.h"
#include "GdiplusEnums.h"
#include "GdiplusTypes.h"
#include "GdiplusInit.h"
#include "GdiplusPixelFormats.h"
#include "GdiplusColor.h"
#include "GdiplusMetaHeader.h"
#include "GdiplusImaging.h"
#include "GdiplusGpStubs.h"
#include "GdiplusHeaders.h"
#endif // !_GDIPLUS_HPP

struct PROP {
    HWND      hwnd;
    LONG_PTR  img;
    long      framecount;
    long      frametouse;
    HDC       hdc;
    HBITMAP   hbitmap;
    HMODULE   gdiplib;
    LONG_PTR  hgdiplus;
};

PROP gP;

#define long_proc typedef long (__stdcall *zProc)

long Load_GDIPLUS() {
    static long nRet;
    if (nRet == 0) {
        gP.gdiplib = LoadLibrary(L"GDIPLUS");
        if (gP.gdiplib != 0) { nRet = -1; }
    }
    return nRet;
}

long GdiplusStart(OUT LONG_PTR &hGDIplus, GdiplusStartupInput &inputbuf, IN LONG_PTR outputbuf) {
    long nRet = -1; // Error
    if (gP.gdiplib) {
        long_proc(LONG_PTR*, GdiplusStartupInput*, LONG_PTR);
        zProc hPROC = (zProc)GetProcAddress(gP.gdiplib, "GdiplusStartup");
        if (hPROC) {
            nRet = hPROC(&hGDIplus, &inputbuf, outputbuf);
        }
    }
    return nRet;
}

long GdiplusShutdown(IN LONG_PTR hGDIplus) {
    long nRet = -1; // Error
    if (gP.gdiplib) {
        long_proc(LONG_PTR);
        zProc hProc = (zProc)GetProcAddress(gP.gdiplib, "GdiplusShutdown");
        if (hProc) { nRet = hProc(hGDIplus); }
    }
    return nRet;
}

long GdipLoadImageFromFile(IN WCHAR* szImgName, OUT LONG_PTR &lpImg) {
    long nRet = -1; // Error
    lpImg = 0;
    if (gP.gdiplib) {
        long_proc(WCHAR*, LONG_PTR*);
        static zProc hProc;
        if (hProc == 0) { hProc = (zProc)GetProcAddress(gP.gdiplib, "GdipLoadImageFromFile"); }
        if (hProc) { nRet = hProc(szImgName, &lpImg); }
    }
    return nRet;
}

long GdipDeleteGraphics(IN LONG_PTR graphics) {
    long nRet = -1; // Error
    if (gP.gdiplib) {
        long_proc(LONG_PTR);
        static zProc hProc;
        if (hProc == 0) { hProc = (zProc)GetProcAddress(gP.gdiplib, "GdipDeleteGraphics"); }
        if (hProc) { nRet = hProc(graphics); }
    }
    return nRet;
}

long GdipDrawImageRectRectI(IN LONG_PTR graphics, IN LONG_PTR lpImg, IN long dstX, IN long dstY, IN long dstW, IN long dstH, IN long srcX, IN long srcY, IN long srcW, IN long srcH, IN long srcUnit, IN LONG_PTR imageattr, IN LONG_PTR lpCallback, IN LONG_PTR callbackdata) {
    long nRet = -1; // Error
    if (gP.gdiplib) {
        long_proc(LONG_PTR, LONG_PTR, long, long, long, long, long, long, long, long, long, LONG_PTR, LONG_PTR, LONG_PTR);
        static zProc hProc;
        if (hProc == 0) { hProc = (zProc)GetProcAddress(gP.gdiplib, "GdipDrawImageRectRectI"); }
        if (hProc) { nRet = hProc(graphics, lpImg, dstX, dstY, dstW, dstH, srcX, srcY, srcW, srcH, srcUnit, imageattr, lpCallback, callbackdata); }
    }
    return nRet;
}

long GdipDisposeImage(IN LONG_PTR lpImg) {
    long nRet = -1; // Error
    if (gP.gdiplib) {
        long_proc(LONG_PTR);
        static zProc hProc;
        if (hProc == 0) { hProc = (zProc)GetProcAddress(gP.gdiplib, "GdipDisposeImage"); }
        if (hProc) { nRet = hProc(lpImg); }
    }
    return nRet;
}

long GdipGetImageWidth(IN LONG_PTR lpImg, OUT long &imgW) {
    long nRet = -1; // Error
    imgW = 0;
    if (gP.gdiplib) {
        long_proc(LONG_PTR, long*);
        static zProc hProc;
        if (hProc == 0) { hProc = (zProc)GetProcAddress(gP.gdiplib, "GdipGetImageWidth"); }
        if (hProc) { nRet = hProc(lpImg, &imgW); }
    }
    return nRet;
}

long GdipGetImageHeight(IN LONG_PTR lpImg, OUT long &imgH) {
    long nRet = -1; // Error
    imgH = 0;
    if (gP.gdiplib) {
        long_proc(LONG_PTR, long*);
        static zProc hProc;
        if (hProc == 0) { hProc = (zProc)GetProcAddress(gP.gdiplib, "GdipGetImageHeight"); }
        if (hProc) { nRet = hProc(lpImg, &imgH); }
    }
    return nRet;
}

long GdipCreateFromHDC(IN HDC hDC, OUT LONG_PTR &graphics) {
    long nRet = -1; // Error
    graphics = 0;
    if (gP.gdiplib) {
        long_proc(HDC, LONG_PTR*);
        static zProc hProc;
        if (hProc == 0) { hProc = (zProc)GetProcAddress(gP.gdiplib, "GdipCreateFromHDC"); }
        if (hProc) { nRet = hProc(hDC, &graphics); }
    }
    return nRet;
}

LONG_PTR GdipStart() {
    if (Load_GDIPLUS()) {
        // Load the GDI+ Dll
        GdiplusStartupInput GpInput;
        GpInput.GdiplusVersion = 1;
        LONG_PTR hGDIplus = 0;
        if (GdiplusStart(hGDIplus, GpInput, NULL) == 0) {
            gP.hgdiplus = hGDIplus;
        }
    }
    return gP.hgdiplus;
}

void GdipEnd(IN LONG_PTR hGDIplus) {
    if (hGDIplus) { GdiplusShutdown(hGDIplus); }
}

BOOL FileExist(IN WCHAR* szFileSpec) {
    WIN32_FIND_DATA fd = { 0 };
    BOOL bRet = FALSE;
    if (wcslen(szFileSpec)) {
        HANDLE hFind;
        hFind = FindFirstFile(szFileSpec, &fd);
        if (hFind != INVALID_HANDLE_VALUE) {
            FindClose(hFind);
            bRet = TRUE;
        }
    }
    return bRet;
}

HBITMAP CreateDIBSection32(IN HDC hDC, IN long nWidth, IN long nHeight) {
    BITMAPINFO bi = { 0 };
    bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
    bi.bmiHeader.biWidth = nWidth;
    bi.bmiHeader.biHeight = -nHeight; // We want to use top left at coordinates 0,0.
    bi.bmiHeader.biPlanes = 1;
    bi.bmiHeader.biBitCount = 32;     // We use 32-bit (alpha channel).
    bi.bmiHeader.biCompression = BI_RGB;
    return CreateDIBSection(hDC, &bi, DIB_RGB_COLORS, NULL, NULL, NULL);
}

void Animate(IN LPVOID Delay) {
    LONG_PTR graphics = 0;
    RECT r = { 0 };
    SIZEL lpSize = { 0 };
    GetWindowRect(gP.hwnd, &r);
    lpSize.cx = r.right - r.left; lpSize.cy = r.bottom - r.top;
    SetRect(&r, 0, 0, lpSize.cx, lpSize.cy);

    if (gP.img == 0) { return; }

    RECT rw = { 0 };
    BLENDFUNCTION bf = { 0 };
    bf.BlendOp = AC_SRC_OVER;
    bf.BlendFlags = 0;
    bf.AlphaFormat = AC_SRC_ALPHA;
    bf.SourceConstantAlpha = 255;

    POINT lp = { 0 }, ptSrc = { 0 };

DoLoop:
    if (gP.hbitmap == 0) {
        HDC DesktopDC = GetDC(0);
        gP.hdc = CreateCompatibleDC(DesktopDC);
        gP.hbitmap = CreateDIBSection32(gP.hdc, lpSize.cx, lpSize.cy);
        SelectObject(gP.hdc, gP.hbitmap);
        ReleaseDC(0, DesktopDC);
    }
    if (gP.hbitmap) {
        // Create a GDI32 transparent brush, to clear the background of our permanent bitmap.
        HGDIOBJ hBrush = CreateSolidBrush(NULL);
        SelectObject(gP.hdc, hBrush);
        FillRect(gP.hdc, &r, (HBRUSH)hBrush);
        DeleteObject(hBrush);

        if (GdipCreateFromHDC(gP.hdc, graphics) == 0) {
            gP.frametouse += 1; if (gP.frametouse > gP.framecount) { gP.frametouse = 1; }
            if (gP.img) {
                GdipDrawImageRectRectI(graphics, gP.img, 0, 0, lpSize.cx, lpSize.cy, lpSize.cx * gP.frametouse - lpSize.cx, 0, lpSize.cx, lpSize.cy, 2, 0, NULL, NULL);
            }
            GdipDeleteGraphics(graphics);
        }

        GetWindowRect(gP.hwnd, &rw); lp.x = rw.left; lp.y = rw.top;
        UpdateLayeredWindow(gP.hwnd, 0, &lp, &lpSize, gP.hdc, &ptSrc, 0, &bf, ULW_ALPHA);

        Sleep((DWORD)Delay);
    }

    goto DoLoop; // Nothing faster than a good ASM jump.
}

long StartAnimation(IN long Delay) {
    long nRet = LB_ERR;
    DWORD dwThreadId = 0;
    HANDLE hThread = CreateThread(NULL,        // default security attributes
        0,                                     // use default stack size 
        (LPTHREAD_START_ROUTINE)Animate,       // thread function name
        (LPVOID)Delay,                         // argument to thread function
        0,                                     // use default creation flags
        &dwThreadId);                          // returns the thread identifier
    if (hThread) { nRet = 0; Sleep(100); }
    CloseHandle(hThread);
    return nRet;
}

void SpinnerInit(IN HWND hParent, IN HWND hWnd, IN WCHAR* szFileName, IN long nSpeedDelay) {

    if (IsWindow(hParent) == 0) { hParent = GetDesktopWindow(); }

    gP.framecount = 0;
    if (gP.img) { GdipDisposeImage(gP.img); gP.img = 0; }

    if (GdipLoadImageFromFile(szFileName, gP.img) == 0) {
        long w, h;
        RECT r = { 0 }; GetWindowRect(hParent, &r);
        GdipGetImageWidth(gP.img, w);
        GdipGetImageHeight(gP.img, h);
        gP.framecount = w / h;
        MoveWindow(hWnd, r.left + ((r.right - r.left - h) / 2), r.top + ((r.bottom - r.top - h) / 2), h, h, 0);

        // Compute animation speed, based on the number of frames.
        if (nSpeedDelay == 0) {
            if (gP.framecount < 4) {
                nSpeedDelay = 75;
            }
            else if (gP.framecount < 8) {
                nSpeedDelay = 50;
            }
            else if (gP.framecount < 12) {
                nSpeedDelay = 37;
            }
            else {
                nSpeedDelay = TIMER_DELAY;
            }
        }

        gP.hwnd = hWnd; StartAnimation(nSpeedDelay);

    }
}

LRESULT CALLBACK SpinnerProc(IN HWND hWnd, IN UINT uMsg, IN WPARAM wParam, IN LPARAM lParam) {
    switch (uMsg) {
    case WM_KEYDOWN:
        if (wParam == VK_ESCAPE) { DestroyWindow(hWnd); }
        break;

    case WM_NCHITTEST:
        return HTCAPTION;

    case WM_DESTROY:
        if (gP.hbitmap) { DeleteObject(gP.hbitmap); }
        if (gP.hdc) { DeleteDC(gP.hdc); }
        PostQuitMessage(0);
        if (gP.img) { GdipDisposeImage(gP.img); gP.img = 0; }
        return 0;
    }
    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) {
    long nRet = 0;
    HWND hWnd = 0, hParent = 0;
    long nSpeedDelay = 0;
    MSG msg = { 0 };
    WNDCLASSEX wcx = { 0 };
    WCHAR szClassName[] = L"ZSPIN_LAYERED";
    WCHAR szFileName[MAX_PATH] = { 0 };

    wcx.cbSize = sizeof(wcx);
    long IsInitialized = GetClassInfoEx(hInstance, szClassName, &wcx);
    if (IsInitialized == 0) {
        wcx.style = CS_HREDRAW | CS_VREDRAW;
        wcx.lpfnWndProc = &SpinnerProc;
        wcx.cbClsExtra = 0;
        wcx.cbWndExtra = 0;
        wcx.hInstance = hInstance;
        wcx.hIcon = NULL;
        wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
        wcx.hbrBackground = NULL;
        wcx.lpszMenuName = NULL;
        wcx.lpszClassName = szClassName;
        wcx.hIconSm = wcx.hIcon;
        if (RegisterClassEx(&wcx)) { IsInitialized = -1; }
    }

    if (IsInitialized) {
        hWnd = CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_TOPMOST | WS_EX_LAYERED, szClassName, szClassName, WS_POPUP | WS_VISIBLE,
            0, 0, 0, 0, NULL, (HMENU)NULL, hInstance, NULL);
        if (hWnd) {

            LONG_PTR hGDIplus = 0;
            RtlMoveMemory(&szFileName, lpCmdLine, sizeof(szFileName));
            if (FileExist(szFileName)) {
                hGDIplus = GdipStart(); if (hGDIplus) { SpinnerInit(hParent, hWnd, szFileName, nSpeedDelay); }
            }
            if (hGDIplus == 0) { DestroyWindow(hWnd); }

            UpdateWindow(hWnd);

            while (GetMessage(&msg, NULL, 0, 0)) {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
            if (hGDIplus) { GdipEnd(hGDIplus); }
            nRet = (long)msg.wParam;
        }
    }
    return nRet;
}


Note: That doesn't increase the size of the resulting EXE.
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

James C. Fuller

#22
Patrice,
  Now with the static added it is worthy of a bc9Basic translation :)
Note, I have never used single line If statements. I find it much easier to read source without them.
Nor do I ever put more than one statement on a line.
I removed a couple items:

typedef signed   short  INT16;
typedef unsigned short  UINT16;
#include <pshpack8.h>   // set structure packing to 8

the first 2 were not needed and the third I believe is the default.
the bc9Basic Do/Loop translates to an empty for block so no goto.
That's not to say bc9Basic doesn't use goto's. It does for SELECT/CASE.
I left the FileExist as is in a bc9 $CCODE block

James


Bc9Basic code:

'=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
'Patrices pngspinner(static) -> bc9Basic
'=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
$CPPHDR
$NOMAIN
$HEADER
    #include <windows.h>
    #include <WinBase.h>
    #include <Dwmapi.h>
    #define TIMER_DELAY   30
    #define TIMER_SPINNER -1
    // GDIPLUS Flat API
    #ifndef _GDIPLUS_H
        #define _GDIPLUS_H
        struct IDirectDrawSurface7;
        namespace DllExports {
        #include "GdiplusMem.h"
        };
        #include "GdiplusBase.h"
        #include "GdiplusEnums.h"
        #include "GdiplusTypes.h"
        #include "GdiplusInit.h"
        #include "GdiplusPixelFormats.h"
        #include "GdiplusColor.h"
        #include "GdiplusMetaHeader.h"
        #include "GdiplusImaging.h"
        #include "GdiplusGpStubs.h"
        #include "GdiplusHeaders.h"
    #endif // !_GDIPLUS_HPP
   
    #define long_proc typedef long (__stdcall *zProc)   
$HEADER

$ONEXIT "jcfpng.BAT $FILE$"

TYPE PROP
    hwnd         As HWND
    img            AS LONG_PTR
    framecount     AS long
    frametouse    AS long
    hdc            AS HDC
    hbitmap        AS HBITMAP
    gdiplib        AS HMODULE
    hgdiplus    AS LONG_PTR
End TYPE

RAW As PROP gP
'==============================================================================
Function Load_GDIPLUS() As long
    static nRet As long
    If nRet = 0 Then
        gP.gdiplib = LoadLibrary(L"GDIPLUS")
        If gP.gdiplib <> 0 Then
            nRet = -1
        End If
    End If
    Function = nRet
End Function
'==============================================================================
Function GdiplusStart(&hGDIplus As LONG_PTR ,&inputbuf As GdiplusStartupInput , outputbuf As LONG_PTR) As long
    Raw As long nRet = -1
    If gP.gdiplib Then
        long_proc(LONG_PTR*, GdiplusStartupInput*, LONG_PTR)
        Raw As zProc hProc = (zProc)GetProcAddress(gP.gdiplib, "GdiplusStartup")
        If hProc Then
            nRet = hProc(&hGDIplus, &inputbuf, outputbuf)
        End If
    End If
    Function = nRet
End Function
'==============================================================================
Function GdiplusShutdown(hGDIplus As LONG_PTR) As long
    Raw As long nRet = -1
    If gP.gdiplib Then
        long_proc(LONG_PTR)
        Raw As zProc hProc = (zProc)GetProcAddress(gP.gdiplib, "GdiplusShutdown")
        If hProc Then
            nRet = hProc(hGDIplus)
        End If
    End If
    Function = nRet
End Function
'==============================================================================
Function GdipLoadImageFromFile(szImgName As WCHAR Ptr, &lpImg As LONG_PTR ) As long
    Raw As long nRet = -1
    lpImg = 0
    If gP.gdiplib Then
        long_proc(WCHAR*, LONG_PTR*)
        static As zProc hProc
        If hProc = 0 Then
            hProc = (zProc)GetProcAddress(gP.gdiplib, "GdipLoadImageFromFile")
        End If
        If hProc Then
            nRet = hProc(szImgName, &lpImg)
        End If
    End If
    Function = nRet
End Function
'==============================================================================
Function GdipDeleteGraphics(graphics As LONG_PTR) As long
    Raw As long nRet = -1
    If gP.gdiplib Then
        long_proc(LONG_PTR)
        static As zProc hProc
        If hProc = 0 Then
            hProc = (zProc)GetProcAddress(gP.gdiplib, "GdipDeleteGraphics")
        End If
        If hProc Then
            nRet = hProc(graphics)
        End If
    End If
    Function = nRet
End Function
'==============================================================================
Function GdipDrawImageRectRectI(graphics As LONG_PTR ,lpImg As LONG_PTR ,dstX As long ,dstY As long ,dstW As long ,dstH As long ,srcX As long ,srcY As long ,srcW As long ,srcH As long ,srcUnit As long ,imageattr As LONG_PTR,lpCallback As LONG_PTR, callbackdata As LONG_PTR) As long
    Raw As long nRet = -1
    If gP.gdiplib Then
        long_proc(LONG_PTR, LONG_PTR, long, long, long, long, long, long, long, long, long, LONG_PTR, LONG_PTR, LONG_PTR)
        static As zProc hProc
        If hProc = 0 Then
            hProc = (zProc)GetProcAddress(gP.gdiplib, "GdipDrawImageRectRectI")
        End If
        If hProc Then
            nRet = hProc(graphics, lpImg, dstX, dstY, dstW, dstH, srcX, srcY, srcW, srcH, srcUnit, imageattr, lpCallback, callbackdata)
        End If
    End If
    Function = nRet
End Function
'==============================================================================
Function GdipDisposeImage(lpImg As LONG_PTR) As long
    Raw As long nRet = -1
    If gP.gdiplib Then
        long_proc(LONG_PTR)
        static As zProc hProc
        If hProc = 0 Then
            hProc = (zProc)GetProcAddress(gP.gdiplib, "GdipDisposeImage")
        End If
        If hProc Then
            nRet = hProc(lpImg)
        End If
    End If
    Function = nRet
End Function
'==============================================================================
Function GdipGetImageWidth(lpImg As LONG_PTR ,&imgW As long ) As long
    Raw As long nRet = -1
    imgW = 0
    If gP.gdiplib Then
        long_proc(LONG_PTR, long*)
        static As zProc hProc
        If hProc = 0 Then
            hProc = (zProc)GetProcAddress(gP.gdiplib, "GdipGetImageWidth")
        End If
        If hProc Then
            nRet = hProc(lpImg, &imgW)
        End If
    End If
    Function = nRet   
End Function
'==============================================================================
Function GdipGetImageHeight(lpImg As LONG_PTR ,&imgH As long ) As long
    Raw As long nRet = -1
    imgH = 0
    If gP.gdiplib Then
        long_proc(LONG_PTR, long*)
        static As zProc hProc
        If hProc = 0 Then
            hProc = (zProc)GetProcAddress(gP.gdiplib, "GdipGetImageHeight")
            If hProc Then
                nRet = hProc(lpImg, &imgH)
            End If
        End If
    End If
    Function = nRet   
End Function
'==============================================================================
Function GdipCreateFromHDC(hDC As HDC, &graphics As LONG_PTR ) As long
    Raw As long nRet = -1
    graphics = 0
    If gP.gdiplib Then
        long_proc(HDC, LONG_PTR*)
        static As zProc hProc
        If hProc = 0 Then
            hProc = (zProc)GetProcAddress(gP.gdiplib, "GdipCreateFromHDC")
        End If
        If hProc Then
            nRet = hProc(hDC, &graphics)
        End If
    End If
    Function = nRet
End Function
'==============================================================================
Function GdipStart() As LONG_PTR
    If Load_GDIPLUS() Then
        Raw As GdiplusStartupInput GpInput
        GpInput.GdiplusVersion = 1
        Raw As LONG_PTR hGDIplus = 0
        If GdiplusStart(hGDIplus, GpInput, NULL) = 0 Then
            gP.hgdiplus = hGDIplus
        End If
    End If
    Function = gP.hgdiplus
End Function
'==============================================================================
Sub GdipEnd(hGDIplus As LONG_PTR )
    If hGDIplus Then
        GdiplusShutdown(hGDIplus)
    End If
End Sub
'==============================================================================
$CCODE funcsub
BOOL FileExist(IN WCHAR* szFileSpec) {
    WIN32_FIND_DATA fd = { 0 };
    BOOL bRet = FALSE;
    if (wcslen(szFileSpec)) {
        HANDLE hFind;
        hFind = FindFirstFile(szFileSpec, &fd);
        if (hFind != INVALID_HANDLE_VALUE) {
            FindClose(hFind);
            bRet = TRUE;
        }
    }
    return bRet;
}
$CCODE
'==============================================================================
Function CreateDIBSection32(hDC As HDC, nWidth As long, nHeight As long) As HBITMAP
    Raw As BITMAPINFO bi = {0}
    bi.bmiHeader.biSize = sizeof(bi.bmiHeader)
    bi.bmiHeader.biWidth = nWidth
    bi.bmiHeader.biHeight = -nHeight ' We want to use top left at coordinates 0,0.
    bi.bmiHeader.biPlanes = 1
    bi.bmiHeader.biBitCount = 32     ' We use 32-bit (alpha channel).
    bi.bmiHeader.biCompression = BI_RGB
    Function = CreateDIBSection(hDC, &bi, DIB_RGB_COLORS, NULL, NULL, NULL)
End Function
'==============================================================================
Sub Animate(Delay As LPVOID)
    Raw As LONG_PTR graphics = 0
    Raw As RECT r = {0}
    Raw As SIZEL lpSize = { 0 }
   
    GetWindowRect(gP.hwnd, &r)
    lpSize.cx = r.right - r.left
    lpSize.cy = r.bottom - r.top
    SetRect(&r, 0, 0, lpSize.cx, lpSize.cy)
    If gP.img = 0 Then
        Exit Sub
    End If
    Raw As RECT rw = {0}
    Raw As BLENDFUNCTION bf = {0}
    bf.BlendOp = AC_SRC_OVER
    bf.BlendFlags = 0
    bf.AlphaFormat = AC_SRC_ALPHA
    bf.SourceConstantAlpha = 255

    Raw As POINT lp = {0}, ptSrc = {0}
    Do
        If gP.hbitmap = 0 Then
            Raw As HDC DesktopDC = GetDC(0)
            gP.hdc = CreateCompatibleDC(DesktopDC)
            gP.hbitmap = CreateDIBSection32(gP.hdc, lpSize.cx, lpSize.cy)
            SelectObject(gP.hdc, gP.hbitmap)
            ReleaseDC(0, DesktopDC)
        End If
       
        If gP.hbitmap Then
            ' Create a GDI32 transparent brush, to clear the background of our permanent bitmap.
            Raw As HGDIOBJ hBrush = CreateSolidBrush(NULL)
            SelectObject(gP.hdc, hBrush)
            FillRect(gP.hdc, &r, (HBRUSH)hBrush)
            DeleteObject(hBrush)
            If GdipCreateFromHDC(gP.hdc, graphics) = 0 Then
                gP.frametouse += 1
                If gP.frametouse > gP.framecount Then
                     gP.frametouse = 1   
                End If
                If gP.img Then
                    GdipDrawImageRectRectI(graphics, gP.img, 0, 0, lpSize.cx, lpSize.cy, lpSize.cx * gP.frametouse - lpSize.cx, 0, lpSize.cx, lpSize.cy, 2, 0, NULL, NULL)
                End If
                GdipDeleteGraphics(graphics)
            End If
            GetWindowRect(gP.hwnd, &rw)
            lp.x = rw.left
            lp.y = rw.top
            UpdateLayeredWindow(gP.hwnd, 0, &lp, &lpSize, gP.hdc, &ptSrc, 0, &bf, ULW_ALPHA)
            Sleep((DWORD)Delay)
        End If
                 
    Loop
End Sub
'==============================================================================
Function StartAnimation(Delay As long) As long
    Raw As long nRet = LB_ERR
    Raw As DWORD dwThreadId = 0
    Raw As HANDLE hThread = CreateThread(NULL, _        ' default security attributes
        0, _                                               ' use default stack size 
        (LPTHREAD_START_ROUTINE)Animate, _                ' thread function name
        (LPVOID)Delay, _                                   ' argument to thread function
        0, _                                               ' use default creation flags
        &dwThreadId)                                       ' returns the thread identifier
    If hThread Then
         nRet = 0
         Sleep(100)
    End If
    CloseHandle(hThread)
    Function = nRet
End Function
'==============================================================================
Sub SpinnerInit(hParent As HWND,hWnd As HWND, szFileName As WCHAR Ptr,nSpeedDelay As long)
    If IsWindow(hParent) = 0 Then
        hParent = GetDesktopWindow()
    End If
   
    gP.framecount = 0
    If gP.img Then
        GdipDisposeImage(gP.img)
        gP.img = 0
    End If
    If GdipLoadImageFromFile(szFileName, gP.img) = 0 Then
        Raw As long w,h
        Raw As RECT r = {0}
        GetWindowRect(hParent, &r)
        GdipGetImageWidth(gP.img, w)
        GdipGetImageHeight(gP.img, h)
        gP.framecount = w / h
        MoveWindow(hWnd, r.left + ((r.right - r.left - h) / 2), r.top + ((r.bottom - r.top - h) / 2), h, h, 0)

        ' Compute animation speed, based on the number of frames.
        If nSpeedDelay = 0 Then
            If gP.framecount < 4 Then
                nSpeedDelay = 75
            ElseIf gP.framecount < 8 Then
                nSpeedDelay = 50
            ElseIf gP.framecount < 12 Then
                nSpeedDelay = 37
            Else
                nSpeedDelay = TIMER_DELAY   
            End If
        End If
        gP.hwnd = hWnd
        StartAnimation(nSpeedDelay)       
    End If
End Sub
'==============================================================================
CALLBACK Function SpinnerProc()
   
    Select Case CBMSG
        Case WM_KEYDOWN
            If CBWPARAM = VK_ESCAPE Then
                DestroyWindow(CBHWND)
            End If   
        Case WM_NCHITTEST     
            Function = HTCAPTION
        Case WM_DESTROY
            If gP.hbitmap Then
                DeleteObject(gP.hbitmap)
            End If   
            If gP.hdc Then
                DeleteDC(gP.hdc)
            End If
            PostQuitMessage(0)
            If gP.img Then
                GdipDisposeImage(gP.img)
                gP.img = 0
            End If
            Function = 0
           
    End Select
End Function
'==============================================================================


Function wWinMain(hInst As HINSTANCE,hPrev As HINSTANCE,CmdLine As LPTSTR, CmdShow As int)
    'MessageBox(0,L"Hello",L"Caption",MB_OK)
    Dim As long nRet,nSpeedDelay
    Dim As HWND hWnd, hParent
    Dim As MSG msg
    Dim As WNDCLASSEX wcx
    Raw As WCHAR szClassName[]= L"ZSPIN_LAYERED"
    Dim As WCHAR szFileName[MAX_PATH]
    wcx.cbSize = sizeof(wcx)
    Raw As long IsInitialized = GetClassInfoEx(hInst, szClassName, &wcx)
   
    If IsInitialized = 0 Then
        wcx.style = CS_HREDRAW | CS_VREDRAW
        wcx.lpfnWndProc = &SpinnerProc
        wcx.cbClsExtra = 0
        wcx.cbWndExtra = 0
        wcx.hInstance = hInst
        wcx.hIcon = NULL
        wcx.hCursor = LoadCursor(NULL, IDC_ARROW)
        wcx.hbrBackground = NULL
        wcx.lpszMenuName = NULL
        wcx.lpszClassName = szClassName
        wcx.hIconSm = wcx.hIcon
        If RegisterClassEx(&wcx) Then
            IsInitialized = -1
        End If
    End If
    If IsInitialized Then
        hWnd = CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_TOPMOST | WS_EX_LAYERED, szClassName, szClassName, WS_POPUP | WS_VISIBLE, _
            0, 0, 0, 0, NULL, (HMENU)NULL, hInst, NULL)
        If hWnd Then
            Raw As LONG_PTR hGDIplus = 0
            RtlMoveMemory(&szFileName, CmdLine, sizeof(szFileName))
            If FileExist(szFileName) Then
                hGDIplus = GdipStart()
                If hGDIplus Then
                    SpinnerInit(hParent, hWnd, szFileName, nSpeedDelay)
                End If
            End If   
            If hGDIplus = 0 Then
                DestroyWindow(hWnd)
            End If
           
            UpdateWindow(hWnd)   
           
            While GetMessage(&msg, NULL, 0, 0)
                TranslateMessage(&msg)
                DispatchMessage(&msg)
            Wend
            If hGDIplus Then
                GdipEnd(hGDIplus)
            End If
            nRet = (long)msg.wParam
        End If
    End If
   
    Function = nRet
   
End Function



C++ translation:


// *********************************************************************
//  Created with bc9Basic - BASIC To C/C++ Translator (V) 9.1.8.5 (2014/01/18)
//       The bc9Basic translator (bc9.exe) was compiled with
//               g++ (rev0, Built by MinGW-W64 project) 4.8.2
// ----------------------------------------------------------------------
//                 BCX (c) 1999 - 2009 by Kevin Diggins
// *********************************************************************
//              Translated for compiling with a C++ Compiler
//                           On MS Windows
// *********************************************************************

// ***************************************************
// $HEADER
// ***************************************************

#include <windows.h>
#include <WinBase.h>
#include <Dwmapi.h>
#define TIMER_DELAY   30
#define TIMER_SPINNER -1
// GDIPLUS Flat API
#ifndef _GDIPLUS_H
#define _GDIPLUS_H
struct IDirectDrawSurface7;
namespace DllExports {
#include "GdiplusMem.h"
};
#include "GdiplusBase.h"
#include "GdiplusEnums.h"
#include "GdiplusTypes.h"
#include "GdiplusInit.h"
#include "GdiplusPixelFormats.h"
#include "GdiplusColor.h"
#include "GdiplusMetaHeader.h"
#include "GdiplusImaging.h"
#include "GdiplusGpStubs.h"
#include "GdiplusHeaders.h"
#endif // !_GDIPLUS_HPP

#define long_proc typedef long (__stdcall *zProc)


// *************************************************
//        User's GLOBAL ENUM blocks
// *************************************************

// *************************************************
//            System Defined Constants
// *************************************************

typedef const char* ccptr;
#define CCPTR const char*
#define cfree free
#define WAITKEY system("pause")
#define cSizeOfDefaultString 2048

// *************************************************
//            User Defined Constants
// *************************************************

#define PROP_CLASS struct _PROP*
// *************************************************
//          User Defined Types And Unions
// *************************************************


typedef struct _PROP
{
    HWND     hwnd;
    LONG_PTR  img;
    long     framecount;
    long     frametouse;
    HDC      hdc;
    HBITMAP  hbitmap;
    HMODULE  gdiplib;
    LONG_PTR  hgdiplus;
} PROP, *LPPROP;


// *************************************************
//            User Global Variables
// *************************************************

static PCHAR   *g_argv;
static int     g_argc;
PROP    gP;


// *************************************************
//               User Prototypes
// *************************************************

long    Load_GDIPLUS (void);
long    GdiplusStart (LONG_PTR &, GdiplusStartupInput &, LONG_PTR);
long    GdiplusShutdown (LONG_PTR);
long    GdipLoadImageFromFile (WCHAR* , LONG_PTR &);
long    GdipDeleteGraphics (LONG_PTR);
long    GdipDrawImageRectRectI (LONG_PTR, LONG_PTR, long, long, long, long, long, long, long, long, long, LONG_PTR, LONG_PTR, LONG_PTR);
long    GdipDisposeImage (LONG_PTR);
long    GdipGetImageWidth (LONG_PTR, long &);
long    GdipGetImageHeight (LONG_PTR, long &);
long    GdipCreateFromHDC (HDC, LONG_PTR &);
LONG_PTR GdipStart (void);
void    GdipEnd (LONG_PTR);
HBITMAP CreateDIBSection32 (HDC, long, long);
void    Animate (LPVOID);
long    StartAnimation (long);
void    SpinnerInit (HWND, HWND, WCHAR* , long);
LRESULT CALLBACK SpinnerProc (HWND, UINT, WPARAM, LPARAM);
int     wWinMain (HINSTANCE, HINSTANCE, LPTSTR, int);

// *************************************************
//            User Global Initialized Arrays
// *************************************************



// *************************************************
//                 Runtime Functions
// *************************************************


// ************************************
//       User C code
// ************************************

BOOL FileExist(IN WCHAR* szFileSpec) {
    WIN32_FIND_DATA fd = { 0 };
    BOOL bRet = FALSE;
    if (wcslen(szFileSpec)) {
        HANDLE hFind;
        hFind = FindFirstFile(szFileSpec, &fd);
        if (hFind != INVALID_HANDLE_VALUE) {
            FindClose(hFind);
            bRet = TRUE;
        }
    }
    return bRet;
}

// ************************************
//       User Subs and Functions
// ************************************

long Load_GDIPLUS ()
{
    static long     nRet;
    if(nRet == 0 )
    {
        gP.gdiplib = LoadLibrary( L"GDIPLUS");
        if(gP.gdiplib != 0 )
        {
            nRet = - 1;
        }
    }
    return nRet;
}


long GdiplusStart (LONG_PTR   &hGDIplus, GdiplusStartupInput   &inputbuf, LONG_PTR  outputbuf)
{
    long     nRet = -1;
    if(gP.gdiplib )
    {
        long_proc(LONG_PTR*, GdiplusStartupInput*, LONG_PTR);
        zProc    hProc = (zProc)GetProcAddress(gP.gdiplib, "GdiplusStartup");
        if(hProc )
        {
            nRet = hProc(  &hGDIplus,  &inputbuf, outputbuf);
        }
    }
    return nRet;
}


long GdiplusShutdown (LONG_PTR  hGDIplus)
{
    long     nRet = -1;
    if(gP.gdiplib )
    {
        long_proc(LONG_PTR);
        zProc    hProc = (zProc)GetProcAddress(gP.gdiplib, "GdiplusShutdown");
        if(hProc )
        {
            nRet = hProc( hGDIplus);
        }
    }
    return nRet;
}


long GdipLoadImageFromFile (WCHAR*  szImgName, LONG_PTR   &lpImg)
{
    long     nRet = -1;
    lpImg = 0;
    if(gP.gdiplib )
    {
        long_proc(WCHAR*, LONG_PTR*);
        static zProc    hProc;
        if(hProc == 0 )
        {
            hProc = ( zProc) GetProcAddress( gP.gdiplib, "GdipLoadImageFromFile");
        }
        if(hProc )
        {
            nRet = hProc( szImgName,  &lpImg);
        }
    }
    return nRet;
}


long GdipDeleteGraphics (LONG_PTR  graphics)
{
    long     nRet = -1;
    if(gP.gdiplib )
    {
        long_proc(LONG_PTR);
        static zProc    hProc;
        if(hProc == 0 )
        {
            hProc = ( zProc) GetProcAddress( gP.gdiplib, "GdipDeleteGraphics");
        }
        if(hProc )
        {
            nRet = hProc( graphics);
        }
    }
    return nRet;
}


long GdipDrawImageRectRectI (LONG_PTR  graphics, LONG_PTR  lpImg, long dstX, long dstY, long dstW, long dstH, long srcX, long srcY, long srcW, long srcH, long srcUnit, LONG_PTR  imageattr, LONG_PTR  lpCallback, LONG_PTR  callbackdata)
{
    long     nRet = -1;
    if(gP.gdiplib )
    {
        long_proc(LONG_PTR, LONG_PTR, long, long, long, long, long, long, long, long, long, LONG_PTR, LONG_PTR, LONG_PTR);
        static zProc    hProc;
        if(hProc == 0 )
        {
            hProc = ( zProc) GetProcAddress( gP.gdiplib, "GdipDrawImageRectRectI");
        }
        if(hProc )
        {
            nRet = hProc( graphics, lpImg, dstX, dstY, dstW, dstH, srcX, srcY, srcW, srcH, srcUnit, imageattr, lpCallback, callbackdata);
        }
    }
    return nRet;
}


long GdipDisposeImage (LONG_PTR  lpImg)
{
    long     nRet = -1;
    if(gP.gdiplib )
    {
        long_proc(LONG_PTR);
        static zProc    hProc;
        if(hProc == 0 )
        {
            hProc = ( zProc) GetProcAddress( gP.gdiplib, "GdipDisposeImage");
        }
        if(hProc )
        {
            nRet = hProc( lpImg);
        }
    }
    return nRet;
}


long GdipGetImageWidth (LONG_PTR  lpImg, long  &imgW)
{
    long     nRet = -1;
    imgW = 0;
    if(gP.gdiplib )
    {
        long_proc(LONG_PTR, long*);
        static zProc    hProc;
        if(hProc == 0 )
        {
            hProc = ( zProc) GetProcAddress( gP.gdiplib, "GdipGetImageWidth");
        }
        if(hProc )
        {
            nRet = hProc( lpImg,  &imgW);
        }
    }
    return nRet;
}


long GdipGetImageHeight (LONG_PTR  lpImg, long  &imgH)
{
    long     nRet = -1;
    imgH = 0;
    if(gP.gdiplib )
    {
        long_proc(LONG_PTR, long*);
        static zProc    hProc;
        if(hProc == 0 )
        {
            hProc = ( zProc) GetProcAddress( gP.gdiplib, "GdipGetImageHeight");
            if(hProc )
            {
                nRet = hProc( lpImg,  &imgH);
            }
        }
    }
    return nRet;
}


long GdipCreateFromHDC (HDC hDC, LONG_PTR   &graphics)
{
    long     nRet = -1;
    graphics = 0;
    if(gP.gdiplib )
    {
        long_proc(HDC, LONG_PTR*);
        static zProc    hProc;
        if(hProc == 0 )
        {
            hProc = ( zProc) GetProcAddress( gP.gdiplib, "GdipCreateFromHDC");
        }
        if(hProc )
        {
            nRet = hProc( hDC,  &graphics);
        }
    }
    return nRet;
}


LONG_PTR GdipStart ()
{
    if(Load_GDIPLUS())
    {
        GdiplusStartupInput  GpInput;
        GpInput.GdiplusVersion = 1;
        LONG_PTR  hGDIplus = 0;
        if(GdiplusStart(hGDIplus, GpInput, NULL) == 0 )
        {
            gP.hgdiplus = hGDIplus;
        }
    }
    return gP.hgdiplus;
}


void GdipEnd (LONG_PTR  hGDIplus)
{
    if(hGDIplus )
    {
        GdiplusShutdown(hGDIplus);
    }
}


HBITMAP CreateDIBSection32 (HDC hDC, long nWidth, long nHeight)
{
    BITMAPINFO  bi = {0};
    bi.bmiHeader.biSize = sizeof( bi.bmiHeader);
    bi.bmiHeader.biWidth = nWidth;
    bi.bmiHeader.biHeight = - nHeight;
    bi.bmiHeader.biPlanes = 1;
    bi.bmiHeader.biBitCount = 32;
    bi.bmiHeader.biCompression = BI_RGB;
    return CreateDIBSection(hDC, &bi, DIB_RGB_COLORS, NULL, NULL, NULL);
}


void Animate (LPVOID  delay)
{
    LONG_PTR  graphics = 0;
    RECT     r = {0};
    SIZEL    lpSize = {0};
    GetWindowRect(gP.hwnd, &r);
    lpSize.cx = r.right - r.left;
    lpSize.cy = r.bottom - r.top;
    SetRect( &r, 0, 0, lpSize.cx, lpSize.cy);
    if(gP.img == 0 )
    {
        return;
    }
    RECT     rw = {0};
    BLENDFUNCTION  bf = {0};
    bf.BlendOp = AC_SRC_OVER;
    bf.BlendFlags = 0;
    bf.AlphaFormat = AC_SRC_ALPHA;
    bf.SourceConstantAlpha = 255;
    POINT    lp = {0};
    POINT    ptSrc = {0};
    for(;;)
    {
        if(gP.hbitmap == 0 )
        {
            HDC      DesktopDC = GetDC(0);
            gP.hdc = CreateCompatibleDC( DesktopDC);
            gP.hbitmap = CreateDIBSection32( gP.hdc, lpSize.cx, lpSize.cy);
            SelectObject(gP.hdc, gP.hbitmap);
            ReleaseDC(0, DesktopDC);
        }
        if(gP.hbitmap )
        {
            HGDIOBJ  hBrush = CreateSolidBrush(NULL);
            SelectObject(gP.hdc, hBrush);
            FillRect(gP.hdc, &r, (HBRUSH)hBrush);
            DeleteObject(hBrush);
            if(GdipCreateFromHDC(gP.hdc, graphics) == 0 )
            {
                gP.frametouse += 1;
                if(gP.frametouse > gP.framecount )
                {
                    gP.frametouse = 1;
                }
                if(gP.img )
                {
                    GdipDrawImageRectRectI(graphics, gP.img, 0, 0, lpSize.cx, lpSize.cy, lpSize.cx * gP.frametouse - lpSize.cx, 0, lpSize.cx, lpSize.cy, 2, 0, NULL, NULL);
                }
                GdipDeleteGraphics(graphics);
            }
            GetWindowRect(gP.hwnd, &rw);
            lp.x = rw.left;
            lp.y = rw.top;
            UpdateLayeredWindow(gP.hwnd, 0, &lp, &lpSize, gP.hdc, &ptSrc, 0, &bf, ULW_ALPHA);
            Sleep((DWORD)delay);
        }
    }

}


long StartAnimation (long delay)
{
    long     nRet = LB_ERR;
    DWORD    dwThreadId = 0;
    HANDLE   hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Animate, (LPVOID)delay, 0, &dwThreadId);
    if(hThread )
    {
        nRet = 0;
        Sleep(100);
    }
    CloseHandle(hThread);
    return nRet;
}


void SpinnerInit (HWND hParent, HWND hWnd, WCHAR*  szFileName, long nSpeedDelay)
{
    if(IsWindow(hParent) == 0 )
    {
        hParent = GetDesktopWindow();
    }
    gP.framecount = 0;
    if(gP.img )
    {
        GdipDisposeImage(gP.img);
        gP.img = 0;
    }
    if(GdipLoadImageFromFile(szFileName, gP.img) == 0 )
    {
        long     w;
        long     h;
        RECT     r = {0};
        GetWindowRect(hParent, &r);
        GdipGetImageWidth(gP.img, w);
        GdipGetImageHeight(gP.img, h);
        gP.framecount = w / h;
        MoveWindow(hWnd, r.left + ((r.right - r.left - h) / 2), r.top + ((r.bottom - r.top - h) / 2), h, h, 0);
        if(nSpeedDelay == 0 )
        {
            if(gP.framecount < 4 )
            {
                nSpeedDelay = 75;
            }
            else if(gP.framecount < 8 )
            {
                nSpeedDelay = 50;
            }
            else if(gP.framecount < 12 )
            {
                nSpeedDelay = 37;
            }
            else
            {
                nSpeedDelay = TIMER_DELAY;
            }
        }
        gP.hwnd = hWnd;
        StartAnimation(nSpeedDelay);
    }
}


LRESULT CALLBACK SpinnerProc (HWND hWnd, UINT Msg, WPARAM  wParam, LPARAM  lParam)
{
    if(Msg == WM_KEYDOWN )
    {
        if(wParam == VK_ESCAPE )
        {
            DestroyWindow(hWnd);
        }
        goto L1001;
    }
    if(Msg == WM_NCHITTEST )
    {
        return HTCAPTION;
    }
    if(Msg == WM_DESTROY )
    {
        if(gP.hbitmap )
        {
            DeleteObject(gP.hbitmap);
        }
        if(gP.hdc )
        {
            DeleteDC(gP.hdc);
        }
        PostQuitMessage(0);
        if(gP.img )
        {
            GdipDisposeImage(gP.img);
            gP.img = 0;
        }
        return 0;
    }
L1001:
    ;
    return DefWindowProc(hWnd, Msg, wParam, lParam);
}


int wWinMain (HINSTANCE  hInst, HINSTANCE  hPrev, LPTSTR  CmdLine, int CmdShow)
{
    long     nRet = {0};
    long     nSpeedDelay = {0};
    HWND     hWnd = {0};
    HWND     hParent = {0};
    MSG      msg = {0};
    WNDCLASSEX  wcx = {0};
    WCHAR    szClassName[] = L"ZSPIN_LAYERED";
    WCHAR    szFileName[MAX_PATH] = {0};
    wcx.cbSize = sizeof( wcx);
    long     IsInitialized = GetClassInfoEx(hInst, szClassName, &wcx);
    if(IsInitialized == 0 )
    {
        wcx.style = CS_HREDRAW | CS_VREDRAW;
        wcx.lpfnWndProc =  &SpinnerProc;
        wcx.cbClsExtra = 0;
        wcx.cbWndExtra = 0;
        wcx.hInstance = hInst;
        wcx.hIcon = NULL;
        wcx.hCursor = LoadCursor( NULL, IDC_ARROW);
        wcx.hbrBackground = NULL;
        wcx.lpszMenuName = NULL;
        wcx.lpszClassName = szClassName;
        wcx.hIconSm = wcx.hIcon;
        if(RegisterClassEx( &wcx))
        {
            IsInitialized = - 1;
        }
    }
    if(IsInitialized )
    {
        hWnd = CreateWindowEx( WS_EX_TOOLWINDOW | WS_EX_TOPMOST | WS_EX_LAYERED, szClassName, szClassName, WS_POPUP | WS_VISIBLE, 0, 0, 0, 0, NULL, (HMENU)( HMENU) NULL, hInst, NULL);
        if(hWnd )
        {
            LONG_PTR  hGDIplus = 0;
            RtlMoveMemory( &szFileName, CmdLine, sizeof(szFileName));
            if(FileExist(szFileName))
            {
                hGDIplus = GdipStart();
                if(hGDIplus )
                {
                    SpinnerInit(hParent, hWnd, szFileName, nSpeedDelay);
                }
            }
            if(hGDIplus == 0 )
            {
                DestroyWindow(hWnd);
            }
            UpdateWindow(hWnd);
            while(GetMessage( &msg, NULL, 0, 0))
            {
                TranslateMessage( &msg);
                DispatchMessage( &msg);
            }

            if(hGDIplus )
            {
                GdipEnd(hGDIplus);
            }
            nRet = ( long) msg.wParam;
        }
    }
    return nRet;
}




My batch file:


CALL "%VS120COMNTOOLS%..\..\VC\vcvarsall.bat" x86_amd64

cl -c %1.cpp /GL /W3 /Gy /Zc:wchar_t /Zi /Gm- /Ox  /fp:precise /D "_UNICODE" /D "UNICODE" /errorReport:prompt /GF /WX- /Zc:forScope /GR- /Gd /Oy /Oi /MT /EHsc  /nologo /Ot



LINK %1.obj /OUT:"%1.exe" /MANIFEST:NO /LTCG /NXCOMPAT /DYNAMICBASE "Dwmapi.lib" "libcpmt.lib" "msvcrt.lib" "kernel32.lib" "user32.lib" "gdi32.lib" /MACHINE:X64 /OPT:REF /NODEFAULTLIB /NOLOGO









James C. Fuller

Patrice,
  I want to thank you for posting your excursions into c++.
This last one has shown how to really reduce app size.
I was especially interested in your dynamic calls to dll functions.
I am going to try this approach on an app I've written and maybe even use it in bc9Basic.

James

Patrice Terrier

James--

I am experimenting the same concept of size reduction with a 64-bit version of BassBox.

I have also written a couple of new functions to avoid the use of the string class.

Note: the size reduction is also increasing much the resulting code speed.

More to come...

Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

Patrice Terrier

Here is a nice new animation.

Very good for summer time  :)

...
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com