First of all, this question can be a duplicate but the question doesnt have enough information to solve the problem.
I have two windows in my native Win32 application. The first is a layered window with WS_EX_NOACTIVATE extended style and the second is a normal window. I want the layered one to be non-activatable. The problem is that, when I have two window in the same application, the layered one which must be non-activatable, gets activated when switching between them. But there is no problem when switching between two external windows, one being not belong to my application. How can I solve this problem? Or Can I solve that? Is there anything I missed? The following is a minimal reproducable example (didn't include any error checking for minimality.) Thank you for taking time.
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <windowsx.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
void init_device_resources(int cx, int cy, void** rgb);
void update_content();
void set_window_size(int width, int height);
HWND layeredhWnd;
HWND otherhWnd;
WNDCLASSEX wc;
MSG msg;
HDC hdcDesktop;
HDC hdcContent;
POINT dstPoint = { 100, 100 };
SIZE windowSize = { 800, 600 };
BLENDFUNCTION bf;
BITMAPINFO bi;
BYTE* rgb_data = NULL;
HBITMAP hBitmap;
HBITMAP hOldBitmap;
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
ZeroMemory(&wc, sizeof(WNDCLASSEX));
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.lpszClassName = L"LayeredWindowClass";
RegisterClassEx(&wc);
wc.lpszClassName = L"OtherWindowClass";
RegisterClassEx(&wc);
layeredhWnd = CreateWindowEx(WS_EX_LAYERED | WS_EX_NOACTIVATE,
L"LayeredWindowClass",
L"",
WS_POPUP | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_THICKFRAME,
0, 0,
800, 600,
NULL,
NULL,
hInstance,
NULL);
otherhWnd = CreateWindowEx(NULL,
L"OtherWindowClass",
L"",
WS_OVERLAPPEDWINDOW,
0, 0,
800, 600,
NULL,
NULL,
hInstance,
NULL);
init_device_resources(800, 600, &rgb_data);
set_window_size(800, 600);
ShowWindow(layeredhWnd, nCmdShow);
ShowWindow(otherhWnd, nCmdShow);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CLOSE:
{
DestroyWindow(hWnd);
break;
}
case WM_DESTROY:
{
PostQuitMessage(0);
break;
}
case WM_ACTIVATE:
{
if(hWnd == layeredhWnd)
update_content();
break;
}
case WM_PAINT:
{
if (hWnd == layeredhWnd)
update_content();
break;
}
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
void init_device_resources(int cx, int cy, void** rgb)
{
hdcDesktop = GetDC(NULL);
hdcContent = CreateCompatibleDC(hdcDesktop);
bf.BlendOp = AC_SRC_OVER;
bf.BlendFlags = 0;
bf.SourceConstantAlpha = 255;
bf.AlphaFormat = AC_SRC_ALPHA;
bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bi.bmiHeader.biWidth = cx;
bi.bmiHeader.biHeight = -cy;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biBitCount = 32;
bi.bmiHeader.biCompression = BI_RGB;
bi.bmiHeader.biSizeImage = cx * cy * 4;
bi.bmiHeader.biXPelsPerMeter = 0;
bi.bmiHeader.biYPelsPerMeter = 0;
bi.bmiHeader.biClrUsed = 0;
bi.bmiHeader.biClrImportant = 0;
bi.bmiColors[0] = (RGBQUAD){ 0 };
hBitmap = CreateDIBSection(hdcContent, &bi, DIB_RGB_COLORS, rgb, NULL, 0);
for (int i = 0; i < cx * cy * 4; i++)
{
rgb_data[i] = 255;
}
hOldBitmap = SelectObject(hdcContent, hBitmap);
}
void update_content()
{
UpdateLayeredWindow(layeredhWnd, hdcDesktop, &dstPoint,
&windowSize, hdcContent, &(POINT){ 0, 0 }, RGB(0, 0, 0), & bf, ULW_ALPHA);
}
void set_window_size(int width, int height)
{
SetWindowPos(layeredhWnd, NULL, 0, 0, width, height, SWP_NOMOVE);
windowSize = (SIZE){ width, height };
}
Although I still don't understand the cause of the problem, with the help of #IInspectable's guidance and documentation, I was able to prevent the window from being activated by processing the WM_MOUSEACTIVATE message. The updated window procedure is as follows.
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CLOSE:
{
DestroyWindow(hWnd);
break;
}
case WM_DESTROY:
{
PostQuitMessage(0);
break;
}
case WM_MOUSEACTIVATE:
{
if (hWnd == layeredhWnd)
return MA_NOACTIVATE;
break;
}
case WM_ACTIVATE:
{
if(hWnd == layeredhWnd)
update_content();
break;
}
case WM_PAINT:
{
if (hWnd == layeredhWnd)
update_content();
break;
}
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
Related
I am writing some code to get acquainted with the windows API. I was able to get a window to open but when I tried to write a program to draw random pixels. I am using GCC with Vscode. here is the code:
#include <windows.h>
#include <time.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void DrawPixels(HWND hwnd);
int WINAPI
WinMain (HINSTANCE hInstance, HINSTANCE hPrevInst, LPTSTR lpCmdLine, int nShowCmd) {
MSG msg;
WNDCLASSW wc = {0};
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpszClassName = L"Pixels";
wc.hInstance = hInstance;
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
wc.lpfnWndProc = WndProc;
wc.hCursor = LoadCursor(0, IDC_ARROW);
RegisterClassW(&wc);
CreateWindowW(wc.lpszClassName, L"Pixels",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
100, 100, 300, 250, NULL, NULL, hInstance, NULL);
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
srand(time(NULL));
return (int) msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam) {
switch(msg) {
case WM_PAINT:
DrawPixels(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProcW(hwnd, msg, wParam, lParam);
}
void DrawPixels(HWND hwnd) {
PAINTSTRUCT ps;
RECT r;
GetClientRect(hwnd, &r);
if (r.bottom == 0) {
return;
}
HDC hdc = BeginPaint(hwnd, &ps);
for (int i=0; i<1000; i++) {
int x = rand() % r.right;
int y = rand() % r.bottom;
SetPixel(hdc, x, y, RGB(255, 0, 0));
}
EndPaint(hwnd, &ps);
}
Whenever I try to compile this I get the error main.o:main.cpp:(.text+0x224): undefined reference to `SetPixel#16'
I have tried changing the variables and the types but it isnt working.
I'm trying to learn how to subclass a GUI control and 'modify' its hdc.
This is my subclass callback:
mygui.h
#include <commctrl.h> // SetWindowSubclass
#pragma comment(lib, "Comctl32.lib")
#include <windows.h> // GDI includes.
#include <objidl.h>
#include <gdiplus.h>
using namespace Gdiplus;
using namespace DllExports;
#pragma comment (lib,"Gdiplus.lib")
typedef UCHAR GuiControls;
enum GuiControlTypes {
GUI_CONTROL_BUTTON
};
struct GuiControlOptionsType
{
int x;
int y;
int width;
int height;
LPCWSTR text;
GuiControlTypes controltype;
bool ERASEDBKGND = false; // Used on the subclass proc.
HDC dc;
};
class Gui
{
public:
std::map<HWND, GuiControlOptionsType> control_list;
HWND GuihWnd;
HWND A_LasthWnd;
LRESULT Create();
LRESULT AddControl(GuiControls aControlType, GuiControlOptionsType opt);
};
LRESULT CALLBACK ButtonProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);
mygui.cpp
/* Window Procedure. */
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
// TODO
return DefWindowProc(hWnd, msg, wParam, lParam);
}
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLine, int nCmdShow)
{
Gui mygui;
mygui.Create();
}
LRESULT Gui::Create()
{
WNDCLASSEX wc{};
MSG Msg;
HWND hWnd = nullptr;
wc.cbSize = sizeof(WNDCLASSEX); wc.style = 0; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0;
wc.hInstance = 0; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wc.lpszMenuName = NULL;
wc.lpszClassName = L"classname";
if (!RegisterClassEx(&wc))
// TODO
this->GuihWnd = CreateWindowW(
wc.lpszClassName,
L"Title",
WS_EX_COMPOSITED | WS_EX_LAYERED | // Double buffering
WS_OVERLAPPED | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU,
CW_USEDEFAULT, CW_USEDEFAULT, 500, 200,
nullptr, nullptr, nullptr, nullptr);
DWORD err = GetLastError();
if (this->GuihWnd == NULL)
// TODO
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
GuiControlOptionsType opt;
opt.x = 10; opt.y = 10; opt.width = 100; opt.height = 100; opt.text = L"test";
this->AddControl(GUI_CONTROL_BUTTON, opt);
SetWindowSubclass(this->A_LasthWnd, ButtonProc, 1, (DWORD_PTR)this);
ShowWindow(this->GuihWnd, SW_SHOW);
UpdateWindow(this->GuihWnd);
while (GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return 0; // Msg.wParam;
}
LRESULT Gui::AddControl(GuiControls aControlType, GuiControlOptionsType opt)
{
switch (aControlType)
{
case GUI_CONTROL_BUTTON:
{
HWND hWnd = CreateWindow(
L"BUTTON", // Predefined class; Unicode assumed
opt.text, // Button text
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, // Styles
opt.x, // x position
opt.y, // y position
opt.width, // Button width
opt.height, // Button height
this->GuihWnd, // Parent window
NULL, // No menu.
NULL, //(HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE),
NULL); // Pointer not needed.
opt.controltype = GUI_CONTROL_BUTTON;
this->control_list.emplace(hWnd, opt);
this->A_LasthWnd = hWnd;
}
break;
default:
break;
}
return 1;
}
LRESULT CALLBACK ButtonProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
Gui* pThis = (Gui*)dwRefData;
switch (uMsg)
{
case WM_ERASEBKGND:
{
if (pThis->control_list[hWnd].ERASEDBKGND)
return 1;
// Create/save the new button dc.
GpBitmap* pBitmap;
GdipCreateBitmapFromScan0(pThis->control_list[hWnd].width, pThis->control_list[hWnd].height, 0, PixelFormat32bppPARGB, 0, &pBitmap);
GpGraphics* g;
GdipGetImageGraphicsContext(pBitmap, &g);
GdipGraphicsClear(g, 0xFF2400ff);
HBITMAP hbm;
GdipCreateHBITMAPFromBitmap(pBitmap, &hbm, 0);
HDC dc = CreateCompatibleDC(NULL);
SelectObject(dc, hbm);
pThis->control_list[hWnd].dc = dc;
GdipDisposeImage(pBitmap);
GdipDeleteGraphics(g);
DeleteObject(hbm);
pThis->control_list[hWnd].ERASEDBKGND = 1;
}
break;
case WM_LBUTTONDBLCLK:
case WM_LBUTTONDOWN:
{
InvalidateRect(hWnd, 0, 1);
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
BLENDFUNCTION bf;
bf.SourceConstantAlpha = 255;
bf.BlendOp = AC_SRC_OVER;
bf.BlendFlags = 0;
bf.AlphaFormat = AC_SRC_ALPHA;
GdiAlphaBlend(hdc, 0, 0, pThis->control_list[hWnd].width, pThis->control_list[hWnd].height,
pThis->control_list[hWnd].dc, 0, 0, pThis->control_list[hWnd].width, pThis->control_list[hWnd].height, bf);
EndPaint(hWnd, &ps);
DeleteObject(hdc);
return TRUE;
}
break;
}
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
The problem is... when I click on the button it restores its default hdc, when I minimize/restore it draws with my 'custom' hdc.
I tried adding a call to InvalidateRect() under WM_LBUTTONDOWN, but it resulted in the same thing.
I also tried creating the Gui with 'double buffering' adding the styles WS_EX_COMPOSITED | WS_EX_LAYERED.
What am I missing?
BS_OWNERDRAW should be "her" style, I think.
Having a window with gif and some elements c++ winapi(Non-MFC) using gdi+. SO I want to make transparent elements(Edit,Static,Button). I want to make transparent gray background of elements.
I have tried to handle WM_CTLCOLORSTATIC and adding style WS_EX_TRANSPARENT and m. but it didn't give correct result. But when I handle WM_CTLCOLORSTATIC with code:
hdcStatic = (HDC) wParam;
SetTextColor(hdcStatic, RGB(0,0,0));
SetBkMode (hdcStatic, TRANSPARENT);
return (LRESULT)GetStockObject(NULL_BRUSH);
And it showed STATIC styles transparent, but I could see background of Windows 10.
Minimum code is:
#include <memory>
#include "Resource.h"
#include <vector>
#include "TESTING.h"
#include "framework.h"
#include <algorithm>
#include <windows.h>
#include <objidl.h>
#include <GdiPlus.h>
#include <gdiplusimaging.h>
#include <shlwapi.h>
#include<CommCtrl.h>
using namespace Gdiplus;
#pragma comment (lib,"Gdiplus.lib")
#pragma comment (lib,"shlwapi.lib")
#pragma comment (lib,"Comctl32.lib")
#define TIMER_ID 101
static HFONT s_hFont = NULL;
static HWND hWnd;
static HWND hwndText;
static HWND hwndButton;
static HWND hwndLabel;
static HWND hwndCode;
static HWND hwndCode2;
static HWND hwndTime;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK SubWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, UINT_PTR, DWORD_PTR);
int WINAPI _WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
ULONG_PTR m_gdiplusToken;
GdiplusStartupInput gdiplusStartupInput;
GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);
HMODULE hMod = GetModuleHandle(NULL);
HRSRC hRes = FindResource(hMod, MAKEINTRESOURCEW(MY_GIF_ID), RT_RCDATA);
if (!hRes) MessageBox(NULL, L"hRes!!", L"ERROR", 0);
HGLOBAL hGlobal = LoadResource(hMod, hRes);
if (!hGlobal)MessageBox(NULL, L"hGlobal!!", L"ERROR", 0);
void* pResData = LockResource(hGlobal);
if (!pResData) MessageBox(NULL, L"pResData!!", L"ERROR", 0);
DWORD dwResData = SizeofResource(hMod, hRes);
IStream* pStream = SHCreateMemStream((BYTE*)pResData, dwResData);
if (!pStream) MessageBox(NULL, L"pStream!!", L"ERROR", 0);
Image gif(pStream);
pStream->Release();
MSG msg = { 0 };
WNDCLASS wc = { 0 };
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance;
wc.hbrBackground = NULL; // <= Do not provide a background brush.
wc.lpszClassName = L"anim_gif_player";
if (!RegisterClass(&wc))
return -1;
hWnd = CreateWindow(wc.lpszClassName,
L"",
WS_EX_TOPMOST | WS_CLIPCHILDREN & ~WS_CAPTION & ~WS_SYSMENU,
0, 0, 640, 480, 0, 0, hInstance, &gif);
if (!hWnd) {
MessageBox(0, L"SSSSSSSSSSSSSSSSSSS", L"kkkkkkkkkkkkkkkkkkkkkk", 0);
return -2;
}
hwndLabel = CreateWindowEx(WS_EX_TRANSPARENT,L"STATIC",
NULL,
WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_CLIPSIBLINGS,
325, 90, 440, 45,
hWnd,
NULL,
NULL,
NULL);
SetWindowSubclass(hwndLabel, SubWndProc, 0, 0);
const TCHAR* fontName = TEXT("Croobie");
const long nFontSize = 24;
HDC hdc = GetDC(hwndLabel);
LOGFONT logFont = { 0 };
logFont.lfHeight = -MulDiv(nFontSize, GetDeviceCaps(hdc, LOGPIXELSY), 72);
logFont.lfWeight = FW_BOLD;
wcscpy_s(logFont.lfFaceName, fontName);
s_hFont = CreateFontIndirect(&logFont);
SendMessage(hwndLabel, WM_SETFONT, (WPARAM)s_hFont, (LPARAM)MAKELONG(TRUE, 0));
ShowWindow(hWnd, SW_SHOWMAXIMIZED);
UpdateWindow(hWnd);
while (GetMessage(&msg, NULL, 0, 0) > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
//DeleteObject(wc.hbrBackground);
return msg.wParam;
}
std::vector<unsigned int> LoadGifFrameInfo(Image* image)
{
// I think animated gifs will always only have 1 frame dimension...
// the "dimension" being the frame count, but I could be wrong about this
int count = image->GetFrameDimensionsCount();
if (count != 1)
return std::vector<unsigned int>();
GUID guid;
if (image->GetFrameDimensionsList(&guid, 1) != 0)
return std::vector<unsigned int>();
int frame_count = image->GetFrameCount(&guid);
auto sz = image->GetPropertyItemSize(PropertyTagFrameDelay);
if (sz == 0)
return std::vector<unsigned int>();
// copy the frame delay property into the buffer backing an std::vector
// of bytes and then get a pointer to its value, which will be an array of
// unsigned ints
std::vector<unsigned char> buffer(sz);
PropertyItem* property_item = reinterpret_cast<PropertyItem*>(&buffer[0]);
image->GetPropertyItem(PropertyTagFrameDelay, sz, property_item);
unsigned int* frame_delay_array = (unsigned int*)property_item[0].value;
// copy the delay values into an std::vector while converting to milliseconds.
std::vector<unsigned int> frame_delays(frame_count);
std::transform(frame_delay_array, frame_delay_array + frame_count, frame_delays.begin(),
[](unsigned int n) {return n * 10; }
);
return frame_delays;
}
void GenerateFrame(Bitmap* bmp, Image* gif)
{
Graphics dest(bmp);
SolidBrush white(Color::White);
dest.FillRectangle(&white, 0, 0, bmp->GetWidth(), bmp->GetHeight());
if (gif)
dest.DrawImage(gif, 0, 0);
}
std::unique_ptr<Bitmap> CreateBackBuffer(HWND hWnd)
{
RECT r;
GetClientRect(hWnd, &r);
return std::make_unique<Bitmap>(r.right - r.left, r.bottom - r.top);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static Image* animated_gif;
static std::unique_ptr<Bitmap> back_buffer;
static std::vector<unsigned int> frame_delays;
static int current_frame;
switch (message) {
case WM_CREATE: {
animated_gif = reinterpret_cast<Image*>(
reinterpret_cast<CREATESTRUCT*>(lParam)->lpCreateParams
);
if (!animated_gif || animated_gif->GetLastStatus() != 0) {
MessageBox(hWnd, L"Unable to load animated gif", L"error", MB_ICONERROR);
return 0;
}
// Create a bitmap the size of the window's clent area
back_buffer = CreateBackBuffer(hWnd);
// get the frame delays and thereby test that this is really an animated gif
frame_delays = LoadGifFrameInfo(animated_gif);
if (frame_delays.empty()) {
MessageBox(hWnd, L"Invalid gif or not an animated gif", L"error", MB_ICONERROR);
return 0;
}
current_frame = 0;
animated_gif->SelectActiveFrame(&FrameDimensionTime, current_frame);
GenerateFrame(back_buffer.get(), animated_gif);
SetTimer(hWnd, TIMER_ID, frame_delays[0], nullptr);
InvalidateRect(hWnd, nullptr, FALSE);
}
break;
case WM_TIMER: {
KillTimer(hWnd, TIMER_ID);
current_frame = (current_frame + 1) % frame_delays.size();
animated_gif->SelectActiveFrame(&FrameDimensionTime, current_frame);
GenerateFrame(back_buffer.get(), animated_gif);
SetTimer(hWnd, TIMER_ID, frame_delays[current_frame], nullptr);
InvalidateRect(hWnd, nullptr, FALSE);
} break;
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
Graphics g(hdc);
g.DrawImage(back_buffer.get(), 0, 0);
EndPaint(hWnd, &ps);
} break;
case WM_SIZE: {
back_buffer = CreateBackBuffer(hWnd);
GenerateFrame(back_buffer.get(), animated_gif);
} break;
case WM_CLOSE:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
LRESULT CALLBACK SubWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, UINT_PTR, DWORD_PTR) {
switch (msg) {
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
RECT rc; GetClientRect(hwnd, &rc);
SetTextColor(hdc, Color::Yellow);
SetBkMode(hdc, TRANSPARENT);
wchar_t buf[256] = { 0 };
GetWindowTextW(hwnd, buf, sizeof(buf) / sizeof(*buf));
DrawTextW(hdc, buf, wcslen(buf), &rc, DT_LEFT | DT_TOP);
EndPaint(hwnd, &ps);
return 0;
}
case WM_NCDESTROY://safely remove subclass
RemoveWindowSubclass(hwnd, SubWndProc, 0);
return DefSubclassProc(hwnd, msg, wParam, lParam);
}
return DefSubclassProc(hwnd, msg, wParam, lParam);
}
The WS_EX_TRANSPARENT style doesn’t mean “transparent”; it means
“paint over siblings.”
The style is called “transparent” not because it makes the window
transparent but because it makes transparency possible.
Please refer: Why isn't my transparent static control transparent?
The only way I've found to do this reliably is to sub-class the static control and paint the background manually.
You can catch the WM_ERASEBKGND message and paint the appropriate portion of the underlying bitmap.
Please refer:
Is it possible to make a Static control transparent?
C++ Win32 Static Control Transparent Background
Also, if you want remove grey background, you can change static control background and make it transparent.
Demon of custom static control:
#include "stdafx.h"
#include "Test_WM_CTLCOLORSTATIC.h"
#define MAX_LOADSTRING 100
// Global Variables:
HINSTANCE hInst; // current instance
WCHAR szTitle[MAX_LOADSTRING]; // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
HWND hWndStatic;
// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK WndProcPanel(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here.
// Initialize global strings
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_TESTWMCTLCOLORSTATIC, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_TESTWMCTLCOLORSTATIC));
MSG msg;
// Main message loop:
while (GetMessage(&msg, nullptr, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_TESTWMCTLCOLORSTATIC));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_TESTWMCTLCOLORSTATIC);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassExW(&wcex);
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
//
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
WNDPROC StaticWndProc = NULL;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
{ LRESULT lRes = DefWindowProc(hWnd, message, wParam, lParam);
hWndStatic = CreateWindowEx(0, L"Static", NULL, WS_CHILD | WS_VISIBLE | SS_LEFT, 10, 130, 200, 40, hWnd, NULL, hInst, NULL); //v2 deleted HWND
StaticWndProc = (WNDPROC)SetWindowLong(hWndStatic, GWL_WNDPROC, (LPARAM)WndProcPanel);
return lRes;
}
break;
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_ERASEBKGND:
{
HBRUSH brush;
RECT rect;
brush = CreateSolidBrush(RGB(0, 255, 0));
SelectObject((HDC)wParam, brush);
GetClientRect(hWnd, &rect);
Rectangle((HDC)wParam, rect.left, rect.top, rect.right, rect.bottom);
}
break;
case WM_DESTROY:
SetWindowLong(hWndStatic, GWL_WNDPROC, (LPARAM)StaticWndProc);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
TCHAR szText[] = _T("TestString");;
LRESULT CALLBACK WndProcPanel(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (message == WM_PAINT)
{
RECT rc;
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
GetClientRect(hWnd, &rc);
SetBkMode(hdc, TRANSPARENT);
DrawText(hdc, szText, _tcslen(szText), &rc, DT_CENTER | DT_VCENTER);
EndPaint(hWnd, &ps);
return 0;
}
return CallWindowProc(StaticWndProc, hWnd, message, wParam, lParam);
}
thx #IInspectable's remind, the best way to subclass controls is to use SetWindowsSubclass, see Subclassing Controls
I'll update the new code later, and I'm sorry for my shallow knowledge.
Updated:
case WM_TIMER: {
KillTimer(hWnd, TIMER_ID);
current_frame = (current_frame + 1) % frame_delays.size();
animated_gif->SelectActiveFrame(&FrameDimensionTime, current_frame);
GenerateFrame(back_buffer.get(), animated_gif);
SetTimer(hWnd, TIMER_ID, frame_delays[current_frame], nullptr);
InvalidateRect(hWnd, nullptr, FALSE);
InvalidateRect(hwndLabel, nullptr, FALSE); //Here add new code
}
Debug Result:
I was actually following a tutorial. I really want to get an answer because I will need to add icons to the window down the line. Getting images to show in the window would be the first step.
Sorry for some reason the update I added did not go through before. My solution is geared towards Unicode.
The corrected updated file is below :
#include <windows.h>
#include <commctrl.h>
using namespace std;
LPCWSTR szClassName = L"myWindowClass";
HWND hLogo;
HBITMAP hLogoImage;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void loadPictures();
void parentControls(HWND);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int icmdshow)
{
HWND hWnd;
WNDCLASSW wc = { 0 };
wc.style = 0;
wc.lpszMenuName = NULL;
wc.lpszClassName = szClassName;
wc.lpfnWndProc = WndProc;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.hInstance = hInstance;
wc.hIcon = LoadIconW(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursorW(NULL, IDC_ARROW);
wc.cbWndExtra = 0;
wc.cbClsExtra = 0;
if (!RegisterClassW(&wc))
{
const wchar_t Error01[] = L"Register Issue To Check On : "; /// Notice this
const wchar_t Error01_Caption[] = L"Error 01";
MessageBoxW(NULL, Error01, Error01_Caption, MB_OK | MB_ICONERROR);
return 0;
}
LPCWSTR parentWinTitle = L"My Window";
hWnd = CreateWindowW(szClassName, parentWinTitle, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 250, 200, NULL, NULL, NULL, NULL);
if (hWnd == NULL)
{
const wchar_t Error02[] = L"Window Creation Issue To Check On : ";
const wchar_t Error02_Caption[] = L"Window Creation Issue To Check On : ";
MessageBoxW(NULL, Error02, Error02_Caption, MB_OK | MB_ICONERROR);
}
ShowWindow(hWnd, icmdshow);
UpdateWindow(hWnd);
MSG msg = { 0 };
while (GetMessageW(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
return 0;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
loadPictures(); /// Must be called first, Calling the Images function in Create
parentControls(hWnd);
break;
/* case WM_COMMAND:
switch (wParam)
{
}
break;
*/
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProcW(hWnd, message, wParam, lParam);
}
return 0;
}
void parentControls(HWND hWnd)
{
hLogo = CreateWindowW(WC_STATICW, NULL, WS_VISIBLE | WS_CHILD | SS_BITMAP, 70, 25, 100, 100, hWnd, NULL, NULL, NULL);
SendMessageW(hLogo, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hLogoImage);
}
void loadPictures()
{ /// bmp image save in file with main.cpp
LPCWSTR myBmp = L"bitmap1.bmp";
hLogoImage = (HBITMAP)LoadImageW(NULL, myBmp, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
}
case WM_COMMAND:
switch(wp)
{
}
break;
parentControls(hWnd); <--- never gets here
loadPictures(); /// Calling the Images function in Create
break;
parentControls and loadPictures are never reached in this switch statement.
loadPictures should be called first.
Remove the two lines, put them in WM_CREATE as follows:
case WM_CREATE:
loadPictures(); /// Calling the Images function in Create
parentControls(hWnd);
break;
Someone told me the answer should be here instead of updated above. I am sure I will be made aware that it is wrong if I add it here. I figure that is why the updates didn't take when I tried them before in the original post above. Either way the update/Answer is below.
#include <windows.h>
#include <commctrl.h>
using namespace std;
LPCWSTR szClassName = L"myWindowClass";
HWND hLogo;
HBITMAP hLogoImage;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void loadPictures();
void parentControls(HWND);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int icmdshow)
{
HWND hWnd;
WNDCLASSW wc = { 0 };
wc.style = 0;
wc.lpszMenuName = NULL;
wc.lpszClassName = szClassName;
wc.lpfnWndProc = WndProc;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.hInstance = hInstance;
wc.hIcon = LoadIconW(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursorW(NULL, IDC_ARROW);
wc.cbWndExtra = 0;
wc.cbClsExtra = 0;
if (!RegisterClassW(&wc))
{
const wchar_t Error01[] = L"Register Issue To Check On : "; /// Notice this
const wchar_t Error01_Caption[] = L"Error 01";
MessageBoxW(NULL, Error01, Error01_Caption, MB_OK | MB_ICONERROR);
return 0;
}
LPCWSTR parentWinTitle = L"My Window";
hWnd = CreateWindowW(szClassName, parentWinTitle, WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 250, 200, NULL, NULL, NULL, NULL);
if (hWnd == NULL)
{
const wchar_t Error02[] = L"Window Creation Issue To Check On : ";
const wchar_t Error02_Caption[] = L"Window Creation Issue To Check On : ";
MessageBoxW(0, Error02, Error02_Caption, MB_OK | MB_ICONERROR);
}
ShowWindow(hWnd, icmdshow);
UpdateWindow(hWnd);
MSG msg = { 0 };
while (GetMessageW(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
return 0;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
loadPictures(); /// Must be called first, Calling the Images function in Create
parentControls(hWnd);
break;
/* case WM_COMMAND:
switch (wParam)
{
}
break;
*/
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProcW(hWnd, message, wParam, lParam);
}
return 0;
}
void parentControls(HWND hWnd)
{
hLogo = CreateWindowW(WC_STATICW, NULL, WS_VISIBLE | WS_CHILD | SS_BITMAP, 70, 25, 100, 100, hWnd, NULL, NULL, NULL);
SendMessageW(hLogo, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hLogoImage);
}
void loadPictures()
{ /// bmp image save in file with main.cpp
LPCWSTR myBmp = L"bitmap1.bmp";
hLogoImage = (HBITMAP)LoadImageW(NULL, myBmp, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
}
I've made two simple classes to use for displaying UIs with Awesomium. However creating the Awesomium WebView and setting the parent window to my Win32 window causes the program to hang and the page is never displayed. The classes are simple and creating a window is simple so there isn't much I can think of that could be going wrong. Perhaps there is something else required than what I've done to display a WebView?
To clarify: Creating the Win32 window without creating the WebView works fine, the window functions including the drag code etc... The hang only happens when you call set_parent_window.
UI.h
#pragma once
#include <Windows.h>
#include <windowsx.h>
#include <Awesomium/WebCore.h>
#include <Awesomium/STLHelpers.h>
using namespace Awesomium;
LRESULT CALLBACK LoginUICallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
class UI
{
public:
//Window Variables
HINSTANCE instance;
HWND window;
BOOL drag_window = false;
SHORT mouse_x, mouse_y, mouse_x_prev, mouse_y_prev;
//Awesomium Variables
WebCore* webcore = 0;
WebView* webview;
static HWND InitWindow(INT width, INT height, WNDPROC callback)
{
HWND hwnd;
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = callback;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = GetModuleHandle(0);
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = "MyUI";
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if (!RegisterClassEx(&wc))
{
char msg[100];
sprintf(msg, "System Error: %i", GetLastError());
MessageBox(NULL, msg, "ERROR", MB_OK);
return NULL;
}
hwnd = CreateWindow("MyUI",
"",
WS_POPUP,
CW_USEDEFAULT,
CW_USEDEFAULT,
width,
height,
NULL,
NULL,
GetModuleHandle(0),
NULL);
if (!hwnd)
{
char msg[100];
sprintf(msg, "System Error: %i", GetLastError());
MessageBox(NULL, msg, "ERROR", MB_OK);
return NULL;
}
ShowWindow(hwnd, SW_SHOWNORMAL);
UpdateWindow(hwnd);
SetTimer(hwnd, 0, 15, NULL);
return hwnd;
}
};
class LoginUI : public UI
{
public:
INT width = 600;
INT height = 600;
INT RunUI()
{
this->window = UI::InitWindow(this->width, this->height, ::LoginUICallback);
if (!this->window)
return 0;
WebConfig config;
this->webcore = WebCore::Initialize(config);
this->webview = this->webcore->instance()->CreateWebView(this->width, this->height, 0, kWebViewType_Window);
this->webview->set_parent_window(this->window);
this->webview->LoadURL(WebURL(WSLit("http://www.google.com")));
MSG msg;
while(GetMessage(&msg, this->window, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
WebCore::Shutdown();
return 1;
}
}login_ui;
LRESULT CALLBACK LoginUICallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_COMMAND:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
case WM_TIMER:
break;
case WM_MOUSEMOVE:
{
if (login_ui.drag_window && (wParam & MK_LBUTTON))
{
// code executed when the dialog window is moved around on the screen
RECT win_rect;
GetWindowRect(hWnd, &win_rect);
int x_coord = GET_X_LPARAM(lParam);
int y_coord = GET_Y_LPARAM(lParam);
MoveWindow(hWnd,
win_rect.left + x_coord - login_ui.mouse_x_prev,
win_rect.top + y_coord - login_ui.mouse_y_prev,
win_rect.right - win_rect.left,
win_rect.bottom - win_rect.top,
false
);
}
break;
}
case WM_LBUTTONDOWN:
{
login_ui.mouse_x = GET_X_LPARAM(lParam);
login_ui.mouse_y = GET_Y_LPARAM(lParam);
if (login_ui.mouse_y < 41)
{
login_ui.mouse_x_prev = login_ui.mouse_x;
login_ui.mouse_y_prev = login_ui.mouse_y;
SetCapture(hWnd);
login_ui.drag_window = true;
}
break;
}
case WM_LBUTTONUP:
{
if (login_ui.drag_window)
{
login_ui.drag_window = false;
ReleaseCapture();
}
break;
}
case WM_SIZE:
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_QUIT:
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
Main.Cpp
#include "UI.h"
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE, char*, int nCmdShow)
{
login_ui.RunUI();
}
Have not used Awesomium but your GetMessage only pumps messages for the WebCore window. So instead you should pass NULL so your message pump dispatches messages for all windows created on that thread.