Draw exactly 1 pixel width line using C/C++ and WinApi - winapi

I am trying to draw the line using C/C++ code and Win API functions. For the specific reason I need to have exactly 1 pixel line width, but what I am getting on the screen is completely different. Depending on the ways of Pen/Brush settings it could be either 2 or 3 pixels wide line and never 1.
Just for the test I’ve tried to draw 3 pixels line and as a result getting 5 pixels.
The same story with other kind of drawing primitives: rounded rectangles, rectangles, ellipses etc.
Is there any way to disable such shadow bounding around drawn lines?
Code sample of drawing function is below.
void DisplayDrawings (HDC hDC, HWND hWnd)
{
LOGBRUSH stLogBrush;
RECT rRect = {0,0,0,0};
HBITMAP hBitmap = NULL;
HBRUSH hBrush = NULL;
HGDIOBJ hOldBrush = NULL;
HGDIOBJ hOldPen = NULL;
HPEN hPen = NULL;
BOOL bB_Result = FALSE;
UINT bBrushByBits [8];
int iRightPos = 0;
int iLeftPos = 30;
int iLineY = 30;
int iDrawStep = 10;
int i = 0;
#ifndef RGBA
#define RGBA(r,g,b,a) ((COLORREF)( (((DWORD)(BYTE)(a))<<24) | RGB(r,g,b) ))
#endif
SetBkMode (hDC, OPAQUE);
bB_Result = GetClientRect(hWnd, &rRect);
if (bB_Result == FALSE)
{
return;
}
iRightPos = rRect.right - 30 - 1;
// Line 1. Draw 1 pixel Line using standard brush/pen.
hPen = CreatePen (PS_SOLID,1, RGB(255, 0,0));
hOldPen = SelectObject (hDC, hPen);
if (hOldPen == NULL)
{
return;
}
MoveToEx (hDC, iLeftPos,iLineY,NULL);
LineTo (hDC,iRightPos,iLineY);
SelectObject (hDC, hOldPen);
DeleteObject (hPen);
iLineY += iDrawStep;
// Result - line with 2 pixels width
// Line 2. Draw 1 pixel Line using standard brush/pen, but setting pen width to "0". CreatePen API says: "If nWidth is zero, the pen is a single pixel wide, regardless of the current transformation"
hPen = CreatePen (PS_SOLID,0, RGB(255, 0,0));
hOldPen = SelectObject (hDC, hPen);
if (hOldPen == NULL)
{
return;
}
MoveToEx (hDC, iLeftPos,iLineY,NULL);
LineTo (hDC,iRightPos,iLineY);
SelectObject (hDC, hOldPen);
DeleteObject (hPen);
iLineY += iDrawStep;
// Result - line with 3 pixels width
// Line 3. Draw 1 pixel as above, but set current brush to NULL
hOldBrush = SelectObject (hDC, GetStockObject(NULL_BRUSH));
if (hOldBrush == NULL)
{
return;
}
hPen = CreatePen (PS_SOLID,0, RGB(255, 0,0));
hOldPen = SelectObject (hDC, hPen);
if (hOldPen == NULL)
{
return;
}
MoveToEx (hDC, iLeftPos,iLineY,NULL);
LineTo (hDC,iRightPos,iLineY);
SelectObject (hDC, hOldPen);
DeleteObject (hPen);
SelectObject (hDC, hOldBrush);
iLineY += iDrawStep;
// Result - line with 2 pixels width
// Line 4. Draw 3 pixel Line using standard brush/pen
hPen = CreatePen (PS_SOLID,3, RGB(255, 0,0));
hOldPen = SelectObject (hDC, hPen);
if (hOldPen == NULL)
{
return;
}
MoveToEx (hDC, iLeftPos,iLineY,NULL);
LineTo (hDC,iRightPos,iLineY);
SelectObject (hDC, hOldPen);
DeleteObject (hPen);
iLineY += iDrawStep;
// Result - line with 5 pixels width
// Line 5. Draw 3 pixel as above, but set current brush to NULL
hOldBrush = SelectObject (hDC, GetStockObject(NULL_BRUSH));
if (hOldBrush == NULL)
{
return;
}
hPen = CreatePen (PS_SOLID,3, RGB(255, 0,0));
hOldPen = SelectObject (hDC, hPen);
if (hOldPen == NULL)
{
return;
}
MoveToEx (hDC, iLeftPos,iLineY,NULL);
LineTo (hDC,iRightPos,iLineY);
SelectObject (hDC, hOldPen);
DeleteObject (hPen);
SelectObject (hDC, hOldBrush);
iLineY += iDrawStep;
// Result - line with 5 pixels width
// Line 6. Draw 1 pixel line by creating own pen with monochrome 8x8 brush. Result is 3
int k = 0;
for(i = 0; i < 8; i++)
{
bBrushByBits [i] = 0x00;
}
hBitmap = CreateBitmap(8, 8, 1, 1, (LPBYTE)bBrushByBits);
if (hBitmap == NULL)
{
return;
}
stLogBrush.lbColor = RGBA(255,0,0,0);
stLogBrush.lbHatch = (ULONG_PTR) hBitmap;
stLogBrush.lbStyle = BS_PATTERN;
hPen = ExtCreatePen (PS_GEOMETRIC, 3, &stLogBrush, 0, NULL);
hOldPen = SelectObject (hDC, hPen);
if (hOldPen == NULL)
{
return;
}
MoveToEx (hDC, iLeftPos,iLineY,NULL);
LineTo (hDC,iRightPos,iLineY);
SelectObject (hDC, hOldPen);
DeleteObject (hPen);
DeleteObject (hBitmap);
// Result - line with 2 pixels width
}
Thanks in advance

tl;dr: DPI Awareness.
Windows scales graphics up for high-DPI monitors unless you explicitly tell it that your program understands how to work with the actual DPI.
You can do this with a manifest or a system call very early in your application. The original version of the API was SetProcessDPIAware. The newer version is SetProcessDPIAwareness, which lets you tell Windows you know what your doing even on a multi-monitor system where the monitors have different DPIs.

Related

how to capture window in windows 10 with c++

I tried use gdi to capture certain window, it's ok for most window.
But to some window like "visual studio code", it doesn't work.
DX can't support capturing certain window.
How should I do? THANKS
::EnumWindows(EnumWindowsProc, NULL);
if (hCapWnd == NULL)
{
return FALSE;
}
SwitchToThisWindow(hCapWnd, true);
Sleep(1000);
//HWND hDesktopWnd = GetDesktopWindow();
HDC hDesktopDC = GetWindowDC(hCapWnd);
HDC hCaptureDC = CreateCompatibleDC(hDesktopDC);
SetStretchBltMode(hCaptureDC, COLORONCOLOR);
RECT rc;
::GetWindowRect(hCapWnd, &rc);
int width = rc.right - rc.left;
int height = rc.bottom - rc.top;
HBITMAP hCaptureBitmap = CreateCompatibleBitmap(hDesktopDC, width, height);
SelectObject(hCaptureDC, hCaptureBitmap);
BOOL bRet = BitBlt(hCaptureDC, 0, 0, width, height, hDesktopDC, 0, 0, SRCCOPY);
Init(width, height);
int nRet = GetDIBits(hCaptureDC, hCaptureBitmap, 0, height, buf, (BITMAPINFO*)&m_bitmapInfo, DIB_RGB_COLORS);
static int n = 0;
//if (n++ % 10 == 0)
{
// std::string name = ustd::format_string("%s\\%d.bmp", ustd::get_program_path().c_str(), n);
SaveBitmapToFile(hCaptureBitmap);
}
ReleaseDC(hCapWnd, hDesktopDC);
DeleteDC(hCaptureDC);
DeleteObject(hCaptureBitmap);

WINAPI - Set background & text color of a combo box dropdown

So I was trying to set a ComboBox's background & text color using Common-Controls & WINAPI.
I did manage to set the background & text color of the combo box itself, but the colors of its dropdown list remain the same.
Here is pretty much what I did:
When creating the combo box, I used the CBS_DROPDOWNLIST style (along with WS_VISIBLE & WS_CHILD).
Then in the window handler function, I handled the CTLCOLOR_LISTBOX messge in the following way:
SetBkMode(dc, OPAQUE);
SetTextColor(dc, RGB(255, 255, 255));
SetBkColor(dc, 0x383838);
comboBrush = CreateSolidBrush(0x383838); //global var
return (LRESULT)comboBrush;
As I said, this only colors the combobox itself, and not its drop-down list.
How can I can color the drop down list as well?
For the background color and text color of the combo box, you can handle the WM_CTLCOLORLISTBOX and WM_CTLCOLOREDIT messages respectively.
WM_CTLCOLORLISTBOX : Sent to the parent window of a list box before
the system draws the list box. By responding to this message, the
parent window can set the text and background colors of the list box
by using the specified display device context handle.
Some code:
// Create Combox control
int xpos = 100; // Horizontal position of the window.
int ypos = 100; // Vertical position of the window.
int nwidth = 200; // Width of the window
int nheight = 200; // Height of the window
HWND hwndParent = hWnd; // Handle to the parent window
hWndComboBox = CreateWindow(WC_COMBOBOX, TEXT(""),
CBS_DROPDOWNLIST | WS_CHILD | WS_VISIBLE,
xpos, ypos, nwidth, nheight, hwndParent, NULL, hInstance,
NULL);
// load the combobox with item list.
// Send a CB_ADDSTRING message to load each item
TCHAR Planets[9][10] =
{
TEXT("Mercury"), TEXT("Venus"), TEXT("Terra"), TEXT("Mars"),
TEXT("Jupiter"), TEXT("Saturn"), TEXT("Uranus"), TEXT("Neptune"),
TEXT("Pluto??")
};
TCHAR A[16];
int k = 0;
memset(&A, 0, sizeof(A));
for (k = 0; k <= 8; k += 1)
{
wcscpy_s(A, sizeof(A) / sizeof(TCHAR), (TCHAR*)Planets[k]);
// Add string to combobox.
SendMessage(hWndComboBox, (UINT)CB_ADDSTRING, (WPARAM)0, (LPARAM)A);
}
// Send the CB_SETCURSEL message to display an initial item
// in the selection field
SendMessage(hWndComboBox, CB_SETCURSEL, (WPARAM)2, (LPARAM)0);
...
Updated:
//Windows Process
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CTLCOLORLISTBOX:
{
COMBOBOXINFO info;
info.cbSize = sizeof(info);
SendMessage(hWndComboBox, CB_GETCOMBOBOXINFO, 0, (LPARAM)&info);
COMBOBOXINFO info1;
info1.cbSize = sizeof(info1);
SendMessage(hWndComboBox1, CB_GETCOMBOBOXINFO, 0, (LPARAM)&info1);
if ((HWND)lParam == info.hwndList)
{
HDC dc = (HDC)wParam;
SetBkMode(dc, OPAQUE);
SetTextColor(dc, RGB(255, 255, 0));
SetBkColor(dc, 0x383838); //0x383838
HBRUSH comboBrush = CreateSolidBrush(0x383838); //global var
return (LRESULT)comboBrush;
}
if ((HWND)lParam == info1.hwndList)
{
HDC dc = (HDC)wParam;
SetBkMode(dc, OPAQUE);
SetTextColor(dc, RGB(255, 0, 0));
SetBkColor(dc, RGB(0, 0, 255));
HBRUSH comboBrush = CreateSolidBrush(RGB(0, 0, 255));
return (LRESULT)comboBrush;
}
}
case WM_CTLCOLOREDIT:
{
HWND hWnd = (HWND)lParam;
HDC dc = (HDC)wParam;
if (hWnd == hWndComboBox)
{
SetBkMode(dc, OPAQUE);
SetTextColor(dc, RGB(255, 0, 255));
SetBkColor(dc, 0x383838); //0x383838
HBRUSH comboBrush = CreateSolidBrush(0x383838); //global var
return (LRESULT)comboBrush;
}
else if (hWnd == hWndComboBox1)
{
SetBkMode(dc, OPAQUE);
SetTextColor(dc, RGB(255, 255, 0));
SetBkColor(dc, RGB(0, 255, 0));
HBRUSH comboBrush = CreateSolidBrush(RGB(0, 255, 0));
return (LRESULT)comboBrush;
}
}
...
Change the background color by comparing the edit handle and listbox handle returned by the window.
Debug:

winapi - painting rich edit thin border

By default a rich edit control has a "3d" border. I draw a thin border around a rich edit control this way:
if (message == WM_NCPAINT)
{
RECT rc;
HDC hdc;
HPEN pen;
HBRUSH brush;
HGDIOBJ oldP, oldB;
POINT tl, br;
::GetWindowRect(hWnd, &rc);
hdc = ::GetDC(hWnd);
tl.x = rc.left;
tl.y = rc.top;
br.x = rc.right;
br.y = rc.bottom;
::ScreenToClient(hWnd, &tl);
::ScreenToClient(hWnd, &br);
pen = ::CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
brush = (HBRUSH) ::GetStockObject(HOLLOW_BRUSH);
oldP = ::SelectObject(hdc, pen);
oldB = ::SelectObject(hdc, brush);
::Rectangle(hdc, tl.x, tl.y, br.x, br.y);
::SelectObject(hdc, oldP);
::SelectObject(hdc, oldB);
::DeleteObject(pen);
::ReleaseDC(hWnd, hdc);
return 0;
}
The border looks fine but the area under the old border is not redrawn. It looks like I have to redraw to whole content of the rich edit control. After that a text shouldn't be a litte bit cut from the bottom. Here you can see what I mean (the second rich edit control has custom border). How to achieve it ?
GetDC returns DC for client area. In this case you need GetWindowDC for the whole richedit window.
Either way, overriding border color in edit and rich-edit can be difficult, because you also have to handle scrollbar painting in WM_NCPAINT
Assuming you don't need vertical and/or horizontal scrollbar, use GetWindowDC as follows:
LRESULT CALLBACK RichEditProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp,
UINT_PTR, DWORD_PTR)
{
static int border_thickness = 1;
switch(msg)
{
case WM_NCPAINT:
{
HDC hdc = GetWindowDC(hwnd);
RECT rc;
GetClientRect(hwnd, &rc);
rc.right += 2 * border_thickness + 1;
rc.bottom += 2 * border_thickness + 1;
HBRUSH hbrush = (HBRUSH)GetStockObject(NULL_BRUSH);
HPEN hpen = CreatePen(PS_SOLID, 2 * border_thickness, RGB(255, 0, 0));
HBRUSH oldbrush = (HBRUSH)SelectObject(hdc, hbrush);
HPEN oldpen = (HPEN)SelectObject(hdc, hpen);
Rectangle(hdc, rc.left, rc.top, rc.right, rc.bottom);
SelectObject(hdc, oldpen);
SelectObject(hdc, oldbrush);
DeleteObject(hpen);
DeleteObject(hbrush);
ReleaseDC(hwnd, hdc);
return 0;
}
case WM_NCCALCSIZE:
if(lp)
{
NCCALCSIZE_PARAMS* sz = (NCCALCSIZE_PARAMS*)lp;
InflateRect(&sz->rgrc[0], -border_thickness, -border_thickness);
return 0;
}
break;
case WM_NCDESTROY:
RemoveWindowSubclass(hwnd, RichEditProc, 0);
break;
}
return DefSubclassProc(hwnd, msg, wp, lp);
}
By default, WM_NCCALCSIZE is not called in subclass procedure, you have to call SetWindowPos with SWP_FRAMECHANGED
HWND hrichedit = CreateWindowEx(...);
SetWindowSubclass(hrichedit, RichEditProc, 0, 0);
SetWindowPos(hrichedit, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
If you do need horizontal/vertical scrollbar, you might consider using a borderless richedit, then paint around the rich control in parent window's WM_PAINT procedure.

How do i Use Fillrect or DrawText on 32bit HBITMAP in C++

i'm sorry for what i did. i edited.
i'd like to use Fillrect on 32bit HBITMAP which is Created with CreateDIBSection
but i can't make rect visible in color that i want to.
(i Drawed a fillrect with CreateSolidBrush blue(RGB(0, 0, 255)) on 32bit HBITMAP(hdcbmp), but it doesn't appear blue.)
here is source code
is there anyway to show rect color that i want to?
sorry for my poor english.
void DrawAlphaBitmap(HWND hWnd, ULONG uWidth, ULONG uHeight)
{
BLENDFUNCTION bf;
HBITMAP hbitmap;
HBITMAP hOldBitmap;
BITMAPINFO bmi;
PVOID pvBits;
HDC hdcwnd = GetDC(hWnd);
HDC hdcbmp = CreateCompatibleDC(hdcwnd);
ZeroMemory(&bmi, sizeof(BITMAPINFO));
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = uWidth;
bmi.bmiHeader.biHeight = uHeight;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biSizeImage = bmi.bmiHeader.biWidth * bmi.bmiHeader.biHeight * 4;
hbitmap = CreateDIBSection(hdcbmp, &bmi, DIB_RGB_COLORS, &pvBits, NULL, 0x0);
hOldBitmap = (HBITMAP)SelectObject(hdcbmp, hbitmap);
bf.BlendOp = AC_SRC_OVER;
bf.BlendFlags = 0;
bf.SourceConstantAlpha = 0xff;
bf.AlphaFormat = AC_SRC_ALPHA;
RECT rc2 = { 100, 100, 200, 200 };
FillRect(hdcbmp, &rc2, CreateSolidBrush(RGB(0, 0, 255)));
AlphaBlend(hdcwnd, 0, 0, uWidth, uHeight, hdcbmp, 0, 0, uWidth, uHeight, bf);
SelectObject(hdcbmp, hOldBitmap);
DeleteObject(hbitmap);
DeleteDC(hdcbmp);
ReleaseDC(hWnd, hdcwnd);
}
From documentation for BLENDFUNCTION:
AlphaFormat:
This flag is set when the bitmap has an Alpha channel (that is, per-pixel alpha).
In this case, alpha channel is not set. CreateDIBSection initializes the alpha values to zero. When AC_SRC_ALPHA is set, AlphaBlend ignores pixels whose alpha value is zero. Modify your code as follows:
//bf.AlphaFormat = AC_SRC_ALPHA; <- remove
bf.AlphaFormat = 0; //replace with 0
Side note, you have resource leak in creation of HBRUSH handle. Change the code to
HBRUSH hbrush = CreateSolidBrush(RGB(0, 0, 255));
RECT rc2 = { 0, 0, w, h };
FillRect(memdc, &rc2, hbrush);
DeleteObject(hbrush);
Ideally, your function prototype should be void DrawAlphaBitmap(HDC hdc, ULONG uWidth, ULONG uHeight); so that HDC can be passed directly, for example from BeginPaint/EndPaint in WM_PAINT message.

Resizing bitmap for CreatePatternBrush when printing

I am trying to print a brush pattern like I see on the screen but I get different results depending on the printer DC. I use Microsoft PDF or a printer. Both are printing using 600 DPI. I'm trying to get the same pattern when I'm printing by resizing the bitmap that is being used by CreatePatternBrush. This seems to work fine for Microsoft PDF but not for the printer. The pattern using the printer is way too large. Any clue why?
OnBnClickedButtonprint is where I'm trying to print where ScaleBitmap is done on the pattern bitmap. Here is the code:
#include "stdafx.h"
#include "Printing.h"
#include "PrintingDlg.h"
#include "afxdialogex.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
RECT rcSmall = { 25, 25, 75, 75 };
RECT rcBig = { 55, 55, 255, 255 };
RECT rcWholeArea = { 0, 0, 300, 300 };
COLORREF crRed = RGB(255, 0, 0);
COLORREF crGreen = RGB(0, 255, 0);
COLORREF crBlue = RGB(0, 0, 255);
COLORREF crWhite = RGB(255, 255, 255);
COLORREF crBlack = RGB(0, 0, 0);
CPrintingDlg::CPrintingDlg(CWnd* pParent /*=NULL*/)
: CDialogEx(IDD_PRINTING_DIALOG, pParent)
{
WORD HatchBits[8] = { 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe };
m_hBitmap = ::CreateBitmap(8, 8, 1, 1, HatchBits);
}
void CPrintingDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CPrintingDlg, CDialogEx)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BUTTONPRINT, &CPrintingDlg::OnBnClickedButtonprint)
END_MESSAGE_MAP()
// CPrintingDlg message handlers
BOOL CPrintingDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
return TRUE; // return TRUE unless you set the focus to a control
}
HBITMAP CPrintingDlg::ScaleBitmap(HDC hdc, HBITMAP hBitmapSrc)
{
double gDPIScaleX = GetDeviceCaps(hdc, LOGPIXELSX) / 96.0f;
double gDPIScaleY = GetDeviceCaps(hdc, LOGPIXELSY) / 96.0f;
if (gDPIScaleX == 1.0 && gDPIScaleY == 1.0)
return hBitmapSrc;
// Get logical coordinates
BITMAP bm;
::GetObject(hBitmapSrc, sizeof(bm), &bm);
int iWidth = (int)(bm.bmWidth * gDPIScaleX);
int iHeight = (int)(bm.bmHeight * gDPIScaleY);
// Select the source DC
HDC hdcSrc = ::CreateCompatibleDC(hdc);
HBITMAP hBitmapOldSrc = (HBITMAP)::SelectObject(hdcSrc, hBitmapSrc);
// Create the bitmap and select the destination DC
HDC hdcDst = ::CreateCompatibleDC(hdc);
HBITMAP hBitmapDst = ::CreateCompatibleBitmap(hdcDst, iWidth, iHeight);
HBITMAP hBitmapOldDst = (HBITMAP)::SelectObject(hdcDst, hBitmapDst);
// Resize
::StretchBlt(hdcDst, 0, 0, iWidth, iHeight, hdcSrc, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
// Reselect the old bitmaps
::SelectObject(hdcSrc, hBitmapOldSrc);
::SelectObject(hdcDst, hBitmapOldDst);
// Delete the resources
DeleteDC(hdcSrc);
DeleteDC(hdcDst);
return hBitmapDst;
}
RECT CPrintingDlg::ScaleRect(HDC hdc, RECT rcOriginal)
{
double gDPIScaleX = GetDeviceCaps(hdc, LOGPIXELSX) / 96.0f;
double gDPIScaleY = GetDeviceCaps(hdc, LOGPIXELSY) / 96.0f;
if (gDPIScaleX == 1.0 && gDPIScaleY == 1.0)
return rcOriginal;
RECT rcScaled;
rcScaled.left = (long)(rcOriginal.left * gDPIScaleX);
rcScaled.right = (long)(rcOriginal.right * gDPIScaleX);
rcScaled.top = (long)(rcOriginal.top * gDPIScaleY);
rcScaled.bottom = (long)(rcOriginal.bottom * gDPIScaleY);
return rcScaled;
}
void CPrintingDlg::DrawRectangle(HDC hdc, RECT rect, COLORREF cr)
{
HPEN hPen = ::CreatePen(PS_SOLID, 1, cr);
::SelectObject(hdc, hPen);
HBRUSH hBrush = ::CreateSolidBrush(cr);
::SelectObject(hdc, hBrush);
::Rectangle(hdc, rect.left, rect.top, rect.right, rect.bottom);
}
void CPrintingDlg::DrawPatternRectangle(HDC hdc, HBITMAP hBitmap, RECT rect, COLORREF cr)
{
int oldROP2 = 0;
HPEN hPen = ::CreatePen(PS_SOLID, 1, crBlack);
::SelectObject(hdc, hPen);
HBRUSH hPatternBrush = ::CreatePatternBrush(hBitmap);
::SelectObject(hdc, hPatternBrush);
::SetTextColor(hdc, crBlack);
if (::GetROP2(hdc) == R2_COPYPEN)
{
::SetBkColor(hdc, crWhite);
oldROP2 = ::SetROP2(hdc, R2_MASKNOTPEN);
::Rectangle(hdc, rect.left, rect.top, rect.right, rect.bottom);
::SetBkColor(hdc, cr);
::SetROP2(hdc, R2_MERGEPEN);
::Rectangle(hdc, rect.left, rect.top, rect.right, rect.bottom);
::SetROP2(hdc, oldROP2);
}
else
{
::SetBkColor(hdc, cr);
::Rectangle(hdc, rect.left, rect.top, rect.right, rect.bottom);
}
}
void CPrintingDlg::OnPaint()
{
CPaintDC hdc(this);
DrawRectangle(hdc, rcWholeArea, crWhite);
DrawRectangle(hdc, rcSmall, crGreen);
DrawPatternRectangle(hdc, m_hBitmap, rcBig, crRed);
}
void CPrintingDlg::OnBnClickedButtonprint()
{
CPrintDialog dlgPrint(FALSE, PD_NOSELECTION);
dlgPrint.GetDefaults();
dlgPrint.m_pd.Flags &= ~PD_RETURNDEFAULT;
DEVMODE* dm = (DEVMODE*)GlobalLock(dlgPrint.m_pd.hDevMode);
dm->dmFields |= DM_ORIENTATION;
dm->dmOrientation = DMORIENT_LANDSCAPE;
GlobalUnlock(dlgPrint.m_pd.hDevMode);
dlgPrint.DoModal();
HDC hdc = dlgPrint.GetPrinterDC();
DOCINFO docInfo;
ZeroMemory(&docInfo, sizeof(docInfo));
docInfo.cbSize = sizeof(docInfo);
docInfo.lpszDocName = _T("PrintTest");
StartDoc(hdc, &docInfo);
StartPage(hdc);
DrawRectangle(hdc, ScaleRect(hdc, rcWholeArea), crWhite);
DrawRectangle(hdc, ScaleRect(hdc, rcSmall), crGreen);
DrawPatternRectangle(hdc, ScaleBitmap(hdc, m_hBitmap), ScaleRect(hdc, rcBig), crRed);
EndPage(hdc);
EndDoc(hdc);
DeleteDC(hdc);
}
Here is what I'm trying to print:

Resources