I'm trying to adapt the bitmap save code for a EBasic window so it will work with my custom control
In my WM_PAINT handler I'm creating a compatible dc (for buffering) and writing all my "stuff" to it.
The line that updates the screen is (px is set with BeginPaint):_BitBlt(px, 0, 0, rc.right,rc.bottom, hdcMem, 0, 0, SRCCOPY)
Right after that line of code, I want to save what was displayed in the control to an external bitmap.
So I'm calling doprint(px,rc)
The file is being created with 121 bytes (which I figure is just a header)
sub doprint(hdc:uint,rc:winrect)
string filename=getstartpath+"testing.bmp"
def hdcWin,hdcComp,hbitmap,hbitmapold,quadsize:int
def info:BITMAPINFOHEADER
def fileheader:BITMAPFILEHEADER
def lpbits,lpbminfo:MEMORY
def fileb:BFILE
ZeroMemory(info,len(info))
ZeroMemory(fileheader,len(fileheader))
hdcComp = _CreateCompatibleDC(hdc)
hbitmap = _CreateCompatibleBitmap(hdc,rc.right,rc.bottom)
hbitmapold = _SelectObject(hdcComp,hbitmap)
_BitBlt(hdcComp,0,0,rc.right,rc.bottom,hdc,0,0,0x00CC0020)
_SelectObject(hdcComp,hbitmapold)
_DeleteDC(hdcComp)
quadsize = CreateInfoStructure(hbitmap,info)
REM allocate memory and get the 'bits' of the bitmap
allocmem lpbits,1,info.biSizeImage
allocmem lpbminfo,1,len(info) + quadsize
writemem lpbminfo,1,info
GetDIBits(hdcComp,hbitmap,0,info.biHeight,lpbits,lpbminfo,0)
REM open a binary file and write the header,color data and bitmap bits
if(openfile(fileb,filename,"W") = 0)
fileheader.bfType = 0x4d42
fileheader.bfSize = len(fileheader) + info.biSize + quadsize + info.biSizeImage
fileheader.bfOffBits = len(fileheader) + info.biSize + quadsize
write fileb,fileheader
write fileb,lpbminfo
write fileb,lpbits
closefile fileb
endif
freemem lpbminfo
freemem lpbits
_DeleteObject(hbitmap)
return
endsub
SUB CreateInfoStructure(hbitmap:uint,info:BITMAPINFOHEADER)
def bmp:BITMAP
def mem:MEMORY
def cClrBits:WORD
def quadsize:int : quadsize = 0
Allocmem mem,1,len(bmp)
GetObjectA(hbitmap,len(bmp),mem)
readmem mem,1,bmp
freemem mem
cClrBits = bmp.bmPlanes * bmp.bmBitsPixel
if (cClrBits = 1)
cClrBits = 1
else
if (cClrBits <= 4)
cClrBits = 4
else
if (cClrBits <= 8)
cClrBits = 8
else
if (cClrBits <= 16)
cClrBits = 16
else
if (cClrBits <= 24)
cClrBits = 24
else
cClrBits = 32
endif
endif
endif
endif
endif
info.biSize = len(info)
info.biWidth = bmp.bmWidth
info.biHeight = bmp.bmHeight
info.biPlanes = bmp.bmPlanes
info.biBitCount = bmp.bmBitsPixel
if (cClrBits < 24)
info.biClrUsed = 2^cClrBits
endif
info.biCompression = 0
info.biSizeImage = (info.biWidth + 7.0) / 8.0 * info.biHeight * cClrBits
if(cClrBits < 24)
quadsize = 4 * (2^cClrBits)
endif
RETURN quadsize
ENDSUB
Don't know what to juggle to fix it.
Larry
I have another solution, maybe easier (designed for bitmaps with width and height multiple by two)$include "windowssdk.inc"
'$define SNAP_NONCLIENT
SaveScreenshot(FindWindow(0, "Emergence BASIC - [SaveScreenshot.eba]"), "desktop.bmp", FALSE)
sub SaveScreenshot(HWND hwnd, LPTSTR path, BOOL fNonClient)
BITMAPINFOHEADER bmiHeader
BITMAPFILEHEADER filehdr
WINRECT rc
ZeroMemory(&bmiHeader, len(bmiHeader))
bmiHeader.biSize = len(BITMAPINFOHEADER)
if (fNonClient)
GetWindowRect(hwnd, &rc)
HDC hdcSource = GetWindowDC(hwnd)
else
GetClientRect(hwnd, &rc)
hdcSource = GetDC(hwnd)
endif
bmiHeader.biWidth = rc.right - rc.left ' target bitmap size
bmiHeader.biHeight = rc.bottom - rc.top
bmiHeader.biPlanes = 1
bmiHeader.biBitCount = 24
pointer pBits ' 24bit: RGBTRIPLE* 32bit:RGBQUAD*
HBITMAP hbmImage = CreateDIBSection(hdcSource, &bmiHeader, DIB_RGB_COLORS, &pBits, 0, 0)
HDC hdcMemory = CreateCompatibleDC(hdcSource)
hbmImage = SelectObject(hdcMemory, hbmImage)
BitBlt(hdcMemory,0,0, bmiHeader.biWidth, bmiHeader.biHeight, hdcSource, 0, 0, SRCCOPY | CAPTUREBLT)
hbmImage = SelectObject(hdcMemory, hbmImage)
DeleteDC(hdcMemory)
ReleaseDC(hwnd, hdcSource)
HANDLE hFile = CreateFile(path, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0)
DWORD bilen = bmiHeader.biWidth * bmiHeader.biHeight * bmiHeader.biBitCount/8
DWORD bytes
filehdr.bfType = 0x4d42 'MB'
filehdr.bfOffBits = len(BITMAPFILEHEADER) + len(BITMAPINFOHEADER)
filehdr.bfSize = len(BITMAPFILEHEADER) + len(BITMAPINFOHEADER) + bilen
filehdr.bfReserved1 = 0
filehdr.bfReserved2 = 0
WriteFile(hFile, &filehdr, len(filehdr), &bytes, NULL)
WriteFile(hFile, &bmiHeader, len(bmiHeader), &bytes, NULL)
WriteFile(hFile, pBits, bilen, &bytes, NULL)
CloseHandle(hFile)
DeleteObject(hbmImage)
endsub
I got a ton errors.
In the program I'm working on I don't use your sdk.inc.
I use Paul's windows.inc
Got it to compile and create a bmp file but it only output 40 bytes; no actual image.
TYPE BITMAPFILEHEADER
DEF bfType:WORD
DEF bfSize:INT
DEF bfReserved1:WORD
DEF bfReserved2:WORD
DEF bfOffBits:INT
ENDTYPE
TYPE SECURITY_ATTRIBUTES
DEF nLength:INT
DEF lpSecurityDescriptor:INT
DEF bInheritHandle:INT
ENDTYPE
TYPE OVERLAPPED
DEF ternal:INT
DEF ternalHigh:INT
DEF offset:INT
DEF OffsetHigh:INT
DEF hEvent:INT
ENDTYPE
CONST CAPTUREBLT = &H40000000
CONST GENERIC_WRITE = &H40000000
CONST CREATE_ALWAYS = 2
DECLARE "user32.dll",GetWindowDC(hwnd:INT),INT
DECLARE "gdi32.dll",CreateDIBSection(hDC:INT, pBitmapInfo:BITMAPINFO, un:INT, lplpVoid:INT, handle:INT, dw:INT),INT
sub SaveScreenshot(hwnd:uint, path:string, fNonClient:int)
BITMAPINFOHEADER bmiHeader
BITMAPFILEHEADER filehdr
WINRECT rc
OVERLAPPED ol
ZeroMemory(ol, len(ol))
ZeroMemory(bmiHeader, len(bmiHeader))
bmiHeader.biSize = len(BITMAPINFOHEADER)
if (fNonClient)
_GetWindowRect(hwnd, rc)
int hdcSource = GetWindowDC(hwnd)
else
_GetClientRect(hwnd, rc)
hdcSource = _GetDC(hwnd)
endif
bmiHeader.biWidth = rc.right - rc.left ' target bitmap size
bmiHeader.biHeight = rc.bottom - rc.top
bmiHeader.biPlanes = 1
bmiHeader.biBitCount = 24
pointer pBits ' 24bit: RGBTRIPLE* 32bit:RGBQUAD*
uint hbmImage = CreateDIBSection(hdcSource, bmiHeader, DIB_RGB_COLORS, pBits, 0, 0)
uint hdcMemory = _CreateCompatibleDC(hdcSource)
hbmImage = _SelectObject(hdcMemory, hbmImage)
_BitBlt(hdcMemory,0,0, bmiHeader.biWidth, bmiHeader.biHeight, hdcSource, 0, 0, SRCCOPY | CAPTUREBLT)
hbmImage = _SelectObject(hdcMemory, hbmImage)
_DeleteDC(hdcMemory)
_ReleaseDC(hwnd, hdcSource)
int hFile = _CreateFile(path, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0)
int bilen = bmiHeader.biWidth * bmiHeader.biHeight * bmiHeader.biBitCount/8
pointer bytes=null
filehdr.bfType = 0x4d42 'MB'
filehdr.bfOffBits = len(BITMAPFILEHEADER) + len(BITMAPINFOHEADER)
filehdr.bfSize = len(BITMAPFILEHEADER) + len(BITMAPINFOHEADER) + bilen
filehdr.bfReserved1 = 0
filehdr.bfReserved2 = 0
_WriteFile(hFile, filehdr, len(filehdr), bytes, ol)
_WriteFile(hFile, bmiHeader, len(bmiHeader), bytes, ol)
_WriteFile(hFile, pBits, bilen, bytes, ol)
_CloseHandle(hFile)
_DeleteObject(hbmImage)
endsub
Larry
Larry,
Get the structures from the draw.eba sample, specifically SaveBitmap.inc which is included with your installation.
TYPE BITMAPFILEHEADER
should be
TYPE BITMAPFILEHEADER,1
Because it requires 1 byte packing.
Paul.
Larry, it creates 40 byte file if the hwnd is invalid. Do you remember win.hwnd ?
By the way here is the port for windows.inc:$include "windows.inc"
SaveScreenshot(_GetDesktopWindow(), "desktop.bmp", FALSE)
TYPE _BITMAPFILEHEADER,2
DEF bfType AS WORD
DEF bfSize AS INT
DEF bfReserved1 AS WORD
DEF bfReserved2 AS WORD
DEF bfOffBits AS INT
ENDTYPE
sub SaveScreenshot(int hwnd, string path, int fNonClient)
BITMAPINFOHEADER bmiHeader
_BITMAPFILEHEADER filehdr
WINRECT rc
if (!_IsWindow(hwnd)) then return _MessageBeep(MB_ICONHAND)
_RtlZeroMemory(&bmiHeader, len(bmiHeader))
bmiHeader.biSize = len(bmiHeader)
if (fNonClient)
_GetWindowRect(hwnd, rc)
int hdcSource = _GetWindowDC(hwnd)
else
_GetClientRect(hwnd, rc)
hdcSource = _GetDC(hwnd)
endif
bmiHeader.biWidth = rc.right - rc.left ' target bitmap size
bmiHeader.biHeight = rc.bottom - rc.top
bmiHeader.biPlanes = 1
bmiHeader.biBitCount = 24
pointer pBits ' 24bit: RGBTRIPLE* 32bit:RGBQUAD*
int hbmImage = _CreateDIBSection(hdcSource, bmiHeader, DIB_RGB_COLORS, &pBits, 0, 0)
int hdcMemory = _CreateCompatibleDC(hdcSource)
hbmImage = _SelectObject(hdcMemory, hbmImage)
_BitBlt(hdcMemory,0,0, bmiHeader.biWidth, bmiHeader.biHeight, hdcSource, 0, 0, SRCCOPY)
hbmImage = _SelectObject(hdcMemory, hbmImage)
_DeleteDC(hdcMemory)
_ReleaseDC(hwnd, hdcSource)
BFILE hFile
Openfile hFile, path, "W"
'int bilen = bmiHeader.biWidth * bmiHeader.biHeight * bmiHeader.biBitCount/8
BITMAP bm
_GetObject(hbmImage, len(bm), bm)
int bilen = bm.bmWidthBytes * bm.bmHeight
filehdr.bfType = 0x4d42 'MB'
filehdr.bfOffBits = len(filehdr) + len(bmiHeader)
filehdr.bfSize = len(filehdr) + len(bmiHeader) + bilen
filehdr.bfReserved1 = 0
filehdr.bfReserved2 = 0
__write hFile, *<string>&filehdr, len(filehdr)
__write hFile, *<string>&bmiHeader, len(bmiHeader)
__write hFile, *<string>pBits, bilen
CloseFile hFile
_DeleteObject(hbmImage)
endsub
Sapero
I now get a bitmap but had/have 2 issues.
1. I had to comment out ImageFilter(hbmImage) or it wouldn't compile.
update: I see from your post to fasecero that the above was just a typo here.
2. The saved bitmap will load into MSPaint and it looks fine.
If I go to thumbnail view in windows explorer the bitmap isn't displayed; just the generic thumbnail for a bitmap.
If I try to preview it in explorer it just displays "Drawing failed." in the center of the window.
All my other bitmaps display just fine.
Larry
Yes, the ImageFilter was from another thread, code updated
I have modified the code two times, first added _BITMAPFILEHEADER definition, then changed len(struct name) to len(variable name) because there was still a reference to the inproperly declared BITMAPFILEHEADER (windows.inc). But it always displayed fine in totalcommander preivew tool (F3 key).
The images it produces now are correct.
I updated with your revisions and still have the same problem as #2 above.
ok with MSPaint
ok with irfanwiew
won't open in MS PictureIt 2002
Larry
Ok updated again, the original code was designed for bitmaps with width and height multiple by two. Changed bilen variable:
BITMAP bm
_GetObject(hbmImage, len(bm), bm)
int bilen = bm.bmWidthBytes * bm.bmHeight
294*295, 295*295, and 295*294 bitmap now opens in pic/fax viewer and office picture viewer.
Sapero
It works perfect now.
Thank you so very much, as always!
Larry