I'm starting programming in C++ and want to start making applications with graphics and user interface.
I've watched many tutorials on the subject,
and have finished the first part of the tutorial
but the window refused to pop up, and I know that it's working because there are no errors,
and I can see it running in task manager.
Please help.
Hear is the code:
#include <Windows.h>
bool running = true;
LRESULT CALLBACK windows_callback(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LRESULT result = 0;
switch (uMsg) {
case WM_CLOSE:
case WM_DESTROY: {
running = false;
}break;
default: {
result = DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
return result;
}
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) {
//compile window
WNDCLASS window_class = {};
window_class.style = CS_HREDRAW | CS_VREDRAW;
window_class.lpszClassName = 0;
window_class.lpfnWndProc = windows_callback;
//register clases
RegisterClass(&window_class);
// create window
HWND window = CreateWindowA(0, "game stuff", WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 720, 360, 0, 0, hInstance, 0); {
while (running) {
// input
// simulate
MSG mesage;
while (PeekMessage(&mesage, window, 0, 0, PM_REMOVE)) {
TranslateMessage(&mesage);
DispatchMessage(&mesage);
}
// render
}
};
}
window refused to pop up, and I know that it's working because there
are no errors, and I can see it running in task manager.
You don't check the error for RegisterClass and CreateWindowA functions calls.
Check the return value of RegisterClass() you will find that the return value is zero, that indicates failure. To get extended error information, call GetLastError.
CreateWindowA() also fails, the return value is NULL. To get extended error information, call GetLastError.
If you use ANSI version of these functions, change WNDCLASS to WNDCLASSA, RegisterClass to RegisterClassA.
You missed class name in both two functions. The following is an example based on your presented code to make the window show up. You can have a try.
CHAR clsName[] = "test";
WNDCLASSA window_class = {};
window_class.style = CS_HREDRAW | CS_VREDRAW;
window_class.lpszClassName = clsName;
window_class.lpfnWndProc = windows_callback;
//register clases
ATOM atom = RegisterClassA(&window_class);
if (0 == atom)
{
DWORD err = GetLastError();
return 0;
}
// create window
HWND window = CreateWindowA(clsName, "game stuff", WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 720, 360, 0, 0, hInstance, 0);
if (NULL == window)
{
DWORD err = GetLastError();
return 0;
}
More references: "Your First Windows Program", "Unicode in the Windows API".
Update:
why does it have a Chinese name (window's name displays unexecpted)
For using above sample code to display window's name expected you can change project setting to "Use Multi-Byte Character Set" like this:
Or you can use UNICODE APIs (RegisterClassW and CreateWindowW) with project setting "Use Unicode Character Set".
Or you can use the macros like RegisterClassEx and CreateWindowEx, it will choose UNICODE or ASCII version API along with your project setting automatically.
Related
Experimenting with attempts to create a Win32 window with minimal code I discovered a strange (perhaps undocumented) behavior. If the programmer omits defining a cursor in the WNDCLASSEX struct or defines the cursor as:
WNDCLASSEX wc
...
wc.hCursor = LoadCursor(hInstance, IDC_ARROW);
The window will be displayed but never activate unless the user hovers the mouse over a border or the title bar. I found out that Windows was constantly sending WM_SETCURSOR messages as well as the normal messages expected during application startup and window creation when over the client area. I never noticed this in the past until I created a window that was initially borderless. That window displayed a continuous "wait" cursor (spinning circle). This behaviour can be reproduced with the following code. Since I could not find any explanation on MSDN or other sites, I just wanted to put this out there for others to find. To see this, run this code and make sure the cursor is over the client area when the window is created.
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
return DefWindowProcW(hwnd, msg, wparam, lparam);
}
int main(int argc, char** argv)
{
HINSTANCE hinstance(GetModuleHandleW(0));
WNDCLASSEXW wc({ 0 });
wc.cbSize = sizeof(WNDCLASSEXW);
//wc.style = CS_HREDRAW | CS_VREDRAW;// | CS_OWNDC; // unneeded
wc.lpszClassName = L"classname";
wc.lpfnWndProc = WndProc;
wc.hInstance = hinstance;
//wc.hbrBackground = HBRUSH(COLOR_WINDOW + 1); // unneeded
//wc.hIcon = LoadIconW(0, IDI_APPLICATION); // unneeded
//wc.hIconSm = wc.hIcon; // unneeded
//wc.hCursor = LoadCursorW(hinstance, IDC_ARROW); // will not activate properly
//wc.hCursor = LoadCursorW(0, IDC_ARROW); // needed for proper activation
if (!RegisterClassExW(&wc)) {
DWORD err = GetLastError();
return -1;
}
DWORD style = WS_OVERLAPPEDWINDOW | WS_VISIBLE;
HWND handle = CreateWindowExW(0, L"classname", L"Test Window"
, style, CW_USEDEFAULT, CW_USEDEFAULT
, CW_USEDEFAULT, CW_USEDEFAULT, 0
, (HMENU)0, hinstance, 0);
if (!handle)
return -1;
MSG msg;
while (1) {
while (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT)
return ((int)msg.wParam);
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
}
return 0;
}
I have a dialog box that I am using for user input, and it was working just fine, now no matter what I do the dialog pops up for one second and then the program dies with no warning, calling WM_DESTROY even after I comment out all the possible exits. There is only one error, which is the no_init_all error, but that shows up every time there is a runtime error, and is pretty useless in trying to find the solution.
Here is my code:
project.cpp
BOOL CreateMyDialog(HINSTANCE hInstance) {
HWND hWnd = CreateDialog(NULL, MAKEINTRESOURCE(myDialogResource), NULL, (DLGPROC)myDialogProcess);
if (!hWnd) {
return FALSE;
}
myDialogGlobalHandle = hWnd;
ShowWindow(hWnd, SW_SHOW);
//UpdateWindow(hWnd);
return TRUE;
}
INT_PTR CALLBACK myDialogProcess(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
INITCOMMONCONTROLSEX InitCtrlEx;
InitCtrlEx.dwSize = sizeof(INITCOMMONCONTROLSEX);
InitCtrlEx.dwICC = ICC_PROGRESS_CLASS;
InitCommonControlsEx(&InitCtrlEx);
switch(msg) {
case WM_INITDIALOG: {
//Do stuff to prep the dialog
return TRUE;
}
case WM_DESTROY: {
PostQuitMessage(WM_QUIT);
break;
}
}
return TRUE;
}
project.rc
myDialogResource DIALOGEX 600, 400, 286, 108
STYLE DS_SYSMODAL | DS_SETFONT | DS_SETFOREGROUND | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION
EXSTYLE WS_EX_OVERLAPPEDWINDOW /*| WS_EX_APPWINDOW*/
CAPTION "My Dialog"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
COMBOBOX dropdownList,112,7,61,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
//... it's all syntactically correct controls that still work the split second the dialog is on the screen
END
This is the shortened code, and even with this the dialog opens on top of itself and glitches on the screen. With my full code, it appears normally for a split-second before the app closes. I believe if I can fix this small bit, I can find the issue with my dialog. So my question is, what's the issue?
EDIT:
Here is my wWinMain:
HWND myDialogGlobalHandle;
int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) {
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
INITCOMMONCONTROLSEX InitCtrlEx;
InitCtrlEx.dwSize = sizeof(INITCOMMONCONTROLSEX);
InitCtrlEx.dwICC = ICC_PROGRESS_CLASS;
InitCommonControlsEx(&InitCtrlEx);
if (!CreateMyDialog(hInstance)) {
//return FALSE;
}
else {
MSG message = { 0 };
while (GetMessage(&message, nullptr, 0, 0)) {
if (!IsDialogMessage(myDialogGlobalHandle, &message)) {
DispatchMessage(&message);
}
}
}
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_PROJECT));
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;
}
As it turns out, all my code was correct. The issue was with the case statements in my dialog procedure, for some reason Visual Studio didn't like brackets in the case statements. After trying everything and then just replacing them with break; statements, my code started working again.
My App is a DLL and i'm injecting it into a (Game) process .
When i use LoadBitmap() and use MAKEINTRESOURCE(IMAGE_RESOURCE_NAME)
Like this :
MyImage = LoadBitmap(hInstance, MAKEINTRESOURCE(IMAGE_RESOURCE_NAME))
SendMessage(MyButton, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)MyImage);
The Create Button code :
MyButton = CreateWindow("BUTTON", "My Button", WS_VISIBLE | WS_CHILD | BS_BITMAP | BS_FLAT, 17, 18, 110, 30, hwnd, (HMENU)ButtonId, (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), NULL);
LoadBitmap() works when i Inject the DLL into any application but the game.
i think because when i inject the DLL to the game, it won't load from Resources and the image doesn't appear. so i'm not able to use LoadBitmap from Resources. somehow the Resources dosen't go with the DLL data to the Game and the game doesn't find the resources so it can't find the Image.
So alternatively i tried to use LoadImage() from disk file. and that way it worked and the Image appears on the button.
When i Inject it to any application like notepad it appears like this :
(That's what i want it to be like)
But when i inject the DLL to the game, the button appears in a border & 3D Effect :
With a lot of searching i assumed that The Game i'm injecting to doesn't apply Visual Styles to my DLL GUI Window and the Buttons appear in the Classy look, Border & 3D Effect. even BS_FLAT doesn't apply to the button.
Here's the full code I'm using :
#include "stdafx.h"
#include "Process.h"
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include <tchar.h>
#include "resource.h"
HINSTANCE hInstance;
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc = { 0 };
HWND MainHwnd;
MSG Msg;
wc.cbSize = sizeof(wc);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.hbrBackground = (HBRUSH)(CreateSolidBrush(RGB(30, 30, 30)));
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.lpszMenuName = NULL;
wc.lpszClassName = "My Application";
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
if (!RegisterClassEx(&wc))
{
MessageBox(NULL, std::to_string(GetLastError()).c_str(), "RegisterClassEx!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
MainHwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
"Application",
"My Application",
WS_SYSMENU | WS_OVERLAPPED | WS_CAPTION | WS_MINIMIZEBOX,
CW_USEDEFAULT, CW_USEDEFAULT, 400, 280,
NULL, NULL, hInstance, NULL);
if (MainHwnd == NULL)
{
MessageBox(NULL, std::to_string(GetLastError()).c_str(), "CreateWindow!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}
ShowWindow(MainHwnd, nCmdShow);
UpdateWindow(MainHwnd);
while (GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}
int MyButtonId = 1000;
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CREATE: {
HWND MyButton;
HBITMAP MyImage;
MyButton = CreateWindow("BUTTON", "A Button Text", WS_VISIBLE | WS_CHILD | BS_BITMAP | BS_FLAT, 17, 18, 110, 30, hwnd, (HMENU)MyButtonId, (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), NULL);
///////// --->
// Here I'm using one of these :
// Using LoadImage()
MyImage = (HBITMAP)LoadImage(hInstance, "UI\\myimage.bmp", IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR | LR_DEFAULTSIZE | LR_LOADFROMFILE);
// Using LoadBitmap() | My_Bitmap is an image resource name
MyImage = LoadBitmap(hInstance, MAKEINTRESOURCE(My_Bitmap));
///////// <---
SendMessage(MyButton, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)MyImage);
break;
}
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
unsigned long __stdcall Win_Thread(LPVOID Param)
{
WinMain(NULL, NULL, NULL, 1);
return 0;
}
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
// Set hInstance to hModule
hInstance = hModule;
CreateThread(0, 0, LPTHREAD_START_ROUTINE(Win_Thread), hModule, 0, 0);
}
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
I think i have two options.
1. try to make the game find my Images from Resources and use LoadBitmap() from Resources. so the button won't be with border & 3d effect.
2. continue using LoadImage() from disk file, and try to hide the border & 3d Effect, e.g Enable Visual Styles for my DLL GUI.
Unfortunately i couldn't do any of those and have no idea how to do that, i'm searching the whole internet but didn't find anything about that.
How could i achieve that, any ideas?
Unfortunately, your pursuit of LoadBitmap is a snipe hunt. Visual Styles are the only thing causing the different appearance. Even if you get the code for using a resource working, you'll still have the wrong appearance unless you enable visual styles.
MSDN has a reference specifically for using Visual Styles in a plugin DLL, when the main application doesn't use them:
Adding Visual Style Support to an Extension, Plug-in, MMC Snap-in or a DLL That Is Brought into a Process
The gist is that you need to use the ISOLATION_AWARE_ENABLED macro and manifest your DLL for visual styles.
You will also need to call InitCommonControlsEx. That's mentioned in several other sections of the above document. For flat buttons, pass the ICC_STANDARD_CLASSES flag (inside the structure).
You do have a couple mistakes in your code, and these might prevent visual styles from properly activating even when you do the manifesting and isolation.
Your DLL should not have a WinMain function. Let there be one function doing all the work that gets called from both WinMain and the DLL thread, instead of having the DLL thread call WinMain. This isn't wrong by itself, just bad style, but it caused the next error which is a bigger problem:
Your hInstance parameter hides the global hInstance variable, resulting in the wrong value for wc.hInstance. If WinMain and DllMain both set the global variable, and then all the rest of the code used the global, you wouldn't be having this problem. But fixing it needs code running in the EXE and not the DLL, which means removing the call from the DLL thread to WinMain.
I recently finished an introductory lesson on C++ and decided to jump into Visual C++ to try to make a little application.
So far, all I want is to at least create and show a window, didn't go any further.
I used many Microsoft Tutorials to get the code I have.
Please note that I have many comments to help me understand what I am doing.
I`m using Microsoft Visual Studio 2015
#include <tchar.h> //A Win32 character string that can be used to describe ANSI, DBCS, or Unicode strings
//Enclose the strings in _T() if an incompatibility error occures or (LPCWSTR)L""
#include <windows.h>
// Global variable
HINSTANCE hinst;
//Function prototype for the window procedure so the inside of the program knows wazup
LRESULT CALLBACK WinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
BOOL InitApplication(HINSTANCE);
BOOL InitInstance(HINSTANCE, int);
//Instead of your usual console program, you get WinMain() instead of int main(int argc,char *argv[])
INT WINAPI wWinMain(HINSTANCE hInst, //Instance of the program being executed
HINSTANCE hPrevInst, //Previous instance, not used much anymore
LPWSTR lpCmdLine, //Holds command line arguments
INT nShowCmd) //Tells how the program should start(minumised, maximised...)
{
/*Steps to create a window:
- Register a window class
- Create the window
- Show the window
- Setup a callback procedure
*/
//We can tell if the window class has failed if RegisterClassEx() returns 0.
//Fortunatley, there is another handy function, namely GetLastError().
//GetLastError() will return an error code, which can then be used to track down the cause of the error.
//https://msdn.microsoft.com/en-us/library/ms681381.aspx
if (!InitApplication(hInst))
{
int nResult = GetLastError();
MessageBox(NULL,
_T("Window class creation failed"),
_T("Window Class Failed"),
MB_ICONERROR);
return 1;
}
//Window creation & display:
if (!InitInstance(hInst, nShowCmd)){
int nResult = GetLastError();
MessageBox(NULL,
_T("Window creation failed"),
_T("Window Creation Failed"),
MB_ICONERROR);
return 1;
}
//The windows 'callback procedure' is necessary to continue
MSG msg; //Message handler
ZeroMemory(&msg, sizeof(MSG));
//Main loop for the program
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);//translates virtual key messages to character messages
DispatchMessage(&msg); //Sends any messages to the callvack procedure, so it can be handled
}
//Still returns an int!
return 0;
}
BOOL InitApplication(HINSTANCE hinstance)
{
//The window class defines the overall 'look and feel' of the window that we want to create.
//First we create an instance of a window class
WNDCLASSEX wClass;
//For more about WNDCLASSEX: https://msdn.microsoft.com/en-us/library/ms633577(VS.85).aspx
//Clearing all the parameters of the WNDCLASSEX instance wClass to zero
ZeroMemory(&wClass, sizeof(WNDCLASSEX));
//Now we are setting up all sotrts of parameters for our instance:
wClass.cbClsExtra = NULL; // cbClsExtra Additional parameters
wClass.cbSize = sizeof(WNDCLASSEX); // cbSize Specifies the size of the window class
wClass.cbWndExtra = NULL; // cbWndExtra Additional parameters
wClass.hbrBackground = (HBRUSH)COLOR_WINDOW; // hbrBackground Sets background color for the window
wClass.hCursor = LoadCursor(NULL, IDC_ARROW); // hCursor The cursor that will appear in the window
wClass.hIcon = NULL; // hIcon Icon for the window
wClass.hIconSm = NULL; // hIconSm Small icon for the window
wClass.hInstance = hinstance; // hInstance Handle to the application instance
wClass.lpfnWndProc = (WNDPROC)WinProc; // lpfnWndProc The callback procedure (more on that later)
wClass.lpszClassName = _T("Window Class"); // lpszClassName The unique name of the window class
wClass.lpszMenuName = NULL; // lpszMenuName Used for menus
wClass.style = CS_HREDRAW | CS_VREDRAW; // style The look and feel of the window
// Register the window class.
return RegisterClassEx(&wClass);
}
BOOL InitInstance(HINSTANCE hinstance, int nCmdShow)
{
// Save the application-instance handle.
hinst = hinstance;
// Create the main window.
//CreateWindowEx returns a HWND
HWND hwnd = CreateWindowEx( // A "handle" is a generic identifier + like "new"
0, // DWORD, extended window style of the window being created https://msdn.microsoft.com/en-us/library/windows/desktop/ff700543(v=vs.85).aspx
_T("MainsWClass"), // LPCTSTR, A null-terminated string or a class atom created by a previous call to the RegisterClass or RegisterClassEx function.
_T("Sample"), // LPCTSTR, The window name.
WS_OVERLAPPEDWINDOW, // DWORD, Style of the window created
CW_USEDEFAULT, // int, X - default horizontal position
CW_USEDEFAULT, // int, Y - default vertical position
CW_USEDEFAULT, // int, nWidth - default width
CW_USEDEFAULT, // int, nHeight - default height
(HWND)NULL, // HWND, hWndParent - handle to the parrent or owner window of the window being created (opptional for pop-up)
(HMENU)NULL, // HMENU, hMenu
hinstance, // HINSTANCE, hInstance - A handle to the instance of the module to be associated with the window.
(LPVOID)NULL); // LPVOID, Pointer to a value to be passed to the window through the CREATESTRUCT structure
//If the creation fails, returns FALSE
if (!hwnd)
return FALSE;
else{
// Show the window and send a WM_PAINT message to the window procedure.
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
return TRUE;
}
}
//callback procedure
LRESULT CALLBACK WinProc(
HWND hWnd, //Handle of the window that we want to monitor
UINT msg, //Message we are receiving
WPARAM wParam, //Additionnal info for the received message
LPARAM lParam)
{
switch (msg)
{
case WM_DESTROY: //Message sent to the application if the program was closed using the X on the top of the window
{
PostQuitMessage(0);
return 0;
}
break;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
You are registering a window class named "Window Class", but try to create a window of class "MainsWClass". That class is unknown. You need to create window of a window class that has previously been registered (either by yourself, or one of the pre-defined window classes like "BUTTON").
I am having trouble using the function SHAutoComplete. It simply does not work correctly when I use it on a edit box whose parent window is not a dialog box.
The auto-complete functionality seems to be working fine, but the rendering of the drop-down list with the possible candidates based on what was typed on the edit box is very messed up. Basically only the borders of the drop-down are shown. The borders are rendered wide enough to fit the possible suggestions, but the suggestions themselves are never drawn. Even the drop-down list background color is wrong. It is as if it was never painted and remains with the original parent window color.
And if the number of suggestions is big enough so the drop-down needs a scroll-bar, the scrollbar also does not get rendered correctly - the arrows do not get drawn.
On both cases, with or without scrollbars, the drop-down list does not accept mouse input, i.e., I cannot click on the items. If I press the "down" key on the keyboard while the drop-down is being shown, it kind of works as expected. After the second or third press the items finally start to appear. But the scrollbar still is does not get rendered correctly.
If instead of registering my own windows class I simply use a dialog with ::DialogBoxParam(), then it all goes as expected. The auto-complete works without any problems at all.
Here is what I am doing. This code will register a window class, create the main window, create an edit box and then call SHAutoComplete on it. It must be linked with Shlwapi.lib
// this code must be linked with Shlwapi.lib
#include <Windows.h>
#include <Shlwapi.h>
// name of the class that will be created for the main window
static const char WindowClassName[] = "SHAutoCompleteDoesNotWorkWithoutADialogWindowClassName";
// the main window procedure
static LRESULT CALLBACK WindowProc(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
switch(uMsg)
{
case WM_CREATE:
{
HWND hwndEdit = ::CreateWindowEx(
0,
"EDIT",
0,
WS_CHILD | WS_VISIBLE,
10,
10,
300,
25,
hwnd,
NULL,
NULL,
0);
::SHAutoComplete(hwndEdit, SHACF_DEFAULT);
return 0;
}
case WM_DESTROY:
::PostQuitMessage(1);
return 0;
default:
return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
// the app entry point
int CALLBACK WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
::CoInitialize(NULL);
WNDCLASSEX wcex = {0};
wcex.cbSize = sizeof(wcex);
wcex.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW ;
wcex.lpfnWndProc = WindowProc;
wcex.hInstance = hInstance;
wcex.lpszClassName = WindowClassName;
wcex.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
ATOM atom = ::RegisterClassEx(&wcex);
HWND hwnd = ::CreateWindowEx(
0,
MAKEINTATOM(atom),
"SHAutoComplete Test",
WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
MSG msg;
while(::GetMessage(&msg, hwnd, 0, 0) > 0)
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
::UnregisterClass((LPCTSTR)atom, NULL);
::CoUninitialize();
return 0;
}
That code produces the following:
the drop-down when a scroll bar is needed
http://www.abload.de/img/shautocomplete_2i1sk4.jpg
the drop-down after a couple of presses to the "down" key. Notice how the scroll bar still is not rendered correctly.
http://www.abload.de/img/shautocomplete_3efsgw.jpg
Now, when I switch to Dialog Boxes, works like a charm. In the code below, IDD_DIALOG1 is simply an empty dialog box resource, created automatically by the IDE.
Here is the relevant part of the rc file
IDD_DIALOG1 DIALOGEX 0, 0, 316, 185
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Dialog"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
END
And here is the code that uses it
// this code must be linked with Shlwapi.lib
#include <windows.h>
#include <Shlwapi.h>
#include "Resource.h"
BOOL CALLBACK DialogProc(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
switch(uMsg)
{
case WM_INITDIALOG:
{
HWND hwndEdit = ::CreateWindowEx(
0,
"EDIT",
0,
WS_VISIBLE | WS_CHILD,
0,
0,
300,
20,
hwnd,
NULL,
NULL,
0);
::SHAutoComplete(hwndEdit, SHACF_DEFAULT);
return 1;
}
case WM_CLOSE:
::EndDialog(hwnd, 0);
return 1;
default:
return 0;
}
}
int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nShowCmd)
{
::CoInitialize(NULL);
::DialogBoxParam(
NULL,
MAKEINTRESOURCE(IDD_DIALOG1),
NULL,
DialogProc,
0);
::CoUninitialize();
return 0;
}
Could you please point out where I am going wrong? As far as I can see, other than the creation and destruction of the main window, there seems to be no difference at all between the two of them. Am I missing something on the SHAutoComplete docs that states it can only be used on edit boxes inside dialogs?
You are using a filtered message loop so any messages for the drop down are not being processed. Pass NULL as the second parameter to GetMessage