PlanetSquires Forums

Support Forums => WinFBX - Windows Framework for FreeBASIC => Topic started by: José Roca on April 28, 2016, 08:05:53 AM

Title: CWindow RC03
Post by: José Roca on April 28, 2016, 08:05:53 AM
CWindow release candidate 3.

Added support for subclassing using SetWindowSubclass.

For the uIdSubclass parameter you can use any positive value except &hFFFFFFFF. CWindow uses the reserved default value of &hFFFFFFF to know if it has to use the old way of subclassing or the new way with SetWindowSubclass.

For more information about subclassing controls see:
https://msdn.microsoft.com/en-us/library/bb773183%28VS.85%29.aspx
Title: Re: CWindow RC03
Post by: José Roca on April 28, 2016, 08:07:49 AM
The following example demonstrates how to subclass a button using the new support for SetWindowSubclass.


' ########################################################################################
' Microsoft Windows
' File: CW_ButtonSubclass2.fbtpl
' Contents: CWindow with a subclassed button
' Subclasses the control using SetWindowSubclass.
' Compiler: FreeBasic 32 & 64 bit
' Copyright (c) 2016 Jose Roca. Freeware. Use at your own risk.
' THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
' EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
' MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
' ########################################################################################

#define unicode
#INCLUDE ONCE "windows.bi"
#INCLUDE ONCE "Afx/CWindow.inc"

USING Afx.CWindowClass

CONST IDC_BUTTON = 1001

DECLARE FUNCTION WinMain (BYVAL hInstance AS HINSTANCE, _
                          BYVAL hPrevInstance AS HINSTANCE, _
                          BYVAL szCmdLine AS ZSTRING PTR, _
                          BYVAL nCmdShow AS LONG) AS LONG

   END WinMain(GetModuleHandleW(""), NULL, COMMAND(), SW_NORMAL)

' ========================================================================================
' Window procedure
' ========================================================================================
FUNCTION WndProc (BYVAL hWnd AS HWND, BYVAL uMsg AS UINT, BYVAL wParam AS WPARAM, BYVAL lParam AS LPARAM) AS LRESULT

   DIM pWindow AS CWindow PTR

   SELECT CASE uMsg

      CASE WM_CREATE
         EXIT FUNCTION

      CASE WM_COMMAND
         SELECT CASE LOWORD(wParam)
            ' // If ESC key pressed, close the application sending an WM_CLOSE message
            CASE IDCANCEL
               IF HIWORD(wParam) = BN_CLICKED THEN
                  SendMessageW hwnd, WM_CLOSE, 0, 0
                  EXIT FUNCTION
               END IF
         END SELECT

      CASE WM_SIZE
         IF wParam <> SIZE_MINIMIZED THEN
            ' // Resize the buttons
            pWindow = CAST(CWindow PTR, GetPropW(hwnd, "CWINDOWPTR"))
            pWindow->MoveWindow GetDlgItem(hwnd, IDC_BUTTON), pWindow->ClientWidth - 120, pWindow->ClientHeight - 50, 75, 23, CTRUE
         END IF

    CASE WM_DESTROY
         PostQuitMessage(0)
         EXIT FUNCTION

   END SELECT

   FUNCTION = DefWindowProcW(hWnd, uMsg, wParam, lParam)

END FUNCTION
' ========================================================================================

' ========================================================================================
' Processes messages for the subclassed Button window.
' ========================================================================================
FUNCTION Button_SubclassProc ( _
   BYVAL hwnd   AS HWND, _                 ' // Control window handle
   BYVAL uMsg   AS UINT, _                 ' // Type of message
   BYVAL wParam AS WPARAM, _               ' // First message parameter
   BYVAL lParam AS LPARAM, _               ' // Second message parameter
   BYVAL uIdSubclass AS UINT_PTR, _        ' // The subclass ID
   BYVAL dwRefData AS DWORD_PTR _          ' // Pointer to reference data
   ) AS LRESULT

   SELECT CASE uMsg

      CASE WM_GETDLGCODE
         ' // All keyboard input
         FUNCTION = DLGC_WANTALLKEYS
         EXIT FUNCTION

      CASE WM_LBUTTONDOWN
         MessageBoxW(GetParent(hwnd), "Click", "FreeBasic", MB_OK)
         EXIT FUNCTION

      CASE WM_KEYDOWN
         SELECT CASE LOWORD(wParam)
            CASE VK_ESCAPE
               SendMessageW(GetParent(hwnd), WM_CLOSE, 0, 0)
               EXIT FUNCTION
         END SELECT

      CASE WM_DESTROY
         ' // REQUIRED: Remove control subclassing
         RemoveWindowSubclass hwnd, @Button_SubclassProc, uIdSubclass

   END SELECT

   FUNCTION = DefSubclassProc(hwnd, uMsg, wParam, lParam)

END FUNCTION
' ========================================================================================

' ========================================================================================
' Main
' ========================================================================================
FUNCTION WinMain (BYVAL hInstance AS HINSTANCE, _
                  BYVAL hPrevInstance AS HINSTANCE, _
                  BYVAL szCmdLine AS ZSTRING PTR, _
                  BYVAL nCmdShow AS LONG) AS LONG

   ' // Set process DPI aware
   AfxSetProcessDPIAware

   DIM pWindow AS CWindow
   pWindow.Create(NULL, "CWindow with a subclassed button", @WndProc)
   pWindow.SetClientSize(500, 320)
   pWindow.Center

   ' // Add a subclassed button without position or size (it will be resized in the WM_SIZE message).
   pWindow.AddControl("Button", pWindow.hWindow, IDC_BUTTON, "Click me", , , , , , , , _
      CAST(WNDPROC, @Button_SubclassProc), IDC_BUTTON, CAST(DWORD_PTR, @pWindow))

   

   FUNCTION = pWindow.DoEvents(nCmdShow)

END FUNCTION
' ========================================================================================

Title: Re: CWindow RC03
Post by: José Roca on April 28, 2016, 08:16:35 AM
Two of the added benefits are that you can use the same subclass procedure for several controls and identify them thanks to the uIdSubclass (for example passing the ID of the control), and that you can pass a pointer to reference data.
Title: Re: CWindow RC03
Post by: José Roca on April 28, 2016, 08:33:32 AM
SetWindowSubclass, GetWindowSubclass, RemoveWindowSubclass and DefSubclassProc were made available for the first time in ComCtl32.dll version 6; therefore, can only be used with Windows XP or superior.

ComCtl32.dll version 6 is Unicode only. The common controls supported by ComCtl32.dll version 6 should not be subclassed (or superclassed) with ANSI window procedures.
Title: Re: CWindow RC03
Post by: José Roca on April 29, 2016, 05:13:06 PM
Next version will include a little class to create tooltips.


' ########################################################################################
' CToolTip class
' Creates a tooltip control
' ########################################################################################
TYPE CTooltip

   Private:
      m_hTooltip AS HWND   ' // Tooltip handle
      m_hwndCtrl AS HWND   ' // Handle of the control
      m_cbSize AS LONG     ' // Size of the TOOLINFO structure
      m_bBalloon AS LONG   ' // Balloon
      m_bCentered AS LONG  ' // Centered

   Public:
      DECLARE CONSTRUCTOR (BYVAL hwndCtrl AS HWND, BYREF wszText AS CONST WSTRING = "", BYVAL bBalloon AS LONG = 0, BYVAL bCentered AS LONG = 0)
      DECLARE DESTRUCTOR
      DECLARE PROPERTY hTooltip () AS HWND
      DECLARE PROPERTY TipText (BYREF wszText AS CONST WSTRING)
      DECLARE SUB SetTitle (BYVAL hIcon AS HANDLE, BYREF wszTitle AS CONST WSTRING)

END TYPE
' ========================================================================================

' ========================================================================================
' CTooltip constructor
' Usage example: DIM pTooltip AS CTooltip = CTooltip(hButton, "This is a tooltip", CTRUE, CTRUE)
' ========================================================================================
CONSTRUCTOR CTooltip (BYVAL hwndCtrl AS HWND, BYREF wszText AS CONST WSTRING = "", BYVAL bBalloon AS LONG = 0, BYVAL bCentered AS LONG = 0)
   ' // Creates the tooltip control
   DIM dwStyle AS DWORD = WS_POPUP OR TTS_ALWAYSTIP
   IF bBalloon THEN dwStyle = dwStyle OR TTS_BALLOON
   IF .IsWindow(hwndCtrl) THEN
      m_hTooltip = .CreateWindowExW(0, "tooltips_class32", "", dwStyle, 0, 0, 0, 0, NULL, NULL, NULL, NULL)
      IF m_hTooltip THEN
      END IF
   END IF
   ' // Registers the window with the tooltip control
   ' // 32-bit: The size of the TOOLINFO structure is of 48 bytes in
   '    version 6 of comctl32.dll, and of 44 bytes in lower versions.
   ' // 64-bit: The size of the TOOLINFO structure is of 72 bytes in
   '    version 6 of comctl32.dll, and of 64 bytes in lower versions.
   DIM tti AS TOOLINFOW
#ifdef __FB_64BIT__
   IF AfxComCtlVersion < 600 THEN m_cbSize = 64 ELSE m_cbSize = 72
#else
   IF AfxComCtlVersion < 600 THEN m_cbSize = 44 ELSE m_cbSize = 48
#endif
   tti.cbSize = m_cbSize
   tti.uFlags = TTF_IDISHWND OR TTF_SUBCLASS
   IF bCentered THEN tti.uFlags = tti.uFlags OR TTF_CENTERTIP
   m_hwndCtrl = hwndCtrl
   tti.hwnd = .GetParent(m_hwndCtrl)
   tti.hinst = .GetModuleHandleW(NULL)
   ' // The length of the string must not exceed of 80 characters, including the terminating null
   DIM wszTooltipText AS WSTRING * 80
   wszTooltipText = wszText
   tti.lpszText = @wszTooltipText
   tti.uId = CAST(UINT_PTR, m_hwndCtrl)
   .SendMessageW m_hTooltip, TTM_ADDTOOLW, 0, CAST(LPARAM, @tti)
   m_bBalloon = bBalloon
   m_bCentered = bCentered
END CONSTRUCTOR
' ========================================================================================

' ========================================================================================
' CTooltip destructor
' ========================================================================================
DESTRUCTOR CTooltip
   ' // Removes the tool from the tooltip control.
   DIM tti AS TOOLINFOW
   tti.cbSize = m_cbSize
   tti.hwnd = .GetParent(m_hwndCtrl)
   tti.uId = CAST(UINT_PTR, m_hwndCtrl)
   .SendMessageW(m_hTooltip, TTM_DELTOOLW, 0, CAST(LPARAM, @tti))
END DESTRUCTOR
' ========================================================================================

' ========================================================================================
' Returns the handle of the tooltip control
' ========================================================================================
PROPERTY CTooltip.hTooltip () AS HWND
   PROPERTY = m_hTooltip
END PROPERTY
' ========================================================================================

' ========================================================================================
' Sets/replaces the text of a tooltip control
' ========================================================================================
PROPERTY CTooltip.TipText (BYREF wszText AS CONST WSTRING)
   ' // The length of the text must not exceed of 80 characters, including the terminating null.
   DIM wszTooltipText AS WSTRING * 80
   wszTooltipText = wszText
   DIM tti AS TOOLINFOW
   tti.cbSize = m_cbSize
   tti.hwnd = .GetParent(m_hwndCtrl)
   tti.uId = CAST(UINT_PTR, m_hwndCtrl)
   ' // Retrieve the tooltip information
   .SendMessageW(m_hTooltip, TTM_GETTOOLINFOW, 0, CAST(LPARAM, @tti))
   IF .SendMessageW(m_hTooltip, TTM_GETTOOLINFOW, 0, CAST(LPARAM, @tti)) THEN
      tti.lpszText = @wszTooltipText
      .SendMessageW(m_hTooltip, TTM_SETTOOLINFOW, 0, CAST(LPARAM, @tti))
   END IF
END PROPERTY
' ========================================================================================

' ========================================================================================
' Set icon and/or title
' Usage example: pTooltip.SetTitle CAST(HANDLE, TTI_INFO), "Tooltip title"
' ========================================================================================
SUB CTooltip.SetTitle (BYVAL hIcon AS HANDLE, BYREF wszTitle AS CONST WSTRING)
   .SendMessageW m_hTooltip, TTM_SETTITLEW, CAST(WPARAM, hIcon), CAST(LPARAM, @wszTitle)
END SUB
' ========================================================================================


This part is very important:


#ifdef __FB_64BIT__
   IF AfxComCtlVersion < 600 THEN m_cbSize = 64 ELSE m_cbSize = 72
#else
   IF AfxComCtlVersion < 600 THEN m_cbSize = 44 ELSE m_cbSize = 48
#endif


because the size of the TOOLINFO structure should be different depending on the version of the CommCtrl library being used (5.xx without a manifest, 6.xx with a manifest).

Usage is very simple:


   ' // Add a button
   DIM hButton AS HWND = pWindow.AddControl("Button", pWindow.hWindow, IDCANCEL, "&Close", 350, 250, 75, 23)
   ' // Add a tooltip to the button
   DIM pTooltip AS CTooltip = CTooltip(hButton, "This is a button with a tooltip", TRUE, TRUE)
   ' // Optional: Set the icon and title
   pTooltip.SetTitle CAST(HANDLE, TTI_INFO), "Tooltip title"
   ' // To change the text, use:
'   pTooltip.TipText = "This is a modified text"

Title: Re: CWindow RC03
Post by: José Roca on April 29, 2016, 05:40:29 PM
Will add a few methods more, like one to set the max width.

Other options less often used can be set with SendMessageW <pToolTip>.hTooltip, <message>, <wparam>, <lparam>.
Title: Re: CWindow RC03
Post by: José Roca on April 30, 2016, 06:19:01 PM
I have written a function to allow to use .png icons in toolbars, etc. Have had some problems until I realized that BYTE is signed in FreeBasic and had to use UBYTE.

Because for some reason GDI+ makes gray icons darker that it should, I have added the option to specify a dimming percentage and gray conversion.

A manifest must be used to preserve the alpha channel.

Will write another one to load it from resources.


' ========================================================================================
' Loads an image from a file using GDI+, converts it to an icon and returns the icon handle.
' Parameter:
' - wszFileName = [in] Path of the image to load and convert.
' - dimPercent = Percent of dimming (1-99)
' - bGrayScale = TRUE or FALSE. Convert to gray scale.
' Return Value:
'   If the function succeeds, the return value is the handle of the created icon.
'   If the function fails, the return value is NULL.
' ========================================================================================
FUNCTION AfxGdiplusCreateHICONFromFile (BYREF wszFileName AS WSTRING, _
   BYVAL dimPercent AS LONG = 0, BYVAL bGrayScale AS LONG = FALSE) AS HICON

   DIM hStatus AS GpStatus, token AS ULONG_PTR
   DIM pImage AS GpImage PTR, hIcon AS HICON
   DIM ImageWidth AS LONG, ImageHeight AS LONG, x AS LONG, y AS LONG
   DIM pixColor AS GDIP_BGRA, iColor AS LONG, rFactor AS SINGLE

   ' // Initialize Gdiplus
   token = AfxGdiplusInit
   ' // Load the image from file
   GdipLoadImageFromFile(wszFileName, @pImage)
   IF pImage = NULL THEN EXIT FUNCTION
   ' // Get the image width and height
   GdipGetImageWidth(pImage, @ImageWidth)
   GdipGetImageHeight(pImage, @ImageHeight)
   ' // Dim or/and gray the image
   IF dimPercent > 0 AND dimPercent < 100 THEN rFactor = dimPercent / 100
   IF rFactor <> 0 OR bGrayScale <> 0 THEN
      FOR y = 0 TO ImageWidth - 1
         FOR x = 0 TO ImageHeight - 1
            ' // Get the pixel color
            GdipBitmapGetPixel(CAST(GpBitmap PTR, pImage), x, y, @pixColor.color)
            IF dimPercent > 0 THEN
               pixColor.red   = (255 - pixColor.red) * rFactor + pixColor.red
               pixColor.green = (255 - pixColor.green) * rFactor + pixColor.green
               pixColor.blue  = (255 - pixColor.blue) * rFactor + pixColor.blue
            END IF
            IF bGrayScale THEN
               ' Note: The sum of the percentages for the three colors should add tp up 1
               iColor = 0.299 * pixColor.red + 0.587 * pixColor.green + 0.114 * pixColor.blue
               pixColor.Color = GDIP_BGRA (iColor, iColor, iColor, pixColor.alpha)
            ELSE
               pixColor.color = GDIP_ARGB(pixColor.alpha, pixColor.red, pixColor.green, pixColor.Blue)
            END IF
            ' // Set the modified pixel color
            GdipBitmapSetPixel(CAST(GpBitmap PTR, pImage), x, y, pixColor.color)
         NEXT
      NEXT
   END IF
   ' // Crete icon from image
   hStatus = GdipCreateHICONFromBitmap(CAST(GpBitmap PTR, pImage), @hIcon)
   ' // Free the image
   IF pImage THEN GdipDisposeImage pImage
   ' // Shut down Gdiplus
   GdiplusShutdown token
   ' // Return the handle of the icon
   FUNCTION = hIcon

END FUNCTION
' ========================================================================================

Title: Re: CWindow RC03
Post by: José Roca on April 30, 2016, 06:39:44 PM
What about 256-bit icons? We are ready for upcoming very high resolution monitors :)
Title: Re: CWindow RC03
Post by: José Roca on April 30, 2016, 06:48:40 PM
A good thing is that we don't need to have icons of different sizes for different DPI settings. We can have only one and use something like...


   DIM cx, cy AS LONG
   cx = 16 : cy = 16
   IF pWindow.IsProcessDPIAware THEN
      IF pWindow.DPI => 120 AND pWindow.DPI < 144 THEN
         cx = 20 : cy = 20
      ELSEIF pWindow.DPI => 144 AND pWindow.DPI < 192 THEN
         cx = 24 : cy = 24
      ELSEIF pWindow.DPI => 192 THEN
         cx = 32 : cy = 32
      END IF
   END IF

   hImageList = ImageList_Create(cx, cx, ILC_COLOR32 OR ILC_MASK, 4, 0)
   IF hImageList THEN
      ImageList_ReplaceIcon(hImageList, -1, AfxGdiplusCreateHICONFromFile(ExePath & "\arrow_left_64.png"))
      ImageList_ReplaceIcon(hImageList, -1, AfxGdiplusCreateHICONFromFile(ExePath & "\arrow_right_64.png", 60, -1))
      ImageList_ReplaceIcon(hImageList, -1, AfxGdiplusCreateHICONFromFile(ExePath & "\home_64.png"))
      ImageList_ReplaceIcon(hImageList, -1, AfxGdiplusCreateHICONFromFile(ExePath & "\save_64.png", 60, -1))
   END IF
[code]
Title: Re: CWindow RC03
Post by: José Roca on April 30, 2016, 08:37:23 PM
This new function can be used to create an icon from an image stored in a buffer. Can be used with gray images because it does not darken the image as GdipLoadImageFromFile does.


' ========================================================================================
' Converts an image stored in a buffer into an icon and returns the icon handle.
' Parameters:
' - pBuffer = [in] Pointer to the buffer
' - bufferSize = Size of the buffer
' Return Value:
'   If the function succeeds, the return value is the handle of the created icon.
'   If the function fails, the return value is NULL.
' Usage example:
'   DIM wszFileName AS WSTRING * MAX_PATH
'   wszFileName = ExePath & "\arrow_left_256.png"
'   DIM bufferSize AS SIZE_T_
'   DIM nFile AS LONG
'   nFile = FREEFILE
'   OPEN wszFileName FOR BINARY AS nFile
'   IF ERR THEN EXIT FUNCTION
'   bufferSize = LOF(nFile)
'   DIM pBuffer AS UBYTE PTR
'   pBuffer = CAllocate(1, bufferSize)
'   GET #nFile, , *pBuffer, bufferSize
'   CLOSE nFile
'   IF pBuffer THEN
'      ImageList_ReplaceIcon(hImageList, -1, AfxGdiplusCreateHICONFromRawData(pBuffer, ImageSize))
'      DeAllocate(pBuffer)
'   END IF
' ========================================================================================
FUNCTION AfxGdiplusCreateHICONFromBuffer (BYVAL pBuffer AS ANY PTR, BYVAL bufferSize AS SIZE_T_) AS HICON

   DIM hStatus AS GpStatus, token AS ULONG_PTR
   DIM pImage AS GpImage PTR, hIcon AS HICON
   DIM ImageWidth AS LONG, ImageHeight AS LONG, x AS LONG, y AS LONG
   DIM pixColor AS GDIP_BGRA, iColor AS LONG, rFactor AS SINGLE
   DIM pImageStream AS IStream PTR, hGlobal AS HGLOBAL, pGlobalBuffer AS LPVOID

   ' // Initialize Gdiplus
   token = AfxGdiplusInit
   IF token = NULL THEN EXIT FUNCTION
   ' // Allocate memory to hold the image
   hGlobal = GlobalAlloc(GMEM_MOVEABLE, bufferSize)
   IF hGlobal THEN
      ' // Lock the memory
      pGlobalBuffer = GlobalLock(hGlobal)
      IF pGlobalBuffer THEN
         ' // Copy the image from the binary string file to global memory
         CopyMemory(pGlobalBuffer, pBuffer, bufferSize)
         ' // Create an stream in global memory
         IF CreateStreamOnHGlobal(hGlobal, FALSE, @pImageStream) = S_OK THEN
            IF pImageStream THEN
               ' // Create a bitmap from the data contained in the stream
               hStatus = GdipCreateBitmapFromStream(pImageStream, @pImage)
               ' // Crete icon from image
               hStatus = GdipCreateHICONFromBitmap(CAST(GpBitmap PTR, pImage), @hIcon)
               ' // Free the image
               IF pImage THEN GdipDisposeImage pImage
               pImageStream->lpVtbl->Release(pImageStream)
            END IF
         END IF
         ' // Unlock the memory
         GlobalUnlock pGlobalBuffer
      END IF
      ' // Free the memory
      GlobalFree hGlobal
   END IF

   ' // Shut down Gdiplus
   GdiplusShutdown token
   ' // Return the handle of the icon
   FUNCTION = hIcon

END FUNCTION
' ========================================================================================

Title: Re: CWindow RC03
Post by: José Roca on April 30, 2016, 09:16:21 PM
As the above function has not problem with gray images, I will rename the first one as AfxGdiplusCreateHICONFromFileEx and implemented this new one.


' ========================================================================================
' Loads an image from a file, converts it to an icon and returns the icon handle.
' Parameters:
' - wszFileName = [in] Path of the image to load and convert.
' Return Value:
'   If the function succeeds, the return value is the handle of the created icon.
'   If the function fails, the return value is NULL.
' ========================================================================================
FUNCTION AfxGdiplusCreateHICONFromFile (BYREF wszFileName AS WSTRING) AS HICON

   DIM fd AS WIN32_FIND_DATAW
   DIM hFind AS HANDLE

   ' // Check for the existence of the file
   IF LEN(wszFileName) = 0 THEN EXIT FUNCTION
   hFind = FindFirstFileW(@wszFileName, @fd)
   IF hFind = INVALID_HANDLE_VALUE THEN EXIT FUNCTION
   FindClose hFind
   ' // Make sure that is not a directory or a temporary file
   IF (fd.dwFileAttributes AND FILE_ATTRIBUTE_DIRECTORY) = FILE_ATTRIBUTE_DIRECTORY OR _
      (fd.dwFileAttributes AND FILE_ATTRIBUTE_TEMPORARY) = FILE_ATTRIBUTE_TEMPORARY THEN
      EXIT FUNCTION
   END IF

   ' // Open the file and store its contents into a buffer
   DIM nFile AS LONG, bufferSize AS SIZE_T_
   nFile = FREEFILE
   OPEN wszFileName FOR BINARY AS nFile
   IF ERR THEN EXIT FUNCTION
   bufferSize = LOF(nFile)
   DIM pBuffer AS UBYTE PTR
   pBuffer = CAllocate(1, bufferSize)
   GET #nFile, , *pBuffer, bufferSize
   CLOSE nFile
   IF pBuffer THEN
      FUNCTION = AfxGdiplusCreateHICONFromBuffer(pBuffer, bufferSize)
      DeAllocate(pBuffer)
   END IF

END FUNCTION
' ========================================================================================

Title: Re: CWindow RC03
Post by: James Fuller on May 01, 2016, 06:58:58 AM
Jose,
I am doing some experimenting and noticed this:
Quote
' ########################################################################################
' File: CWindow.inc
' Version: 1.0
' Release candidate 2
' Contents: A wrapper class to create a SDK main window and add controls to it.
' Operating system: Microsoft Windows
' Compiler: FreeBasic 32/64-bit, Unicode.
' Freeware. Use at your own risk.
' Copyright (c) 2016 Jose Roca. All Rights Reserved.
' THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
' EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
' MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
' #######################################################################################
Did you inadvertently upload rc2 or not update the header info.

James
Title: Re: CWindow RC03
Post by: José Roca on May 01, 2016, 07:27:55 AM
Forgot to update the number. Sorry.

BTW is "dimming" the appropriate word for what I'm doing, i.e. reducing the saturation of color?
Title: Re: CWindow RC03
Post by: José Roca on May 01, 2016, 08:07:35 AM
I'm going to shorten a little the name of the functions, e.g. AfxGdipIconFromFile instead of AfxGdiplusCreateHICONFromFile.
Title: Re: CWindow RC03
Post by: Barry Gordon on May 01, 2016, 09:03:52 AM
Hi,

> BTW is "dimming" the appropirate word for what I'm doing, i.e. reducing the saturation of color?

So why not 'desaturate' then?

Cheers
Barry
Title: Re: CWindow RC03
Post by: José Roca on May 01, 2016, 09:17:43 AM
Don't know. I have used dim because of this thread: How to Create Dim Background Images? ( http://forum.powerbasic.com/forum/user-to-user-discussions/powerbasic-for-windows/54850-how-to-create-dim-background-images?t=53493 ), from which I have taken the idea. Just wanted to know if dimPercent = Percent of dimming (1-99) makes sense to English speaking people or not.
Title: Re: CWindow RC03
Post by: José Roca on May 01, 2016, 09:20:38 AM
And this is the function to load .png icons from resources.


' ========================================================================================
' Loads an image from a resource, converts it to an icon using GDI+ and returns the icon handle.
' Parameter:
' - hInstance = [in] A handle to the module whose portable executable file or an accompanying
'               MUI file contains the resource. If this parameter is NULL, the function searches
'               the module used to create the current process.
' - wszImage  = [in] Name of the image in the resource file (.RES). If the image resource uses
'               an integral identifier, wszImage should begin with a number symbol (#)
'               followed by the identifier in an ASCII format, e.g., "#998". Otherwise,
'               use the text identifier name for the image. Only images embedded as raw data
'               (type RCDATA) are valid. These must be icons in format .png, .jpg, .gif, .tiff.
' Return Value:
'   If the function succeeds, the return value is the handle of the created icon.
'   If the function fails, the return value is NULL.
' ========================================================================================
FUNCTION AfxGdipIconFromRes (BYVAL hInstance AS HINSTANCE, BYREF wszImage AS WSTRING) AS HICON

   DIM hStatus AS GpStatus, token AS ULONG_PTR
   DIM hRes AS HRSRC, wID AS WORD, dwID AS DWORD, imageSize AS DWORD
   DIM pImage AS GpImage PTR, hIcon AS HICON
   DIM pResData AS HRSRC
   DIM pImageStream AS IStream PTR, hGlobal AS HGLOBAL, pGlobalBuffer AS LPVOID

   ' // Initialize Gdiplus
   token = AfxGdipInit
   IF token = NULL THEN EXIT FUNCTION

   ' // Find the resource
   IF LEFT(wszImage, 1) = "#" THEN
      wID = VAL(MID(wszImage, 2))
      dwID = MAKELONG(wID, 0)
      hRes = FindResourceW(hInstance, MAKEINTRESOURCEW(dwID), CAST(LPCWSTR, RT_RCDATA))
   ELSE
      hRes = FindResourceW(hInstance, wszImage, CAST(LPCWSTR, RT_RCDATA))
   END IF
   IF hRes THEN
      ' // Retrieve the size of the image
      imageSize = SizeofResource(hInstance, hRes)
      IF imageSize THEN
         ' // Load the resource and get a pointer to the resource data.
         ' // Note: LockResource does not actually lock memory; it is just used
         ' // to obtain a pointer to the memory containing the resource data.
         pResData = LockResource(LoadResource(hInstance, hRes))
         IF pResData THEN
            ' // Allocate memory to hold the image
            hGlobal = GlobalAlloc(GMEM_MOVEABLE, imageSize)
            IF hGlobal THEN
               ' // Lock the memory
               pGlobalBuffer = GlobalLock(hGlobal)
               IF pGlobalBuffer THEN
                  ' // Copy the image from the binary string file to global memory
                  CopyMemory(pGlobalBuffer, pResData, imageSize)
                  ' // Create an stream in global memory
                  IF CreateStreamOnHGlobal(hGlobal, FALSE, @pImageStream) = S_OK THEN
                     IF pImageStream THEN
                        ' // Create a bitmap from the data contained in the stream
                        hStatus = GdipCreateBitmapFromStream(pImageStream, @pImage)
                        ' // Crete icon from image
                        hStatus = GdipCreateHICONFromBitmap(CAST(GpBitmap PTR, pImage), @hIcon)
                        ' // Free the image
                        IF pImage THEN GdipDisposeImage pImage
                        pImageStream->lpVtbl->Release(pImageStream)
                     END IF
                  END IF
                  ' // Unlock the memory
                  GlobalUnlock pGlobalBuffer
               END IF
               ' // Free the memory
               GlobalFree hGlobal
            END IF
         END IF
      END IF
   END IF

   ' // Shut down Gdiplus
   GdiplusShutdown token
   ' // Return the handle of the icon
   FUNCTION = hIcon

END FUNCTION
' ========================================================================================


In the resource file, we need to use the RCDATA statement, e.g.


//=============================================================================
// Manifest
//=============================================================================

1 24 "WThemes.xml"

//=============================================================================
// Toolbar icons
//=============================================================================

// Toolbar, normal
IDI_ARROW_LEFT_48       RCDATA "arrow_left_48.png"
IDI_ARROW_RIGHT_48      RCDATA "arrow_right_48.png"
IDI_HOME_48             RCDATA "home_48.png"
IDI_SAVE_48             RCDATA "save_48.png"

// Toolbar, disabled
IDI_ARROW_LEFT_48_D     RCDATA "arrow_left_48_d.png"
IDI_ARROW_RIGHT_48_D    RCDATA "arrow_right_48_d.png"
IDI_HOME_48_D           RCDATA "home_48_d.png"
IDI_SAVE_48_D           RCDATA "save_48_d.png"

Title: Re: CWindow RC03
Post by: José Roca on May 01, 2016, 09:21:58 AM
Usage example:


   ' // Add a tooolbar
   DIM hToolBar AS HWND = pWindow.AddControl("Toolbar", pWindow.hWindow, IDC_TOOLBAR)
   ' // MOdule instance handle
   DIM hInst AS HINSTANCE = GetModuleHandle(NULL)
   ' // Create an image list for the toolbar
   DIM hImageList AS HIMAGELIST
   hImageList = ImageList_Create(48, 48, ILC_COLOR32 OR ILC_MASK, 4, 0)
   IF hImageList THEN
      ImageList_ReplaceIcon(hImageList, -1, AfxGdipIconFromRes(hInst, "IDI_ARROW_LEFT_48"))
      ImageList_ReplaceIcon(hImageList, -1, AfxGdipIconFromRes(hInst, "IDI_ARROW_RIGHT_48"))
      ImageList_ReplaceIcon(hImageList, -1, AfxGdipIconFromRes(hInst, "IDI_HOME_48"))
      ImageList_ReplaceIcon(hImageList, -1, AfxGdipIconFromRes(hInst, "IDI_SAVE_48"))
   END IF
   SendMessageW hToolBar, TB_SETIMAGELIST, 0, CAST(LPARAM, hImageList)
   ' // Add buttons to the toolbar
   AfxToolbarAddButtonW hToolBar, 0, IDM_LEFTARROW
   AfxToolbarAddButtonW hToolBar, 1, IDM_RIGHTARROW
   AfxToolbarAddButtonW hToolBar, 2, IDM_HOME
   AfxToolbarAddButtonW hToolBar, 3, IDM_SAVEFILE
   ' // Size the toolbar
   SendMessageW hToolBar, TB_AUTOSIZE, 0, 0

Title: Re: CWindow RC03
Post by: José Roca on May 01, 2016, 10:27:04 AM
I have modified all the functions to create an icon or a bitmap. It defaults to icon, but there are two optional parameters imageType (IMAGE_ICON or IMAGE_BITMAP) and clrBackground )the background color of the bitmap). The names of the functions now begin with AfxImage instead of AfxIcon.

This is the new include file so far:


' ########################################################################################
' Microsoft Windows
' File: AfxGdiplus.bas
' Content: Gdi Plus wrapper functions
' Compiler: Free Basic
' Freeware. Use at your own risk.
' Copyright (c) 2016 Jose Roca. All Rights Reserved.
' THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
' EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
' MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
' ########################################################################################

#pragma once

#include once "windows.bi"
#ifdef __FB_64BIT__
    #inclib "gdiplus"
    #include "win/gdiplus-c.bi"
#else
    #include once "win/gdiplus.bi"
    using gdiplus
#endif

NAMESPACE Afx.Gdiplus

UNION GDIP_BGRA
   color AS DWORD
   TYPE
      blue  AS UBYTE
      green AS UBYTE
      red   AS UBYTE
      alpha AS UBYTE
   END TYPE
END UNION

' ========================================================================================
' Returns an ARGB color value initialized with the specified values for the alpha, red,
' green, and blue components.
' ========================================================================================
FUNCTION GDIP_ARGB (BYVAL a AS UBYTE, BYVAL r AS UBYTE, BYVAL g AS UBYTE, BYVAL b AS UBYTE) AS DWORD
   DIM clr AS GDIP_BGRA
   clr.alpha = a : clr.red   = r : clr.green = g : clr.blue  = b
   FUNCTION  = clr.color
END FUNCTION
' ========================================================================================

' ========================================================================================
' Returns an XRGB color value initialized with the specified values for the red, green,
' and blue components.
' ========================================================================================
FUNCTION GDIP_XRGB (BYVAL r AS UBYTE, BYVAL g AS UBYTE, BYVAL b AS UBYTE) AS DWORD
   FUNCTION = GDIP_ARGB(&HFF, r, g, b)
END FUNCTION
' ========================================================================================

' ========================================================================================
' Returns a BGRA color value initialized with the specified values for the  blue, green,
' red and alpha components.
' ========================================================================================
FUNCTION GDIP_BGRA (BYVAL b AS UBYTE, BYVAL g AS UBYTE, BYVAL r AS UBYTE, BYVAL a AS UBYTE) AS DWORD
   DIM clr AS GDIP_BGRA
   clr.blue  = b : clr.green = g : clr.red   = r : clr.alpha = a
   FUNCTION  = clr.color
END FUNCTION
' ========================================================================================

' ========================================================================================
' Returns an RGBA color value initialized with the specified values for the red, green,
' blue and alpha components.
' ========================================================================================
FUNCTION GDIP_RGBA (BYVAL r AS UBYTE, BYVAL g AS UBYTE, BYVAL b AS UBYTE, BYVAL a AS UBYTE) AS DWORD
   FUNCTION = GDIP_ARGB(a, r, g, b)
END FUNCTION
' ========================================================================================

' ========================================================================================
' Returns the version of Gdiplus.dll, e.g. 601 for version 6.01.
' ========================================================================================
FUNCTION AfxGdipDllVersion () AS LONG

   DIM pvsffi AS VS_FIXEDFILEINFO PTR
   DIM pVerInfo AS HANDLE, dwHandle AS DWORD, dwVersion AS DWORD
   DIM cbLen AS DWORD, wMajor AS WORD, wMinor AS WORD
   cbLen = GetFileVersionInfoSizeW("GDIPLUS.DLL", @dwHandle)
   IF cbLen = 0 THEN RETURN NULL
   pVerInfo = HeapAlloc(GetProcessHeap, HEAP_ZERO_MEMORY, cbLen)
   IF pVerInfo = NULL THEN RETURN NULL
   IF GetFileVersionInfoW("GDIPLUS.DLL", dwHandle, cbLen, pVerInfo) THEN
      IF VerQueryValueW(pVerInfo, "\", @pvsffi, @cbLen) THEN
         wMajor = HIWORD(pvsffi->dwFileVersionMS)
         wMinor = LOWORD(pvsffi->dwFileVersionMS)
      END IF
   END IF
   HeapFree GetProcessHeap, 0, pVerInfo
   FUNCTION = (wMajor + wMinor / 100) * 100

END FUNCTION
' ========================================================================================

' ========================================================================================
' Initilizes GDI+
' Returns a token. Pass the token to GdiplusShutdown when you have finished using GDI+.
' ========================================================================================
FUNCTION AfxGdipInit (BYVAL version AS UINT32 = 1) AS ULONG_PTR
   DIM hStatus AS GpStatus, token AS ULONG_PTR, StartupInput AS GdiplusStartupInput
   StartupInput.GdiplusVersion = version
   hStatus = GdiplusStartup(@token, @StartupInput, NULL)
   FUNCTION = token
END FUNCTION
' ========================================================================================

' ========================================================================================
' Loads an image from a file using GDI+, converts it to an icon or bitmap and returns the handle.
' Parameters:
' - wszFileName   = [in] Path of the image to load and convert.
' - dimPercent    = Percent of dimming (1-99)
' - bGrayScale    = TRUE or FALSE. Convert to gray scale.
' - imageType     = IMAGE_ICON or IMAGE_BITMAP.
' - clrBackground = [in] The background color. This parameter is ignored if the image type
'                   is IMAGE_ICON or the bitmap is totally opaque.
' Return Value:
'   If the function succeeds, the return value is the handle of the created icon or bitmap.
'   If the function fails, the return value is NULL.
' ========================================================================================
FUNCTION AfxGdipImageFromFileEx (BYREF wszFileName AS WSTRING, _
   BYVAL dimPercent AS LONG = 0, BYVAL bGrayScale AS LONG = FALSE, _
   BYVAL imageType AS LONG = IMAGE_ICON, BYVAL clrBackground AS ARGB = 0) AS HANDLE

   DIM token AS ULONG_PTR, pImage AS GpImage PTR, hImage AS HANDLE
   DIM ImageWidth AS LONG, ImageHeight AS LONG, x AS LONG, y AS LONG
   DIM pixColor AS GDIP_BGRA, iColor AS LONG, rFactor AS SINGLE

   ' // Initialize Gdiplus
   token = AfxGdipInit
   IF token = NULL THEN EXIT FUNCTION
   ' // Load the image from file
   GdipLoadImageFromFile(wszFileName, @pImage)
   IF pImage = NULL THEN EXIT FUNCTION
   ' // Get the image width and height
   GdipGetImageWidth(pImage, @ImageWidth)
   GdipGetImageHeight(pImage, @ImageHeight)
   ' // Dim or/and gray the image
   IF dimPercent > 0 AND dimPercent < 100 THEN rFactor = dimPercent / 100
   IF rFactor <> 0 OR bGrayScale <> 0 THEN
      FOR y = 0 TO ImageWidth - 1
         FOR x = 0 TO ImageHeight - 1
            ' // Get the pixel color
            GdipBitmapGetPixel(CAST(GpBitmap PTR, pImage), x, y, @pixColor.color)
            IF dimPercent > 0 THEN
               pixColor.red   = (255 - pixColor.red) * rFactor + pixColor.red
               pixColor.green = (255 - pixColor.green) * rFactor + pixColor.green
               pixColor.blue  = (255 - pixColor.blue) * rFactor + pixColor.blue
            END IF
            IF bGrayScale THEN
               ' Note: The sum of the percentages for the three colors should add tp up 1
               iColor = 0.299 * pixColor.red + 0.587 * pixColor.green + 0.114 * pixColor.blue
               pixColor.Color = GDIP_BGRA (iColor, iColor, iColor, pixColor.alpha)
            ELSE
               pixColor.color = GDIP_ARGB(pixColor.alpha, pixColor.red, pixColor.green, pixColor.Blue)
            END IF
            ' // Set the modified pixel color
            GdipBitmapSetPixel(CAST(GpBitmap PTR, pImage), x, y, pixColor.color)
         NEXT
      NEXT
   END IF
   ' // Crete icon from image
   IF imageType = IMAGE_ICON THEN
      GdipCreateHICONFromBitmap(CAST(GpBitmap PTR, pImage), @hImage)
   ELSE
      GdipCreateHBITMAPFromBitmap(CAST(GpBitmap PTR, pImage), @hImage, clrBackground)
   END IF
   ' // Free the image
   IF pImage THEN GdipDisposeImage pImage
   ' // Shut down Gdiplus
   GdiplusShutdown token
   ' // Return the handle of the icon
   FUNCTION = hImage

END FUNCTION
' ========================================================================================

' ========================================================================================
' Converts an image stored in a buffer into an icon or bitmap and returns the handle.
' Parameters:
' - pBuffer       = [in] Pointer to the buffer
' - bufferSize    = Size of the buffer
' - imageType     = IMAGE_ICON or IMAGE_BITMAP.
' - clrBackground = [in] The background color. This parameter is ignored if the image type
'                   is IMAGE_ICON or the bitmap is totally opaque.
' Return Value:
'   If the function succeeds, the return value is the handle of the created icon or bitmap.
'   If the function fails, the return value is NULL.
' Usage example:
'   DIM wszFileName AS WSTRING * MAX_PATH
'   wszFileName = ExePath & "\arrow_left_256.png"
'   DIM bufferSize AS SIZE_T_
'   DIM nFile AS LONG
'   nFile = FREEFILE
'   OPEN wszFileName FOR BINARY AS nFile
'   IF ERR THEN EXIT FUNCTION
'   bufferSize = LOF(nFile)
'   DIM pBuffer AS UBYTE PTR
'   pBuffer = CAllocate(1, bufferSize)
'   GET #nFile, , *pBuffer, bufferSize
'   CLOSE nFile
'   IF pBuffer THEN
'      ImageList_ReplaceIcon(hImageList, -1, AfxGdipImageFromBuffer(pBuffer, ImageSize))
'      DeAllocate(pBuffer)
'   END IF
' ========================================================================================
FUNCTION AfxGdipImageFromBuffer (BYVAL pBuffer AS ANY PTR, BYVAL bufferSize AS SIZE_T_, _
   BYVAL imageType AS LONG = IMAGE_ICON, BYVAL clrBackground AS ARGB = 0) AS HANDLE

   DIM token AS ULONG_PTR, pImage AS GpImage PTR, hImage AS HANDLE
   DIM ImageWidth AS LONG, ImageHeight AS LONG, x AS LONG, y AS LONG
   DIM pixColor AS GDIP_BGRA, iColor AS LONG, rFactor AS SINGLE
   DIM pImageStream AS IStream PTR, hGlobal AS HGLOBAL, pGlobalBuffer AS LPVOID

   ' // Initialize Gdiplus
   token = AfxGdipInit
   IF token = NULL THEN EXIT FUNCTION
   ' // Allocate memory to hold the image
   hGlobal = GlobalAlloc(GMEM_MOVEABLE, bufferSize)
   IF hGlobal THEN
      ' // Lock the memory
      pGlobalBuffer = GlobalLock(hGlobal)
      IF pGlobalBuffer THEN
         ' // Copy the image from the binary string file to global memory
         CopyMemory(pGlobalBuffer, pBuffer, bufferSize)
         ' // Create an stream in global memory
         IF CreateStreamOnHGlobal(hGlobal, FALSE, @pImageStream) = S_OK THEN
            IF pImageStream THEN
               ' // Create a bitmap from the data contained in the stream
               GdipCreateBitmapFromStream(pImageStream, CAST(GpBitmap PTR PTR, @pImage))
               ' // Crete icon from image
               IF imageType = IMAGE_ICON THEN
                  GdipCreateHICONFromBitmap(CAST(GpBitmap PTR, pImage), @hImage)
               ELSE
                  GdipCreateHBITMAPFromBitmap(CAST(GpBitmap PTR, pImage), @hImage, clrBackground)
               END IF
               ' // Free the image
               IF pImage THEN GdipDisposeImage pImage
               pImageStream->lpVtbl->Release(pImageStream)
            END IF
         END IF
         ' // Unlock the memory
         GlobalUnlock pGlobalBuffer
      END IF
      ' // Free the memory
      GlobalFree hGlobal
   END IF

   ' // Shut down Gdiplus
   GdiplusShutdown token
   ' // Return the handle of the icon
   FUNCTION = hImage

END FUNCTION
' ========================================================================================

' ========================================================================================
' Loads an image from a file, converts it to an icon or bitmap and returns the handle.
' Parameters:
' - wszFileName   = [in] Path of the image to load and convert.
' - imageType     = IMAGE_ICON or IMAGE_BITMAP.
' - clrBackground = [in] The background color. This parameter is ignored if the image type
'                   is IMAGE_ICON or the bitmap is totally opaque.
' Return Value:
'   If the function succeeds, the return value is the handle of the created icon or bitmap.
'   If the function fails, the return value is NULL.
' ========================================================================================
FUNCTION AfxGdipImageFromFile (BYREF wszFileName AS WSTRING, _
   BYVAL imageType AS LONG = IMAGE_ICON, BYVAL clrBackground AS ARGB = 0) AS HICON

   DIM fd AS WIN32_FIND_DATAW
   DIM hFind AS HANDLE

   ' // Check for the existence of the file
   IF LEN(wszFileName) = 0 THEN EXIT FUNCTION
   hFind = FindFirstFileW(@wszFileName, @fd)
   IF hFind = INVALID_HANDLE_VALUE THEN EXIT FUNCTION
   FindClose hFind
   ' // Make sure that is not a directory or a temporary file
   IF (fd.dwFileAttributes AND FILE_ATTRIBUTE_DIRECTORY) = FILE_ATTRIBUTE_DIRECTORY OR _
      (fd.dwFileAttributes AND FILE_ATTRIBUTE_TEMPORARY) = FILE_ATTRIBUTE_TEMPORARY THEN
      EXIT FUNCTION
   END IF

   ' // Open the file and store its contents into a buffer
   DIM nFile AS LONG, bufferSize AS SIZE_T_
   nFile = FREEFILE
   OPEN wszFileName FOR BINARY AS nFile
   IF ERR THEN EXIT FUNCTION
   bufferSize = LOF(nFile)
   DIM pBuffer AS UBYTE PTR
   pBuffer = CAllocate(1, bufferSize)
   GET #nFile, , *pBuffer, bufferSize
   CLOSE nFile
   IF pBuffer THEN
      FUNCTION = AfxGdipImageFromBuffer(pBuffer, bufferSize, imageType, clrBackground)
      DeAllocate(pBuffer)
   END IF

END FUNCTION
' ========================================================================================

' ========================================================================================
' Loads an image from a resource, converts it to an icon or bitmap and returns the handle.
' Parameter:
' - hInstance     = [in] A handle to the module whose portable executable file or an accompanying
'                   MUI file contains the resource. If this parameter is NULL, the function searches
'                   the module used to create the current process.
' - wszImage      = [in] Name of the image in the resource file (.RES). If the image resource uses
'                   an integral identifier, wszImage should begin with a number symbol (#)
'                   followed by the identifier in an ASCII format, e.g., "#998". Otherwise,
'                   use the text identifier name for the image. Only images embedded as raw data
'                   (type RCDATA) are valid. These must be icons in format .png, .jpg, .gif, .tiff.
' - imageType     = IMAGE_ICON or IMAGE_BITMAP.
' - clrBackground = [in] The background color. This parameter is ignored if the image type
'                   is IMAGE_ICON or the bitmap is totally opaque.
' Return Value:
'   If the function succeeds, the return value is the handle of the created icon or bitmap.
'   If the function fails, the return value is NULL.
' ========================================================================================
FUNCTION AfxGdipImageFromRes (BYVAL hInstance AS HINSTANCE, BYREF wszImage AS WSTRING, _
   BYVAL imageType AS LONG = IMAGE_ICON, BYVAL clrBackground AS ARGB = 0) AS HANDLE

   DIM token AS ULONG_PTR, pImage AS GpImage PTR, hImage AS HANDLE
   DIM hRes AS HRSRC, pResData AS HRSRC, wID AS WORD, dwID AS DWORD, imageSize AS DWORD
   DIM pImageStream AS IStream PTR, hGlobal AS HGLOBAL, pGlobalBuffer AS LPVOID

   ' // Initialize Gdiplus
   token = AfxGdipInit
   IF token = NULL THEN EXIT FUNCTION

   ' // Find the resource
   IF LEFT(wszImage, 1) = "#" THEN
      wID = VAL(MID(wszImage, 2))
      dwID = MAKELONG(wID, 0)
      hRes = FindResourceW(hInstance, MAKEINTRESOURCEW(dwID), CAST(LPCWSTR, RT_RCDATA))
   ELSE
      hRes = FindResourceW(hInstance, wszImage, CAST(LPCWSTR, RT_RCDATA))
   END IF
   IF hRes THEN
      ' // Retrieve the size of the image
      imageSize = SizeofResource(hInstance, hRes)
      IF imageSize THEN
         ' // Load the resource and get a pointer to the resource data.
         ' // Note: LockResource does not actually lock memory; it is just used
         ' // to obtain a pointer to the memory containing the resource data.
         pResData = LockResource(LoadResource(hInstance, hRes))
         IF pResData THEN
            ' // Allocate memory to hold the image
            hGlobal = GlobalAlloc(GMEM_MOVEABLE, imageSize)
            IF hGlobal THEN
               ' // Lock the memory
               pGlobalBuffer = GlobalLock(hGlobal)
               IF pGlobalBuffer THEN
                  ' // Copy the image from the binary string file to global memory
                  CopyMemory(pGlobalBuffer, pResData, imageSize)
                  ' // Create an stream in global memory
                  IF CreateStreamOnHGlobal(hGlobal, FALSE, @pImageStream) = S_OK THEN
                     IF pImageStream THEN
                        ' // Create a bitmap from the data contained in the stream
                        GdipCreateBitmapFromStream(pImageStream, CAST(GpBitmap PTR PTR, @pImage))
                        ' // Crete icon from image
                        IF imageType = IMAGE_ICON THEN
                           GdipCreateHICONFromBitmap(CAST(GpBitmap PTR, pImage), @hImage)
                        ELSE
                           GdipCreateHBITMAPFromBitmap(CAST(GpBitmap PTR, pImage), @hImage, clrBackground)
                        END IF
                        ' // Free the image
                        IF pImage THEN GdipDisposeImage pImage
                        pImageStream->lpVtbl->Release(pImageStream)
                     END IF
                  END IF
                  ' // Unlock the memory
                  GlobalUnlock pGlobalBuffer
               END IF
               ' // Free the memory
               GlobalFree hGlobal
            END IF
         END IF
      END IF
   END IF

   ' // Shut down Gdiplus
   GdiplusShutdown token
   ' // Return the handle of the icon
   FUNCTION = hImage

END FUNCTION
' ========================================================================================

END NAMESPACE


Title: Re: CWindow RC03
Post by: Paul Squires on May 03, 2016, 12:19:44 PM
Hi Jose, can you post an attachment with the "WThemes.xml" file and the png's that you are using?
Title: Re: CWindow RC03
Post by: José Roca on May 03, 2016, 01:51:18 PM
This attachment includes the testing code that I have used for toolbars. Requires version RC05.