A GDI-based Screenshot Method
I was struggling with trying to make an easy screenshot method using SlimDX. Looking at MDX samples, the standard method was to grab the Backbuffer into a surface (Device.GetBackbuffer), then use the SurfaceLoader.Save helper method to save that surface to a file. I have not been able to find that SurfaceLoader.Save method anywhere within SlimDX. (I have added it to the SlimDX "issues" list as an enhancement request.)
In the meantime, I was looking for a way to make it work. An internet acquaintence of mine (and a hyper-good coder also working on a SlimDX-based project), CodeImp, suggested that I lock the surface and transfer the data to a GDI bitmap and use the Bitmap's ability to save-to-file. I also wondered about using the SlimDX's Texture.FromStream method to create a texture from the surface, then do a Texture.SaveToFile ... but none of these worked. For some reason, once I locked the rectangle on the surface, that LockedRect's Stream wasn't able to get its own length -- so it kept throwing errors.
So, my next attempt was to use the surface's GetDC to see if I could create a GDI Graphics device from that DC and do something with it that way. That's where the "looky what I found" happened ... GDI Graphics devices have a method called "CopyFromScreen", which does exactly what it says. This made me drop any SlimDX-related code and go pure GDI, with great results.
Here are the steps:
-
Determine your Top, Left, Width, and Height to capture ... if in full screen, these are 0,0,ScreenWidth,ScreenHeight ... if in windowed, these are the Top, Left, Width, Height of your Game Form
-
Create a new Bitmap using Width and Height
-
Create a Graphics Device from the new Bitmap
-
Do Graphics.CopyFromScreen
-
Do Bitmap.Save
-
Dispose the Graphics Device and Bitmap
So, it's not quite the 3-step process available with MDX, but this pure-GDI process should work no matter what your drawing system is. Here's the actual VB.Net code:
tempBMP = New Bitmap(tempWidth, tempHeight)
G = System.Drawing.Graphics.FromImage(tempBMP)
G.CopyFromScreen(tempLeft, tempTop, 0, 0, New Size(tempWidth, tempHeight))
tempFileName = "Screenshot_" & Date.Now.ToString("yyyyMMdd_hhmmss") & ".png"
tempBMP.Save(tempFileName, System.Drawing.Imaging.ImageFormat.Png)
G.Dispose()
tempBMP.Dispose()
This routine names the file using the current date and time (down to the second) and saves it as a PNG. It seems to work fine in both windowed and fullscreen mode.
-Matt