I'm needing to convert binary buffers (BMP screenshot images) to base64 so I can encode them into html files.
I found a function Base64ToBinary (below) in the database, and it works great. Not what I need, but it works.
What I need is BinaryToBase64 , So I tried making that and I'm having trouble. Dll error 234. I'm not great at DLL calls.
what am I doing wrong in the BinaryToBase64 function below?
probably something with the parameters to the dll call...
TIA, Kirby
#DefineFunction Base64ToBinary(strBase64, phBinary)
; CryptStringToBinaryA function https://docs.microsoft.com/en-us/windows/desktop/api/wincrypt/nf-wincrypt-cryptstringtobinarya
; BOOL CryptStringToBinaryA(
; LPCSTR pszString,
; DWORD cchString,
; DWORD dwFlags,
; BYTE *pbBinary,
; DWORD *pcbBinary,
; DWORD *pdwSkip,
; DWORD *pdwFlags
; )
*phBinary = 0
CRYPT_STRING_BASE64 = 1
hCrypt = DllLoad(DirWindows(1):"Crypt32.dll")
hByteCount = BinaryAlloc(4)
; Get the binary buffer size
bResult = DllCall(hCrypt, long:"CryptStringToBinaryA",lpstr:strBase64, long:0, long:CRYPT_STRING_BASE64, lpnull, lpbinary:hByteCount, lpnull, lpnull)
If !bResult
BinaryFree(hByteCount)
DllFree(hCrypt)
Return DllLastError()
EndIf
BinaryEodSet( hByteCount, 4 )
nConvertedBytes = BinaryPeek4(hByteCount, 0)
hConverted = BinaryAlloc(nConvertedBytes)
; Convert the string
bResult = DllCall(hCrypt, long:"CryptStringToBinaryA",lpstr:strBase64, long:0, long:CRYPT_STRING_BASE64, lpbinary:hConverted, lpbinary:hByteCount, lpnull, lpnull)
If !bResult Then nReturn = DllLastError()
Else nReturn = 0
BinaryFree(hByteCount)
DllFree(hCrypt)
BinaryEodSet(hConverted, nConvertedBytes)
*phBinary = hConverted
Return nReturn ; 0 on success otherwise system error
#EndFunction
#DefineFunction BinaryToBase64(hBinary, pstrBase64)
; CryptBinaryToStringA function https://docs.microsoft.com/en-us/windows/desktop/api/wincrypt/nf-wincrypt-cryptbinarytostringa
; BOOL CryptBinaryToStringA(
; const BYTE *pbBinary,
; DWORD cbBinary,
; DWORD dwFlags,
; LPSTR pszString,
; DWORD *pcchString
; )
CRYPT_STRING_BASE64 = 1
hCrypt = DllLoad(DirWindows(1):"Crypt32.dll")
ByteCount = BinaryEodGet(hBinary)
hStrCount = BinaryAlloc(4)
strBase64 = ""
; Convert to string
bResult = DllCall(hCrypt, long:"CryptBinaryToStringA", lpbinary:hBinary, long:ByteCount, long:CRYPT_STRING_BASE64, lpstr:StrBase64, lpbinary:hStrCount)
If !bResult
nReturn = DllLastError()
Else
nReturn = 0
endif
DllFree(hCrypt)
StrCount = BinaryPeek4(hStrCount, 0)
BinaryFree(hStrCount)
*pstrBase64 = strBase64
Return nReturn
#EndFunction
Betty = "12345"
If Base64ToBinary(Betty, &hResult) == 0
if BinaryToBase64(hResult, &Sally) == 0
message(betty, sally)
endif
EndIf
You need to call the "CryptBinaryToStringA" function twice. On the first call set the pszString parameter to lpNull so that you get the size of the date after conversion in the pcchString parameter. On the second call, you pass a binary buffer to the function and use BinaryEodSet and BinaryPokeStr to get your converted value. The binary buffer should be allocated to the size indicated in the pcchString parameter after the first call to the function.
Quick and dirty example:
#DefineFunction BinaryToBase64(hBinary, pstrBase64)
; CryptBinaryToStringA function https://docs.microsoft.com/en-us/windows/desktop/api/wincrypt/nf-wincrypt-cryptbinarytostringa
; BOOL CryptBinaryToStringA(
; const BYTE *pbBinary,
; DWORD cbBinary,
; DWORD dwFlags,
; LPSTR pszString,
; DWORD *pcchString
; )
CRYPT_STRING_BASE64 = 1
hCrypt = DllLoad(DirWindows(1):"Crypt32.dll")
ByteCount = BinaryEodGet(hBinary)
hStrCount = BinaryAlloc(4)
strBase64 = ""
; Get converted to string's size.
bResult = DllCall(hCrypt, long:"CryptBinaryToStringA", lpbinary:hBinary, long:ByteCount, long:CRYPT_STRING_BASE64, lpNull, lpbinary:hStrCount)
If !bResult
nReturn = DllLastError()
Else
nReturn = 0
endif
if !nReturn
StrCount = BinaryPeek4(hStrCount, 0)
hConverted = BinaryAlloc(StrCount)
; Convert to string
bResult = DllCall(hCrypt, long:"CryptBinaryToStringA", lpbinary:hBinary, long:ByteCount, long:CRYPT_STRING_BASE64, lpBinary:hConverted, lpbinary:hStrCount)
If !bResult
nReturn = DllLastError()
Else
BinaryEodSet(hConverted, StrCount)
*pstrBase64 = BinaryPeekStr(hConverted, 0, StrCount)
nReturn = 0
endif
BinaryFree(hConverted)
endif
DllFree(hCrypt)
BinaryFree(hStrCount)
;;*pstrBase64 = strBase64
Return nReturn
#EndFunction
Cool. Thanks so much Tony. I'll have to stare at this for while. The arcane ways of the Dll call are inscrutable, but apparently perceptible with study. (smile)
But it works great, so I'm on my way. This idea is to pack the image for my HTML report right inside the HTML itself using src="data:image...."
I'll have to flip the BMP produced by Snapshot() to JPG for the reduction in size, but I know how to use pixie for that.
I'll post if I get it working.
OK, FWIW, this puts together an HTML file with a screen shot encoded therein.
Not terribly useful unless you need exactly that.
#DefineFunction MakeSnapShotBinary(ShotType)
; requires Pixie Extender WWIMG44I.DLL
;
; returns binarybuffer handle with snapshot encoded therein
;
; JPG snapshot is somewhat grainy, but only 3% the size of the bitmap.
; GIF makes sharp image, and is 25% the size of the bitmap.
;
tf1 = StrCat(Environment("TEMP"), "\MakeSnapShot.bmp")
tf2 = StrCat(Environment("TEMP"), "\MakeSnapShot.gif") ; or jpg
;Takes a bitmap snapshot of a window to the clipboard.
Snapshot(ShotType) ; 0 for whole screen, 4 for active window
;returns the size of buffer needed for a subsequent BinaryAlloc,
;but doesn't attempt to place the contents of clipboard into a buffer
size=BinaryClipGet(0,8)
;allocates a data buffer
bb=BinaryAlloc(size)
;read file format type CF_DIB
BinaryClipGet(bb,8)
; need to add first 14 bytes to make it
; a BMP file format
bmpdatasize=14
bb2=BinaryAlloc(size + bmpdatasize)
;The characters identifying the bitmap.'BM'
BinaryPokeStr(bb2, 0, "BM")
;Complete file size in bytes.
BinaryPoke4(bb2,2,size + bmpdatasize)
;Reserved
BinaryPoke4(bb2,6,0)
;Data offset
headersize=BinaryPeek4(bb,0)
dataoffset = headersize + bmpdatasize
BinaryPoke4(bb2,10,dataoffset)
BinaryCopy(bb2,bmpdatasize,bb,0,size)
BinaryFree(bb)
FileDelete(tf1)
BinaryWrite(bb2,tf1)
AddExtender("WWIMG44I.DLL")
ImgConvert(tf1,tf2) ; convert bmp to ???
FileDelete(tf1)
BinaryRead(bb2, tf2)
FileDelete(tf2)
return bb2 ; return the BinaryBuffer handle
#EndFunction
#DefineFunction BinaryToBase64(hBinary, pstrBase64)
; CryptBinaryToStringA function https://docs.microsoft.com/en-us/windows/desktop/api/wincrypt/nf-wincrypt-cryptbinarytostringa
; BOOL CryptBinaryToStringA(
; const BYTE *pbBinary,
; DWORD cbBinary,
; DWORD dwFlags,
; LPSTR pszString,
; DWORD *pcchString
; )
CRYPT_STRING_BASE64 = 1
hCrypt = DllLoad(DirWindows(1):"Crypt32.dll")
ByteCount = BinaryEodGet(hBinary)
hStrCount = BinaryAlloc(4)
; Get converted to string's size.
bResult = DllCall(hCrypt, long:"CryptBinaryToStringA", lpbinary:hBinary, long:ByteCount, long:CRYPT_STRING_BASE64, lpNull, lpbinary:hStrCount)
If !bResult
nReturn = DllLastError()
Else
nReturn = 0
endif
if !nReturn
StrCount = BinaryPeek4(hStrCount, 0)
hConverted = BinaryAlloc(StrCount)
; Convert to string
bResult = DllCall(hCrypt, long:"CryptBinaryToStringA", lpbinary:hBinary, long:ByteCount, long:CRYPT_STRING_BASE64, lpBinary:hConverted, lpbinary:hStrCount)
If !bResult
nReturn = DllLastError()
Else
BinaryEodSet(hConverted, StrCount)
*pstrBase64 = BinaryPeekStr(hConverted, 0, StrCount)
nReturn = 0
endif
BinaryFree(hConverted)
endif
DllFree(hCrypt)
BinaryFree(hStrCount)
Return nReturn
#EndFunction
hBuf = MakeSnapShotBinary(3) ; 3=client area of active window
terminate(BinaryToBase64(hBuf, &Base64string), "BinaryToBase64", "failed to convert")
intcontrol(53,0,0,0,0) ; no auto line terminate on filewrite
of = shortcutdir("desktop"):"\DeleteMe.htm"
oh = fileopen(of, "write")
filewrite(oh, `Here's a bunch of complicated html.<br>`:@crlf)
filewrite(oh, `Here's a snapshot of the <b>active window</b><br>`:@crlf)
filewrite(oh, `encoded right here in this html file.<br>`:@crlf)
filewrite(oh, `<img src="data:image/jpg;base64,`:@crlf) ; either jpg or gif
filewrite(oh, Base64String)
filewrite(oh, `"; alt="Base64 encoded image" />`:@crlf)
fileclose(oh)
Exit