Jim,
I believe that the reason you are getting a NULL pvBits on the destination surface in your DrvStretchBlt call is because of the way you created your surface. Unless I am mistaken, it seems you called
EngCreateDeviceSurface
and probably should have instead called
EndCreateBitmap
When you call EngCreateDeviceSurface, you are, in effect, telling GDI “Look, take it for granted that I have created a surface bitmap that is X wide by Y high. I will take care of all the drawing operations.”
When told this, the GDI shrugs and says “OK, you’re the boss, but be ready to handle everything I throw at you.”
Then, during the calls to DrvStretchBlt, etc, the GDI will pass in a pointer to a bitmap representing the source bitmap, but the pvBits of the destination will be NULL because you have already, in essence, told GDI that YOU were going to take care of the actual destination bitmap surface.
Getting back to your original goal, if your desire is to merely process the final image before it makes its way to the printer, you should be able to get away with allowing GDI to do everything, up until the last moment.
I would try this…
In your DrvEnableSurface call, eliminate the call to EngCreateDeviceSurface and replace it with a call to EngCreateBitmap. In this call you tell the GDI how large to make the bitmap, and you also tell it the format. If you desire or require a full color RGB bitmap, make sure that you pass the argument BMF_24BPP, etc. So your call would look something like…
SIZEL bitmapsize;
bitmapsize.cx = bitmap width;
bitmapsize.cy = bitmap height;
EngCreateBitmap(bitmapsize, bitmapstride, BMF_24BPP, 0, NULL);
With this call, you will have asked GDI to allocate the memory for the bitmap, and it will be in a format that the GDI can directly do all the drawing on. The GDI will also KNOW about this surface, so in all Drv_xxx calls the destination surface will be this surface, and will no longer be NULL.
Also, there is no need to hook DrvStretchBlt, nor any of the other Drv_xxx drawing calls. If you hook DrvStretchBlt, etc, you will have to punt the call back to EngStretchBlt, etc. But if you do NOT hook the calls, then GDI will see that the calls are not hooked, and it will automatically call EngStretchBlt on your behalf, without you even having to bother with it. Unless you have a specific reason why you need to hook DrvStretchBlt, etc, such as collecting stats for decisions later, there is no reason to hook DrvStretchBlt if the only work it accomplishes is immediately punting the call to EngStretchBlt, etc. You have the option of not hooking the calls, saving the effort, and GDI will automatically rasterize EVERYTHING onto your surface bitmap.
The only call you would need to hook would be DrvSendPage. GDI will call this with a pointer to your surface bitmap, which has by that time been completely drawn and finished.
With the pointer to this surface, you can at that time modify, or pre-process the image by direct manipulation of the bits pointed to by pvBits. As I suggested earlier, you could create a function similar to the following…
MyBitmapPreProcessingFunction(SURFOBJ *surfin)
and within that function do whatever you desire to the complete page image.
Then send the image to EngWritePrinter.
If you cannot send the bitmap directly to the printer, but need to translate it into “…special fonts understood by the printer…” then within the DrvSendPage function you can traverse each scanline using the pointer to pvBits, make a translation of the pixel into the “font character”, and send it to the printer via EngWritePrinter, etc.
Again, you should not need to hook any of the drv_xxx drawing calls unless you are going to do MORE than merely punting them to Eng_xxx equivalents. If you do not hook them, the GDI will call them directly without any effort on your part.
DrvSendPage is your best chance at getting access to the completely finished page in a rasterized format, and doing whatever you need before sending it on its way to the printer.
Cary J.