WM_HOVER not working with WinAPI ListView - c++

I have a ListView drawing to the screen. Now, I am trying to have a function called when the user hovers over the items. I am trying to use WM_HOVER right now because it seems the most straight foward; however, it doesn't seem to be working. I got WM_CLICK to work fine, but not for the hovering.
Will WM_HOVER do what I need it to, or should I be looking into something else such as TrackMouseEvent()?
Here is some example code. Really the only pertinent part, I believe, are the lines in the WndProc() following case WM_HOVER:
//libraries
#pragma comment ("lib", "Comctl32.lib")
#pragma comment ("lib", "d2d1.lib")
#include "targetver.h"
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files
#include <windows.h>
// C RunTime Header Files
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>
#include <vector>
#include <string>
#include <dwrite.h>
#include <d2d1.h>
#include <commctrl.h>
#include <strsafe.h>
#define IDS_APP_TITLE 103
#define IDR_MAINFRAME 128
#define IDD_PRACTICE_DIALOG 102
#define IDD_ABOUTBOX 103
#define IDM_EXIT 105
#define IDI_PRACTICE 107
#define IDI_SMALL 108
#define IDC_PRACTICE 109
#define IDC_MYICON 2
#ifndef IDC_STATIC
#define IDC_STATIC -1
#endif
#define MAX_LOADSTRING 100
#define PROJECT_LIST_VIEW 110
BOOL mouseTracking = false;
// Global Variables:
HINSTANCE hInst; // current instance
WCHAR szTitle[MAX_LOADSTRING]; // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
std::vector<std::string> stringsVector = { "String1", "String2", "String3" };
//D2D1 pointers
ID2D1Factory* m_pD2DFactory;
ID2D1DCRenderTarget* m_pRenderTarget;
ID2D1SolidColorBrush* m_pBlackBrush;
//dimension variables
int w, h;
RECT rc;
HWND listViewHandle;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow);
HRESULT CreateDeviceResources(HWND hwnd, HDC hdc);
bool onRender(HWND hwnd, PAINTSTRUCT* ps);
///////////////////
//Function to insert the items into the list view
//////////////////
BOOL InsertListViewItems(HWND hWndListView, int cItems);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// Initialize global strings
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_PRACTICE, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
// Perform application initialization:
if (!InitInstance(hInstance, nCmdShow))
{
return FALSE;
}
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_PRACTICE));
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;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
switch (message)
{
case WM_CREATE:
//Create the List View Control
listViewHandle = CreateWindow(WC_LISTVIEW, L"", WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_EDITLABELS, 100, 100, 500, 500, hWnd, (HMENU)PROJECT_LIST_VIEW, hInst, NULL);
InsertListViewItems(listViewHandle, stringsVector.size());
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_PAINT:
{
HDC hdc = BeginPaint(hWnd, &ps);
onRender(hWnd, &ps);
EndPaint(hWnd, &ps);
break;
}
case WM_SIZE:
{
if (m_pRenderTarget)
{
m_pRenderTarget->Release();
m_pRenderTarget = nullptr;
}
break;
}
////////////////////////////////////////////
//
// HERE ARE THE MOUSE MOVE CASES
//
/////////////////////////////////////////////
case WM_MOUSEHOVER:
{
OutputDebugStringA("HOVER\n");
mouseTracking = FALSE;
break;
}
case WM_MOUSEMOVE:
if (!mouseTracking)
{
// start tracking if we aren't already
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_HOVER | TME_LEAVE;
tme.hwndTrack = listViewHandle; //This is the handle to the ListView window
tme.dwHoverTime = HOVER_DEFAULT;
mouseTracking = TrackMouseEvent(&tme);
}
break;
case WM_MOUSELEAVE:
mouseTracking = FALSE;
break;
case WM_NOTIFY:
{
NMLVDISPINFO* plvdi;
switch (((LPNMHDR)lParam)->code)
{
case NM_CLICK:
OutputDebugStringA("CLICK\n");
break;
case LVN_GETDISPINFO:
{
////////////////////
//This is the callback that sets the pszText attribute of the items
////////////////////
plvdi = (NMLVDISPINFO*)lParam;
const char* inString = stringsVector[plvdi->item.iItem].c_str();
size_t size = strlen(inString) + 1;
wchar_t* outString = new wchar_t[size];
size_t outSize;
mbstowcs_s(&outSize, outString, size, inString, size - 1);
LPWSTR ptr = outString;
StringCchCopy(plvdi->item.pszText, plvdi->item.cchTextMax, outString);
delete[] outString;
break;
}
}
break;
}
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
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_PRACTICE));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_PRACTICE);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassExW(&wcex);
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
D2D1CreateFactory(
D2D1_FACTORY_TYPE_SINGLE_THREADED,
&m_pD2DFactory
);
hInst = hInstance; // Store instance handle in our global variable
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, hInstance, nullptr);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
//////////////////
//Function to insert the items into the list view
//////////////////
BOOL InsertListViewItems(HWND hWndListView, int cItems)
{
LVCOLUMN lvc;
lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
// Initialize LVITEM members that are common to all items.
// Initialize LVITEM members that are different for each item.
lvc.iSubItem = 0;
lvc.pszText = (LPWSTR)L"test";
lvc.cx = 200;
// Insert items into the list.
if (ListView_InsertColumn(hWndListView, 0, &lvc) == -1)
return FALSE;
LVITEM lvI;
// Initialize LVITEM members that are common to all items.
lvI.pszText = LPSTR_TEXTCALLBACK; //This should send an LVN_GETDISPINFO message
lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
lvI.stateMask = 0;
lvI.iSubItem = 0;
lvI.state = 0;
// Initialize LVITEM members that are different for each item.
for (int index = 0; index < cItems; index++)
{
lvI.iItem = index;
lvI.iImage = index;
// Insert items into the list.
if (ListView_InsertItem(hWndListView, &lvI) == -1)
return FALSE;
}
return TRUE;
}
HRESULT CreateDeviceResources(HWND hwnd, HDC hdc)
{
HRESULT hr = S_OK;
if (!m_pRenderTarget) { //If m_pRenderTarget changes size
// Create a DC render target.
D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties(
D2D1_RENDER_TARGET_TYPE_DEFAULT,
D2D1::PixelFormat(
DXGI_FORMAT_B8G8R8A8_UNORM,
D2D1_ALPHA_MODE_IGNORE),
0,
0,
D2D1_RENDER_TARGET_USAGE_NONE,
D2D1_FEATURE_LEVEL_DEFAULT
);
hr = m_pD2DFactory->CreateDCRenderTarget(&props, &m_pRenderTarget);
GetClientRect(hwnd, &rc);
if (SUCCEEDED(hr))
hr = m_pRenderTarget->BindDC(hdc, &rc);
D2D1_SIZE_U size = D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top);
w = size.width;
h = size.height;
if (SUCCEEDED(hr))
{//position objects
// Create a black brush
hr = m_pRenderTarget->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black), &m_pBlackBrush);
}
}
return hr;
}
bool onRender(HWND hwnd, PAINTSTRUCT* ps)
{
HDC hdc = ps->hdc;
HRESULT hr;
hr = CreateDeviceResources(hwnd, hdc);
if (SUCCEEDED(hr))
{
m_pRenderTarget->BeginDraw();
m_pRenderTarget->SetTransform(D2D1::IdentityMatrix());
m_pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::White));
hr = m_pRenderTarget->EndDraw();
}
SetWindowPos(listViewHandle, HWND_TOP, w * .1, h * .1, w * .3, h * .3, SWP_SHOWWINDOW);
SendMessage(listViewHandle, LVM_SETCOLUMNWIDTH, 0, w * .2);
if(SUCCEEDED(hr))
return true;
return false;
}

As dxiv said, If you need to handle NM_HOVER message, you need to add LVS_EX_TRACKSELECT style:
ListView_SetExtendedListViewStyle(listViewHandle, LVS_EX_TRACKSELECT);
If you don't want to choose hover but only want to handle hover, you can refer to:How can I detect if the mouse is over an item/subitem in a List View control?
Edit:
According to : TrackMouseEvent tracks mouse events in your window, but only if the events belong to your window
So you need to subclass your ListView and handle its window procedure:
WNDPROC oldListViewProc; //A global variable
oldListViewProc = (WNDPROC)SetWindowLongPtr(listViewHandle, GWL_WNDPROC, (LONG_PTR)ListViewProc);
......
LRESULT CALLBACK ListViewProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_MOUSEHOVER:
{
OutputDebugStringA("HOVER\n");
return 0;
}
case WM_MOUSEMOVE:
if (!mouseTracking)
{
// start tracking if we aren't already
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_HOVER | TME_LEAVE;
tme.hwndTrack = hwnd; //This is the handle to the ListView window
tme.dwHoverTime = HOVER_DEFAULT;
mouseTracking = TrackMouseEvent(&tme);
}
break;
case WM_MOUSELEAVE:
mouseTracking = FALSE;
break;
}
return CallWindowProc(oldListViewProc, hwnd, msg, wParam, lParam);
}

Related

How to subclass a gui control?

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.

Failed in Creating DDB Grayscale Bitmap with 24bit RGB by C++

I am trying to create a DDB Grayscale Bitmap using 24BitRGB format by C++. But I always get a bitmap with black block at bottom. It will be very appreciated if someone can help me on this issue. Many thanks.
The bitmap is : 1024x408 widthxheight
Below is my code:
enter code here
#include "stdafx.h"
#include "Win32Project19.h"
#include <windows.h>
#include <wingdi.h>
#include <algorithm>
#define MAX_LOADSTRING 100
// 全局变量:
HINSTANCE hInst; // 当前实例
WCHAR szTitle[MAX_LOADSTRING]; // 标题栏文本
WCHAR szWindowClass[MAX_LOADSTRING]; // 主窗口类名
// 此代码模块中包含的函数的前向声明:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(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: 在此放置代码。
// 初始化全局字符串
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_WIN32PROJECT19, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// 执行应用程序初始化:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WIN32PROJECT19));
MSG msg;
// 主消息循环:
while (GetMessage(&msg, nullptr, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
//
// 函数: MyRegisterClass()
//
// 目的: 注册窗口类。
//
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_WIN32PROJECT19));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_WIN32PROJECT19);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassExW(&wcex);
}
//
// 函数: InitInstance(HINSTANCE, int)
//
// 目的: 保存实例句柄并创建主窗口
//
// 注释:
//
// 在此函数中,我们在全局变量中保存实例句柄并
// 创建和显示主程序窗口。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // 将实例句柄存储在全局变量中
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
//
// 函数: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// 目的: 处理主窗口的消息。
//
// WM_COMMAND - 处理应用程序菜单
// WM_PAINT - 绘制主窗口
// WM_DESTROY - 发送退出消息并返回
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HBITMAP hBitmap;
HDC hdcMem, hdc;
static BYTE* lpBits = new BYTE[1024*3*408];
static BYTE* p;
static int cxClient, cyClient;
int i = 0;
int c = 0;
switch (message)
{
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// 分析菜单选择:
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_CREATE:
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
for (int y = 0; y < 408; y++)
{
for (int x = 0; x < 1024; x++)
{
lpBits[c + 0] = i;
lpBits[c + 1] = i;
lpBits[c + 2] = i;
c += 3;
}
i++;
if (i > 255)
i = 0;
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
hdc = BeginPaint(hWnd, &ps);
RECT rect;
// TODO: Please add code here....
hBitmap = CreateCompatibleBitmap(hdc, 1024, 408);
SetBitmapBits(hBitmap, 1024 * 3 * 408, lpBits);
GetClientRect(hWnd, &rect);
hdcMem = CreateCompatibleDC(hdc);
SelectObject(hdcMem, hBitmap);
StretchBlt(hdc, rect.left, rect.top, rect.right, rect.bottom, hdcMem, 0, 0, 1024,
408, SRCCOPY);
DeleteDC(hdcMem);
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
DeleteObject(hBitmap);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
I always get below results (always a black block in the bottom):
You are assuming that bitmap uses 3 bytes per pixel, but it appears that you need 4 (one for alpha channel).
I got your code to work by simply replacing all 3 with 4:
static BYTE* lpBits = new BYTE[WIDTH * 4 * HEIGHT];
...
c += 4;
...
SetBitmapBits(hBitmap, WIDTH * 4 * HEIGHT, lpBits);
Also, you create your hBitmap for each WM_PAINT message you get, but delete only once, in WM_DESTROY. That causes a resource leak, that may lead to other issues. Since hBitmap is static, you can create it like this:
if (!hBitmap) {
hBitmap = CreateCompatibleBitmap(hdc, WIDTH, HEIGHT);
SetBitmapBits(hBitmap, WIDTH * 4 * HEIGHT, lpBits);
}

List View failing to draw strings

I am trying to use a list view to draw a vector of std::strings as a list. However, when I run the code, nothing happens. No error is thrown: it just simple doesn't draw, and I'm stumped. Here is a minimal reproducible example (the bulk of the code that I am questioning is in the WndProc under case WM_NOTIFY and InsertListViewItems):
//libraries
#pragma comment ("lib", "Comctl32.lib")
#include "targetver.h"
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files
#include <windows.h>
// C RunTime Header Files
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>
#include <vector>
#include <string>
#include <dwrite.h>
#include <d2d1.h>
#include <commctrl.h>
#include <strsafe.h>
#define IDS_APP_TITLE 103
#define IDR_MAINFRAME 128
#define IDD_PRACTICE_DIALOG 102
#define IDD_ABOUTBOX 103
#define IDM_EXIT 105
#define IDI_PRACTICE 107
#define IDI_SMALL 108
#define IDC_PRACTICE 109
#define IDC_MYICON 2
#ifndef IDC_STATIC
#define IDC_STATIC -1
#endif
#define MAX_LOADSTRING 100
#define PROJECT_LIST_VIEW 110
// Global Variables:
HINSTANCE hInst; // current instance
WCHAR szTitle[MAX_LOADSTRING]; // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
std::vector<std::string> stringsVector = { "String1", "String2", "string3" };
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
HWND listViewHandle;
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_PRACTICE));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_PRACTICE);
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, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, hInstance, nullptr);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
///////////////////
//Function to insert the items into the list view
//////////////////
BOOL InsertListViewItems(HWND hWndListView, int cItems)
{
LVITEM lvI;
// Initialize LVITEM members that are common to all items.
lvI.pszText = LPSTR_TEXTCALLBACK; //This should send an LVN_GETDISPINFO message
lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
lvI.stateMask = 0;
lvI.iSubItem = 0;
lvI.state = 0;
// Initialize LVITEM members that are different for each item.
for (int index = 0; index < cItems; index++)
{
lvI.iItem = index;
lvI.iImage = index;
// Insert items into the list.
if (ListView_InsertItem(hWndListView, &lvI) == -1)
return FALSE;
}
return TRUE;
}
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// Initialize global strings
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_PRACTICE, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance(hInstance, nCmdShow))
{
return FALSE;
}
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_PRACTICE));
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;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
//Create the List View Control
listViewHandle = CreateWindow(WC_LISTVIEW, L"", WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_EDITLABELS, 100, 100, 500, 500, hWnd, (HMENU)PROJECT_LIST_VIEW, hInst, NULL);
InsertListViewItems(listViewHandle, stringsVector.size());
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_NOTIFY:
{
NMLVDISPINFO* plvdi;
OutputDebugStringA("WM_NOTIFY");
switch (((LPNMHDR)lParam)->code)
{
case LVN_GETDISPINFO:
{
////////////////////
//This is the callback that should set the pszText attribute of the items
////////////////////
OutputDebugStringA("LVN_GETDISPINFO\n");
plvdi = (NMLVDISPINFO*)lParam;
const char* inString = stringsVector[plvdi->item.iItem].c_str();
size_t size = strlen(inString) + 1;
wchar_t* outString = new wchar_t[size];
size_t outSize;
mbstowcs_s(&outSize, outString, size, inString, size - 1);
LPWSTR ptr = outString;
StringCchCopy(plvdi->item.pszText, plvdi->item.cchTextMax, outString);
OutputDebugString(outString);
OutputDebugStringA("\n");
delete[] outString;
break;
}
}
break;
}
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
Thank you for your time!
As Jonathan Potter and Remy said, you need to add at least one column to ensure that the list is displayed correctly:
LVCOLUMN lvc;
lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
// Initialize LVITEM members that are common to all items.
// Initialize LVITEM members that are different for each item.
lvc.iSubItem = 0;
lvc.pszText = (LPWSTR)L"test";
lvc.cx = 200;
// Insert items into the list.
if (ListView_InsertColumn(hWndListView, 0, &lvc) == -1)
return FALSE;
And it works for me:
More reference: How to Add List-View Columns

while implementing dwrite to draw a glyph of a font in c++ leads to nullptr error

I have been taking reference for my project from this source:
https://learn.microsoft.com/en-us/windows/win32/directwrite/getting-started-with-directwrite
My goal is very simple:
Follow the guidance in the link given below and somehow get the output that the link finally gets. I would have been glad if I at least got the intermediate output.
However, unfortunately my project always seems to compile with a nullptr error, and these are my findings so far. I'm working in an area out of my expertise and I was only able to find the following:
I am not sure if I have created the SimpleText class according to what has been given in the link
I am probably not linking the window handler correctly to the Simple Text class object
Here is my code(it seems big, but it is only just class definition + basic window creation, honestly nothing else at all)
// cvvvv.cpp : Defines the entry point for the application.
//
#include "framework.h"
#include "cvvvv.h"
#include<dwrite.h>
#include<d2d1.h>
#include<iostream>
#include<fstream>
#include<stdio.h>
using namespace std;
#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
// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
// *********************************************************************************
//HRESULT HasCharacter(
// UINT32 unicodeValue,
// BOOL* exists
//);
long const uniLast = 1114111;
//UINT32 codePoints[uniLast];
//UINT32 codePointsCount = uniLast;
//UINT16 glyphIndices[uniLast];
long long SairamAll;
// https://learn.microsoft.com/en-us/windows/win32/directwrite/getting-started-with-directwrite //
///// Part 1: Declare DirectWrite and Direct2D Resources. /////
// 1. In your class header file(SimpleText.h), declare pointers to IDWriteFactoryand IDWriteTextFormat interfaces as private members.
//IDWriteFactory* pDWriteFactory_;
//IDWriteTextFormat* pTextFormat_;
// 3. Declare pointers to ID2D1Factory, ID2D1HwndRenderTarget, and ID2D1SolidColorBrush interfaces for rendering the text with Direct2D.
//ID2D1Factory* pD2DFactory_;
//ID2D1HwndRenderTarget* pRT_;
//ID2D1SolidColorBrush* pBlackBrush_;
///// Part 2: Create Device Independent Resources. /////
template <class T> void SafeRelease(T** ppT)
{
if (*ppT)
{
(*ppT)->Release();
*ppT = NULL;
}
}
class SimpleText {
private:
// 2. Declare members to hold the text string to render and the length of the string.
IDWriteFactory* pDWriteFactory_;
IDWriteTextFormat* pTextFormat_;
const wchar_t* wszText_;
UINT32 cTextLength_;
ID2D1Factory* pD2DFactory_;
ID2D1HwndRenderTarget* pRT_;
ID2D1SolidColorBrush* pBlackBrush_;
HRESULT hr;
RECT rc;
HWND hwnd_;
float dpiScaleX_, dpiScaleY_;
public:
SimpleText() {
hr = CreateDeviceResources();
if (SUCCEEDED(hr))
{
pRT_->BeginDraw();
pRT_->SetTransform(D2D1::IdentityMatrix());
pRT_->Clear(D2D1::ColorF(D2D1::ColorF::White));
// Call the DrawText method of this class.
hr = DrawText();
if (SUCCEEDED(hr))
{
hr = pRT_->EndDraw(
);
}
}
if (FAILED(hr))
{
DiscardDeviceResources();
}
}
void CreateDeviceIndependentResources() {
hr = D2D1CreateFactory(
D2D1_FACTORY_TYPE_SINGLE_THREADED,
&pD2DFactory_);
if (SUCCEEDED(hr))
{
hr = DWriteCreateFactory(
DWRITE_FACTORY_TYPE_SHARED,
__uuidof(IDWriteFactory),
reinterpret_cast<IUnknown**>(&pDWriteFactory_)
);
}
wszText_ = L"Hello World using DirectWrite!";
cTextLength_ = (UINT32)wcslen(wszText_);
if (SUCCEEDED(hr))
{
hr = pDWriteFactory_->CreateTextFormat(
L"Gabriola", // Font family name.
NULL, // Font collection (NULL sets it to use the system font collection).
DWRITE_FONT_WEIGHT_REGULAR,
DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
72.0f,
L"en-us",
&pTextFormat_
);
}
// Center align (horizontally) the text.
if (SUCCEEDED(hr))
{
hr = pTextFormat_->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER);
}
if (SUCCEEDED(hr))
{
hr = pTextFormat_->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
}
}
HRESULT CreateDeviceResources() {
GetClientRect(hwnd_, &rc);
D2D1_SIZE_U size = D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top);
if (!pRT_)
{
// Create a Direct2D render target.
hr = pD2DFactory_->CreateHwndRenderTarget(
D2D1::RenderTargetProperties(),
D2D1::HwndRenderTargetProperties(
hwnd_,
size
),
&pRT_
);
// Create a black brush.
if (SUCCEEDED(hr))
{
hr = pRT_->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF::Black),
&pBlackBrush_
);
}
}
return hr;
}
void DiscardDeviceResources() {
SafeRelease(&pRT_);
SafeRelease(&pBlackBrush_);
}
HRESULT DrawText() {
D2D1_RECT_F layoutRect = D2D1::RectF(
static_cast<FLOAT>(rc.left) / dpiScaleX_,
static_cast<FLOAT>(rc.top) / dpiScaleY_,
static_cast<FLOAT>(rc.right - rc.left) / dpiScaleX_,
static_cast<FLOAT>(rc.bottom - rc.top) / dpiScaleY_
);
pRT_->DrawText(
wszText_, // The string to render.
cTextLength_, // The string's length.
pTextFormat_, // The text format.
layoutRect, // The region of the window where the text will be rendered.
pBlackBrush_ // The brush used to draw the text.
);
return hr;
}
};
// *********************************************************************************
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_CVVVV, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_CVVVV));
MSG msg;
SimpleText s;
// Main message loop:
while (GetMessage(&msg, nullptr, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
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_CVVVV));
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_CVVVV);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassExW(&wcex);
}
//
// FUNCTION: InitInstance(HINSTANCE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
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);
if (!hWnd)
{
return FALSE;
}
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
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
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_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code that uses hdc here...
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
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;
}
I am sorry if I am asking for too much. But I am honestly stuck, and very surprisingly, I was not able to find this implemented anywhere on the net(hope I did not miss something that was obviously there).

attach ActiveX into win32 application

i create win32 application and i want to attach an ActiveX into so i proceed like this
#include "stdafx.h"
#include "test.h"
#include <Windows.h>
#include <iostream>
#include <exdisp.h>
#using <System.dll>
using namespace std;
using namespace System;
// Constants
namespace {
TCHAR * windowClassName = TEXT("win32host");
TCHAR * windowTitle = TEXT("Win32 interface");
int windowWidth = 600;
int windowHeight = 600;
}
HWND container;
LRESULT CALLBACK WindowProc( HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam )
{
switch(messg)
{
case WM_SIZE:
// Redimensionnement du conteneur quand la taille de la fenêtre change:
MoveWindow(container,0,0,LOWORD(lParam), HIWORD(lParam),1);
break;
case WM_CLOSE:
// Détruire la fenêtre principale:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
// Envoyer le message de sortie du programme:
PostQuitMessage( 0 );
break;
default:
//Retour:
return( DefWindowProc( hWnd, messg, wParam, lParam ) );
}
return 0;
}
int CALLBACK WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// Register our Window class
WNDCLASS wndclass;
wndclass.style = CS_VREDRAW | CS_HREDRAW;
wndclass.lpfnWndProc = &WindowProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = NULL;
wndclass.hCursor = NULL;
wndclass.hbrBackground = reinterpret_cast <HBRUSH> (COLOR_BTNFACE + 1);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName =windowClassName;
::RegisterClass(&wndclass);
// Create our main, raw win32 API window
// We create the window invisible (meaning that we do not provide WS_VISIBLE as the window style parameter), because making it visible and then
// adding a HwndSource will make it flicker.
HWND mainWindow = ::CreateWindow(
windowClassName,
windowTitle,
0,
CW_USEDEFAULT,
CW_USEDEFAULT,
windowWidth,
windowHeight,
NULL,
NULL,
hInstance,
0);
::ShowWindow (mainWindow, nCmdShow);
::UpdateWindow( mainWindow );
//ocx
typedef HRESULT (WINAPI *PFonc)(IUnknown*, HWND,IUnknown**);
HINSTANCE hDLL2 = ::LoadLibrary(TEXT("atl.dll"));
if (!hDLL2)
return 1;
//PAttachControl AtlAxAttachControl = (PAttachControl) GetProcAddress(hDLL2, (LPCSTR)"AtlAxAttachControl");
PFonc AtlAxAttachControl = (PFonc) ::GetProcAddress(hDLL2,"AtlAxAttachControl");
CLSID clsid = GetClsid();
IID DIID__DLiveX = GetDIID__DLiveX();
RECT rect;
::GetClientRect(mainWindow,&rect);
container = ::CreateWindowEx(WS_EX_CLIENTEDGE, L"EDIT",L"",WS_CHILD | WS_VISIBLE,100,100,rect.right,rect.bottom,mainWindow,0,hInstance,0);
HRESULT hr = ::CoInitialize(0);
IWebBrowser2 *pIwb;
IUnknown* unkn;
hr = ::CoCreateInstance(CLSID_WebBrowser,0,CLSCTX_ALL,IID_IWebBrowser2,(void**)&pIwb);
hr = AtlAxAttachControl(pIwb,container,0);
if(FAILED(hr)){
MessageBox(0, L"FAILED(AtlAxAttachControl(pitd, container, NULL))", L"Error", MB_ICONERROR | MB_OK);
}
pIwb->GoHome();
pIwb->Navigate2((VARIANT*)L"www.google.com",0,0,0,0);
// Start message processing
::MSG message;
while (::GetMessageA(&message, 0, 0, 0)) {
switch (message.message) {
case WM_QUIT:
break;
default:
::TranslateMessage(& message);
::DispatchMessage(& message);
break;
}
}
CoUninitialize();
FreeLibrary(hDLL2);
return 0;
}
but the when i execute my programme i got two window, one my originale empty and the Activex in another wind,
Thanks.
I have made small changes and it compiles and shows only one window with an ActiveX included:
#include "stdafx.h"
#include <iostream>
#include <windows.h>
#include <comdef.h>
#include <exdisp.h>
#include <oledlg.h>
using namespace std;
// Constants
namespace {
TCHAR * windowClassName = TEXT("win32host");
TCHAR * windowTitle = TEXT("Win32 interface");
int windowWidth = 600;
int windowHeight = 600;
}
HWND container;
LRESULT CALLBACK WindowProc( HWND hWnd, UINT messg, WPARAM wParam, LPARAM lParam )
{
switch(messg)
{
case WM_SIZE:
// Redimensionnement du conteneur quand la taille de la fenêtre change:
MoveWindow(container,0,0,LOWORD(lParam), HIWORD(lParam),1);
break;
case WM_CLOSE:
// Détruire la fenêtre principale:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
// Envoyer le message de sortie du programme:
PostQuitMessage( 0 );
break;
default:
//Retour:
return( DefWindowProc( hWnd, messg, wParam, lParam ) );
}
return 0;
}
int CALLBACK WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// Register our Window class
WNDCLASS wndclass;
wndclass.style = CS_VREDRAW | CS_HREDRAW;
wndclass.lpfnWndProc = &WindowProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = NULL;
wndclass.hCursor = NULL;
wndclass.hbrBackground = reinterpret_cast <HBRUSH> (COLOR_BTNFACE + 1);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName =windowClassName;
::RegisterClass(&wndclass);
// Create our main, raw win32 API window
// We create the window invisible (meaning that we do not provide WS_VISIBLE as the window style parameter), because making it visible and then
// adding a HwndSource will make it flicker.
HWND mainWindow = ::CreateWindow(
windowClassName,
windowTitle,
0,
CW_USEDEFAULT,
CW_USEDEFAULT,
windowWidth,
windowHeight,
NULL,
NULL,
hInstance,
0);
::ShowWindow (mainWindow, nCmdShow);
::UpdateWindow( mainWindow );
typedef HRESULT (WINAPI *PFonc)(IUnknown*, HWND,IUnknown**);
HINSTANCE hDLL2 = ::LoadLibrary(TEXT("atl.dll"));
if (!hDLL2)
return 1;
PFonc AtlAxAttachControl = (PFonc) ::GetProcAddress(hDLL2,"AtlAxAttachControl");
RECT rect;
::GetClientRect(mainWindow,&rect);
container = ::CreateWindowEx(
WS_EX_CLIENTEDGE,
L"EDIT",
L"",WS_CHILD | WS_VISIBLE,
0,
0,
rect.right,
rect.bottom,
mainWindow,
0,
hInstance,
0);
HRESULT hr = ::CoInitialize(0);
IWebBrowser2 *pIwb;
hr = ::CoCreateInstance(CLSID_WebBrowser,0,CLSCTX_ALL,IID_IWebBrowser2,(void**)&pIwb);
hr = AtlAxAttachControl(pIwb,container,0);
if(FAILED(hr))
{
MessageBox(0, L"FAILED(AtlAxAttachControl(pitd, container, NULL))", L"Error", MB_ICONERROR | MB_OK);
}
pIwb->GoHome();
pIwb->Navigate2((VARIANT*)L"www.google.com",0,0,0,0);
// Start message processing
::MSG message;
while (::GetMessageA(&message, 0, 0, 0))
{
switch (message.message) {
case WM_QUIT:
break;
default:
::TranslateMessage(& message);
::DispatchMessage(& message);
break;
}
}
CoUninitialize();
FreeLibrary(hDLL2);
return 0;
}
I test out duDE's code and it works except it did not browse to the requested URL.
I am quite surprise that ocx can be used in win32 without ATL/MFC so easily in this way, but it actually works.
I think the failure to browse is because:
pIwb->Navigate2((VARIANT*)L"www.google.com",0,0,0,0);
Change it to:
// create variant for url
VARIANT varUrl;
// init variant
VariantInit(&varUrl);
varUrl.vt = VT_BSTR;
varUrl.bstrVal = SysAllocString(L"www.google.com");
// browse to url
hr = pIwb->Navigate2((VARIANT*)&varUrl,0,0,0,0);
// release variant
VariantClear(&varUrl);