Archived

This topic is now archived and is closed to further replies.

Loradim

(SOLVED) Taking a screenshot from a DirectX Window?

Recommended Posts

Hi @ all, i would like to take a screenshot from a DirectX (another process) and save it as an .bmp File. Guess what, it's not working Maybe you can tell what i did wrong? Or you tell me how to take a screenshot from another DirectX Window? (I usually don't do windows programming, so please forgive my bad skills in windows programming). Here is my source including with a few comments what seems to go wrong. Also i am not sure, whether i can take a screenshot from a DirectX-Window using GDI Calls? Any help is appreciated! Thx in advance! UPDATE: The other DirectX Window runs in WINDOW Mode. ~Loradim
HWND otherwindow;
HDC otherDC;
HDC memDC;
HBITMAP memBH;
HGDIOBJ myObject;
BITMAP bitmapbuffer;
unsigned char* buffer = NULL;

buffer = (unsigned char*) malloc (800*600*3*sizeof (char));
otherwindow = getotherwindow ();
otherDC = GetDC (otherwindow);
memDC = CreateCompatibleDC (otherDC);
memBH = CreateCompatibleBitmap (memDC, 800, 600); // Why do i get a 1x1 Bitmap here?
SetBitmapDimensionEx (memBH, 800, 600, NULL); // is this the right way to set height&width to bitmap?
BitBlt (memDC, 0, 0, 800, 600, otherDC, 0, 0, SRCCOPY); // Error, cause my created Bitmap is just 1x1 ??


// the following code should be correct, got it from the book "OpenGL Game Programming
FILE* fout;
BITMAPFILEHEADER bitmapFileHeader;
BITMAPINFOHEADER bitmapInfoHeader;
unsigned int imageIdx;
unsigned char tempRGB;
fout = fopen ("c:\\screenshot.bmp", "wb");
if (!fout) return 0;
bitmapFileHeader.bfSize = sizeof (BITMAPFILEHEADER);
bitmapFileHeader.bfType = 0x4d42;
bitmapFileHeader.bfReserved1 = 0;
bitmapFileHeader.bfReserved2 = 0;
bitmapFileHeader.bfOffBits = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER);

bitmapInfoHeader.biSize = sizeof (BITMAPINFOHEADER);
bitmapInfoHeader.biPlanes = 1;
bitmapInfoHeader.biBitCount = 24;
bitmapInfoHeader.biCompression = BI_RGB;
bitmapInfoHeader.biSizeImage = 800*600*3;
bitmapInfoHeader.biXPelsPerMeter = 0;
bitmapInfoHeader.biYPelsPerMeter = 0;
bitmapInfoHeader.biClrUsed = 0;
bitmapInfoHeader.biClrImportant = 0;
bitmapInfoHeader.biWidth = 800;
bitmapInfoHeader.biHeight = 600;

for (imageIdx = 0; imageIdx < bitmapInfoHeader.biSizeImage; imageIdx += 3)
{
	tempRGB = buffer[imageIdx];
	buffer[imageIdx] = buffer[imageIdx + 2];
	buffer[imageIdx + 2] = tempRGB;
}
fwrite (&bitmapFileHeader, 1, sizeof (BITMAPFILEHEADER), fout);
fwrite (&bitmapInfoHeader, 1, sizeof (BITMAPINFOHEADER), fout);
fwrite (&buffer, 1, bitmapInfoHeader.biSizeImage, fout);
fclose (fout);

DeleteObject (memBH);
ReleaseDC (gWnd, memDC);   // gWnd is a handle to my own window
ReleaseDC (otherwindow, otherDC);
free (buffer);
    
[edited by - Loradim on May 17, 2004 7:06:09 PM] [edited by - Loradim on May 19, 2004 2:27:36 AM] [edited by - Loradim on May 19, 2004 5:31:42 PM]

Share this post


Link to post
Share on other sites
IIRC, you can''t take a screenshot of a DX app with GDI calls because the DirectX window is hardware accelerated. The same thing applies to media player movies - try taking a screenshot, and it''s just a blank image.

Check out this article to see how you should be doing it. However, I''m not sure how you can do this from another process, since you need the IDirect3DDevice*.


Dustin Franklin
Mircrosoft DirectX MVP

Share this post


Link to post
Share on other sites
Dustin,

thank you for your reply! I see that i can''t take a screenshot from a directx window by using GDI calls. I hope it would work, but.. oh well.

Now i can take a screenshot pressing "ALT+PrintScreen". This actually copies the window to the clipboard. So SOMEHOW i must be able to get the data.

Any idea how?

~Loradim

Share this post


Link to post
Share on other sites
Linky

if you are using DX8.0 or 8.1 that article will compile, if you are using DX9.0 a-b then you have to change a couple of lines of code(im not at home or i''d at least tell you which, but if you try to compile it you can single them out and find the solution in the docs pretty quickly)


Best of Luck

Dredd
________________________________________

"To die with your sword still in its sheath is most regrettable" -- Miyomoto Musashi


Share this post


Link to post
Share on other sites
Dear Dredd,

i allready found this article, but from my understanding, i have to provide the IDirect3DDevice8-device to the function for working propably. So it propably has to be initalized correctly? As i want to take a screenshot from another programm, i think i don''t have the device yet?

Maybe I don''t have the right understanding of DirectX yet, so i will try it out.

Thank you for your help!

~Loradim

Share this post


Link to post
Share on other sites
I don't have time to explain, but maybe this quick copy
and paste of some D3DX code of mine will help ya

// Save Screen

LPDIRECT3DSURFACE9 BackBuffer = NULL;
Device->GetBackBuffer(0,0,D3DBACKBUFFER_TYPE_MONO,&BackBuffer);

for(INT v=0; v<999; v++)
{
sprintf(Dbm,"%s%s_%03d.bmp",Setup.ExeDir,Setup.AppName,v);
if(FileSize(Dbm) <= 0)
break;
}

D3DXSaveSurfaceToFile(Dbm, D3DXIFF_BMP, BackBuffer, NULL, NULL);

BackBuffer->Release();

Have fun

[edited by - Jiia on May 18, 2004 11:17:23 PM]

Share this post


Link to post
Share on other sites
I don''t have the device, as it is in another window!

Update: I found out, that GetPixel (); works for that DirectX Window, though BitBlt didn''t seem to work yet. Maybe i got something wrong. Will tell ya, when i somehow got it to work.

Thx for all replies so far!

~Loradim

Share this post


Link to post
Share on other sites
You are using Direct3D?

If you are, it is a simple matter of calling:

D3DXSaveSurfaceToFile( filename, *format, D3DBackBuffer, NULL, NULL );

Where D3DBackBuffer is a IDirect3DSurface9 * object that points to the backbuffer. You will need a device to get the back buffer -- see the documentation.

Share this post


Link to post
Share on other sites
Allright, i got it to work finally (working with GDI functions btw):

otherwindow = myClass.Getotherwindowhwnd();
myDC = GetDC (otherwindow);
memDC = CreateCompatibleDC (myDC);
myBitmap = CreateCompatibleBitmap (myDC, 800, 600);
SelectObject (memDC, myBitmap);
rc = BitBlt (memDC, 0, 0, 800, 600, myDC, 0, 0, SRCCOPY);

b = (char*) malloc (800*600*4);
for (int i=0;i < 256; i++) b = i;
BITMAPINFO* myInfo;
myInfo = (BITMAPINFO*) malloc (sizeof (BITMAPINFO) + sizeof(RGBQUAD)*800+600);
myInfo->bmiHeader.biBitCount = 32;
myInfo->bmiHeader.biClrImportant = 0;
myInfo->bmiHeader.biClrUsed = 0;
myInfo->bmiHeader.biCompression = BI_RGB;
myInfo->bmiHeader.biHeight = 600;
myInfo->bmiHeader.biPlanes = 1;
myInfo->bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
myInfo->bmiHeader.biSizeImage = 800*600*4;
myInfo->bmiHeader.biWidth = 800;
myInfo->bmiHeader.biXPelsPerMeter = 1;
myInfo->bmiHeader.biYPelsPerMeter = 1;
GetDIBits (memDC, myBitmap, 0, 600, b, myInfo, DIB_RGB_COLORS);
free (myInfo);
//free (b);

Now i have the screen shot in b[..] and can save it to disk. Thx for all replies anyway!!

~Loradim

Share this post


Link to post
Share on other sites