Note that this document contains some links to the old news2news website which does not work at the moment. This material will be available sometime in the future.
Download ResourceContainer.dll before testing this code. This DLL is nothing more but a resource storage containing five icons. It does not require any installation procedure; just copy it to your FoxPro directory.
- How to change font name and size in the MessageBox dialog
- Extended MessageBox Class
- Storing registration key in the resources of an executable file
- Icon Viewer
#DEFINE MB_YESNO 4
#DEFINE MB_USERICON 0x80
#DEFINE MB_DEFBUTTON2 0x100
#DEFINE LOAD_LIBRARY_AS_DATAFILE 2
#DEFINE MSGBOXPARAMS_SIZE 40
DO declare
LOCAL hResource, cBuffer, oText, oCaption
hResource = LoadLibraryEx("ResourceContainer.dll",;
0, LOAD_LIBRARY_AS_DATAFILE)
IF hResource = 0
* 2=ERROR_FILE_NOT_FOUND
* 193=ERROR_BAD_EXE_FORMAT
? "Could not load resource file: ", GetLastError()
RETURN
ENDIF
oText = CREATEOBJECT("PChar",;
"Use custom icons with the MESSAGEBOX dialog. ")
oCaption = CREATEOBJECT("PChar",;
"Using MessageBoxIndirect API")
* Populate the MSGBOXPARAMS structure
* Note: the resource file used in this code sample
* contains five icons, resource ids from 101 to 105
cBuffer = num2dword(MSGBOXPARAMS_SIZE) +;
num2dword(_screen.HWnd) +;
num2dword(hResource) +;
num2dword(oText.GetAddr()) +;
num2dword(oCaption.GetAddr()) +;
num2dword(MB_USERICON+MB_YESNO+MB_DEFBUTTON2) +;
num2dword(105) +;
num2dword(0) +;
num2dword(0) +;
num2dword(VAL(SYS(3004)))
= MessageBoxIndirect(@cBuffer)
= FreeLibrary(hResource)
* end of main
PROCEDURE declare
DECLARE INTEGER MessageBoxIndirect IN user32 STRING @lpMsgBoxParams
DECLARE INTEGER FreeLibrary IN kernel32 INTEGER hLibModule
DECLARE INTEGER GetLastError IN kernel32
DECLARE INTEGER LoadLibraryEx IN kernel32;
STRING lpFileName, INTEGER hFile, INTEGER dwFlags
FUNCTION num2dword(lnValue)
#DEFINE m0 0x0000100
#DEFINE m1 0x0010000
#DEFINE m2 0x1000000
IF lnValue < 0
lnValue = 0x100000000 + lnValue
ENDIF
LOCAL b0, b1, b2, b3
b3 = Int(lnValue/m2)
b2 = Int((lnValue - b3*m2)/m1)
b1 = Int((lnValue - b3*m2 - b2*m1)/m0)
b0 = Mod(lnValue, m0)
RETURN Chr(b0)+Chr(b1)+Chr(b2)+Chr(b3)
DEFINE CLASS PChar As Session
PROTECTED hMem
PROCEDURE Init(lcString)
THIS.hMem = 0
THIS.setValue(lcString)
PROCEDURE Destroy
THIS.ReleaseString
FUNCTION GetAddr
RETURN THIS.hMem
FUNCTION GetValue
LOCAL lnSize, lcBuffer
lnSize = THIS.getAllocSize()
lcBuffer = SPACE(lnSize)
IF THIS.hMem <> 0
DECLARE RtlMoveMemory IN kernel32 As MemToStr;
STRING @, INTEGER, INTEGER
= MemToStr(@lcBuffer, THIS.hMem, lnSize)
ENDIF
RETURN lcBuffer
FUNCTION GetAllocSize
DECLARE INTEGER GlobalSize IN kernel32 INTEGER hMem
RETURN Iif(THIS.hMem=0, 0, GlobalSize(THIS.hMem))
PROCEDURE SetValue(lcString)
#DEFINE GMEM_FIXED 0
THIS.ReleaseString
DECLARE INTEGER GlobalAlloc IN kernel32 INTEGER, INTEGER
DECLARE RtlMoveMemory IN kernel32 As StrToMem;
INTEGER, STRING @, INTEGER
LOCAL lnSize
lcString = lcString + Chr(0)
lnSize = Len(lcString)
THIS.hMem = GlobalAlloc(GMEM_FIXED, lnSize)
IF THIS.hMem <> 0
= StrToMem(THIS.hMem, @lcString, lnSize)
ENDIF
PROCEDURE ReleaseString
IF THIS.hMem <> 0
DECLARE INTEGER GlobalFree IN kernel32 INTEGER
= GlobalFree (THIS.hMem)
THIS.hMem = 0
ENDIF
ENDDEFINE FreeLibrary
GetLastError
GlobalAlloc
GlobalFree
GlobalSize
LoadLibraryEx
MessageBox
MessageBoxIndirect
A resource-only DLL can be created in VC++. It contains virtually no executable code but resources, such as icons, bitmaps, strings, and dialog boxes. The file created with the /NOENTRY linker option is always light-weighted with an overhead below 3K (Portable Executable headers).
Any other file containing compatible icon resources can be used, for example Shell32.dll. Normally this file locates in System32 directory and contains plenty colorful icons the system readily uses itself.
Change the code sample as shown below:
hResource = LoadLibraryEx(GETENV("windir") + "\system32\shell32.dll",;
0, LOAD_LIBRARY_AS_DATAFILE)
...
cBuffer = num2dword(MSGBOXPARAMS_SIZE) +;
num2dword(_screen.HWnd) +;
num2dword(hResource) +;
num2dword(oText.GetAddr()) +;
num2dword(oCaption.GetAddr()) +;
num2dword(MB_USERICON+MB_YESNO+MB_DEFBUTTON2) +;
num2dword(47) +;
num2dword(0) +;
num2dword(0) +;
num2dword(VAL(SYS(3004)))which should provide this or similar result
Changing the dialog icon by sending the STM_SETICON message to the icon window is another approach (requires extra programming in C++). The STM_SETICON is usually sent before the dialog activates. The WMPARAM in this message is the HICON handle.
There are several ways of obtaining the HICON: loading icon from ICO file (call LoadIcon or LoadImage ), get an icon resource from executable or DLL (call LoadLibrary and then LoadImage). The SHGetFileInfo returns HICON handles for the file or for the file type specified.
On the screenshot below, the icon inside the MessageBox is retrieved from the Skype executable by calling the SHGetFileInfo. Such functionality can be programmed in FLL or DLL library.
Home 
