Related
I'm trying to make a custom title bar/border and I want it to be half transparent. When I load the image it works fine, but as soon, as I make even just 1 pixel from 255 opacity to 254, it just shows a white image.
Help would really be appreciated!
I use the windows.h library.
I use a resource ( .rc ) file to get the location of the images.
Don't think about where im doing things right, it's just for testing. I know it's not very efficient.
The Code!
( or at least the most of it / the important )
#include "../resource/resource.h"
#include "../header/Window.h"
#pragma warning(disable : 4244)
/////////////////////////
// Window
//
LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
HWND m_hWnd;
POINT wndSize = { 900, 900 };
Window::Window() : m_hInstance(GetModuleHandle(nullptr))
{
const wchar_t * className = L"Main Window";
WNDCLASS wc = {};
wc.lpszClassName = className;
wc.hInstance = m_hInstance;
wc.hIcon = LoadIcon(m_hInstance, MAKEINTRESOURCE(IDI_ICON));
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpfnWndProc = WindowProc;
wc.hbrBackground = CreatePatternBrush(LoadBitmap(m_hInstance, MAKEINTRESOURCE(IDB_BG)));
RegisterClass(&wc);
DWORD style = NULL;
RECT rect;
rect.left = GetSystemMetrics(SM_CXSCREEN) * .5 - (wndSize.x * .5);
rect.top = GetSystemMetrics(SM_CYSCREEN) * .5 - (wndSize.y * .5);
rect.right = rect.left + wndSize.x;
rect.bottom = rect.top + wndSize.y;
AdjustWindowRect(&rect, style, false);
m_hWnd = CreateWindowEx(
0,
className,
L"Chess",
style,
rect.left,
rect.top,
rect.right - rect.left,
rect.bottom - rect.top,
NULL,
NULL,
m_hInstance,
NULL
);
SetWindowLongPtr(m_hWnd, GWL_STYLE, NULL); // Remove the default borders
ShowWindow(m_hWnd, SW_SHOW);
}
Window::~Window()
{
const wchar_t * className = L"Main Window";
UnregisterClass(className, m_hInstance);
}
bool Window::ProcessMessage()
{
MSG msg = {};
RECT rectBorder;
HBRUSH colorBorder = CreatePatternBrush(LoadBitmap(m_hInstance, MAKEINTRESOURCE(IDB_TOP)));
//BitBlt(GetWindowDC(m_hWnd), 0, 0, 900, 30, GetWindowDC(m_hWnd), 0, 0, SRCINVERT);
//BitBlt(GetWindowDC(m_hWnd), 0, 0, 900, 30, GetWindowDC(m_hWnd), 0, 0, SRCAND);
//BitBlt(GetWindowDC(m_hWnd), 0, 0, 900, 30, GetWindowDC(m_hWnd), 0, 0, SRCINVERT);
while(PeekMessage(&msg, nullptr, 0u, 0u, PM_REMOVE))
{
switch(msg.message)
{
case WM_MOUSEMOVE: // On mouse motion
Window::updateWndEvents();
break;
case WM_PAINT: // On draw request
rectBorder = { 0, 0, wndSize.x, 30 };
FillRect(GetWindowDC(m_hWnd), &rectBorder, colorBorder); // Draw the top border
break;
case WM_QUIT: // On quit
return false;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return true;
}
/////////////////////////
// Window Functions
//
void Window::resizeWindow()
{
}
void Window::moveWindow()
{
}
void Window::updateWndEvents()
{
}
The alpha channel of a PNG image cannot be loaded using LoadBitmap.
It is recommended to use LockBits with PixelFormat32bppARGB in GDI+.
I am very new to the win10 dev, and I am trying to create a win10 app which will create a floating window in all the monitors the system is connected to. So far I am successful in using GDI API to create window in my primary monitor, but it is not working on my secondary monitor, I cannot get why it is not working even when I am using the API as mentioned in the microsoft page.
Below is my code
// Register the window class.
WNDCLASSEX wcex = { sizeof(WNDCLASSEX) };
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = DXGIDraw::WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = sizeof(LONG_PTR);
wcex.hInstance = HINST_THISCOMPONENT;
wcex.hbrBackground = NULL;
wcex.lpszMenuName = NULL;
wcex.hCursor = LoadCursor(NULL, IDI_APPLICATION);
wcex.lpszClassName = L"DemoApp";
RegisterClassEx(&wcex);
m_hwnd = CreateWindowEx(WS_EX_LAYERED,
L"DemoApp",
L"Demo App",
0,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
HWND_DESKTOP,
NULL,
HINST_THISCOMPONENT,
NULL
);
const int nWidth = GetSystemMetrics(SM_CXSCREEN);
const int nHeight = GetSystemMetrics(SM_CYSCREEN);
CImage img;
DISPLAY_DEVICE ddd;
ZeroMemory(&ddd, sizeof(ddd));
ddd.cb = sizeof(ddd);
for (int i = 0; EnumDisplayDevices(NULL, i, &ddd, 0); i++)
{
if (ddd.StateFlags & DISPLAY_DEVICE_ACTIVE) {
//Active monitor
}
if (ddd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) {
//Primary monitor
}
else {
//other types
}
}
//The following API supposed to work for all the monitors, but this API is not working. This is where I need attention.
HDC hdcScreen = CreateDC(ddd.DeviceName, NULL, NULL, NULL);
//But if I use below API I can get it working for the primary monitor only, still trying to understand why
//HDC hdcScreen = CreateDC(L"DISPLAY", NULL, NULL, NULL);
HDC hDC = CreateCompatibleDC(hdcScreen);
HBITMAP hBmp = CreateCompatibleBitmap(hdcScreen, nWidth, nHeight);
HBITMAP hBmpOld = (HBITMAP)SelectObject(hDC, hBmp);
img.Draw(hDC, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight);
//Add layered window
BLENDFUNCTION blend = { 0 };
blend.BlendOp = AC_SRC_OVER;
blend.SourceConstantAlpha = 255;
blend.AlphaFormat = AC_SRC_ALPHA;
POINT ptLocation = { 0, 0 };
SIZE szWnd = { nWidth, nHeight };
POINT ptSrc = { 0, 0 };
BOOL status1 = UpdateLayeredWindow(m_hwnd, hdcScreen, &ptLocation, &szWnd, hDC, &ptSrc, 0, &blend, ULW_ALPHA);
//Set window's position
BOOL status = SetWindowPos(m_hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
hr = m_hwnd ? S_OK : E_FAIL;
if (SUCCEEDED(hr))
{
BOOL status;
status = ShowWindow(m_hwnd, SW_MAXIMIZE);
status = UpdateWindow(m_hwnd);
}
SelectObject(hDC, hBmpOld);
DeleteObject(hBmp);
DeleteDC(hDC);
ReleaseDC(NULL, hdcScreen);
}
EnumDisplayDevices is the wrong API for this job. You need to use EnumDisplayMonitors which gives you the monitor coordinates directly.
You need to retreive the bounding rectangle for the desired monitor within the virtual screen, and then you can position a window within that rectangle as desired. Use EnumDisplayMonitors() to get the rectangle of each moinitor. Or, if you have an HMONITOR handle to a specific monitor, you can use GetMonitorInfo().
On Windows, I'm trying to use CEF (Chromium Embedded Framework) to create a window application with parent window to be transparent and its child window to be opaque (I want to have a rounded corner and an arrow pointing to the status bar in the child window). Something similar to:
I tried to use SetLayeredWindowAttributes to make the parent window transparent but it also makes the child window transparent. Is there a way to make this happen on Windows?
SetLayeredWindowAttributes needs a color for transparency. Make sure the transparency color is not used by the child window. You can pick a random color, for example RGB(255, 0, 254) and assume the child window is not using it.
If you have no control over the child window, and you can't be sure what colors it might use, then SetWindowRgn is another option to create non-rectangular windows.
The example below shows how to set the region such that the corners are round with a triangle on top.
You can use GDI+ to gain more flexibility for drawing the region, and for anti-aliasing effect so that the borders look more smooth.
#include <Windows.h>
int triangle_height = 30;
int corner_size = 20;
int caption_height = 60;
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
switch(msg)
{
case WM_CREATE:
{
//create a child button for testing
CreateWindowW(L"BUTTON", L"Close", WS_CHILD | WS_VISIBLE,
10, caption_height + 10, 100, 30,
hwnd, HMENU(100), GetModuleHandle(NULL), NULL);
RECT rc;
GetClientRect(hwnd, &rc);
//create a triangle region
int w = rc.right;
int h = rc.bottom;
int z = triangle_height;
POINT pt[3];
pt[0] = { w / 2, 0 };
pt[1] = { w / 2 - z, z };
pt[2] = { w / 2 + z, z };
HRGN htri = CreatePolygonRgn(pt, 3, WINDING);
//create a round rectangle region
HRGN hrgn = CreateRoundRectRgn(0, z, w, h - z, corner_size, corner_size);
//combine the triangle with round rectangle
CombineRgn(hrgn, htri, hrgn, RGN_OR);
//set the new region
SetWindowRgn(hwnd, hrgn, TRUE);
DeleteObject(htri);
DeleteObject(hrgn);
return 0;
}
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
RECT rc = ps.rcPaint;
//we don't have a standard title bar, paint one here:
rc.bottom = caption_height;
SetDCBrushColor(hdc, RGB(80, 80, 80));
FillRect(hdc, &rc, (HBRUSH)GetStockObject(DC_BRUSH));
//paint the background
rc = ps.rcPaint;
rc.top = caption_height;
SetDCBrushColor(hdc, RGB(240, 240, 240));
FillRect(hdc, &rc, (HBRUSH)GetStockObject(DC_BRUSH));
//use FrameRgn to paint a border around the region
HRGN hrgn = CreateRectRgn(0, 0, 0, 0);
GetWindowRgn(hwnd, hrgn);
SetDCBrushColor(hdc, RGB(128, 128, 128));
FrameRgn(hdc, hrgn, (HBRUSH)GetStockObject(DC_BRUSH), 1, 1);
DeleteObject(hrgn);
EndPaint(hwnd, &ps);
return 0;
}
case WM_NCHITTEST:
{
//we don't have a standard title-bar
//respond to our custome title-bar manually:
POINT pt;
GetCursorPos(&pt);
ScreenToClient(hwnd, &pt);
if(pt.y < caption_height)
return HTCAPTION;
break;
}
case WM_COMMAND:
if(HIWORD(wparam) == BN_CLICKED)
if(LOWORD(wparam) == 100)
SendMessage(hwnd, WM_CLOSE, 0, 0);
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, msg, wparam, lparam);
}
int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE, LPTSTR, int)
{
WNDCLASSEXW wcex = { sizeof(wcex) };
wcex.style = CS_DROPSHADOW;
wcex.lpfnWndProc = WndProc;
wcex.hInstance = hInstance;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = NULL;
wcex.lpszClassName = L"classname";
RegisterClassExW(&wcex);
CreateWindowW(wcex.lpszClassName, L"Test", WS_VISIBLE | WS_POPUP,
200, 200, 600, 400, 0, 0, hInstance, 0);
MSG msg;
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
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.
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: