i want to know if there's a way to print a jpg onto a picture control rectangle (that i build with ResEdit) the action that should print the image is case IDC_BUTTON1: and the target i want to view the image is in a picture control with the id: IDC_STATIC
BOOL CALLBACK AppDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_INITDIALOG:
DragAcceptFiles(hDlg,true);
SetClassLongPtr(hDlg, GCLP_HICON, (long)LoadIcon(0, IDI_APPLICATION));
return 1;
case WM_COMMAND:
switch(wParam)
{
case IDOK:
return 0;
case IDCANCEL:
EndDialog(hDlg, 0);
}
switch(wParam)
{
case IDC_BUTTON1:
ShellExecute(hDlg,
"open",
"C:\immagine1.jpg",
NULL,
NULL,
SW_SHOWDEFAULT);
break;
}
switch(wParam)
{
case IDC_BUTTON4:
ShellExecute(hDlg,
"open",
"C:\log.txt",
NULL,
NULL,
SW_SHOWDEFAULT);
break;
}
}
return 0;
}
instead of using shell execute that open the default viewer thank you all
The OleLoadPicturePath API function can load a JPEG file.
Then it's just a matter of accessing the bits.
There's also the Windows Imaging Component API, but I haven't used that.
I suspect that it also works, though, and it may be simpler than dealing with the OLE stuff, but here I exemplify OleLoadPicturePath.
Before trying to adapt the code below, you should:
Make sure that the type of the picture control resource is set to BITMAP (essentially, at the .rc text level, that it has the SS_BITMAP style).
Change the ID to something unique, instead of IDC_STATIC.
#include <header_wrapper/olectl_h.h> // IPicture
#include <header_wrapper/windows_h.h>
#include "resource.h" // IDD_DEMO_DIALOG, IDC_PICTURE
#include <progrock/cppx/throwx.h> // hopefully, throwX, std::exception
#include <progrock/cppx/size.h> // size
#include <progrock/winapi/path.h> // *
#include <progrock/winapi/ComPointer.h> // ComPointer
using namespace progrock;
#include <assert.h> // assert
#include <iostream>
#include <stdlib.h> // EXIT_FAILURE, EXIT_SUCCESS
using namespace std;
using cppx::hopefully;
using cppx::size;
using cppx::throwX;
using winapi::String;
struct IsHrSuccess
{
friend bool operator>>( HRESULT const hr, IsHrSuccess const& )
{
return SUCCEEDED( hr );
}
};
IsHrSuccess const isHrSuccess = IsHrSuccess();
short kindOf( IPicture const& pic )
{
short kind = 0;
const_cast< IPicture& >( pic ).get_Type( &kind )
>> isHrSuccess || throwX( "kindOf: IPicture::get_Type failed" );
return kind;
}
bool isBitmap( IPicture const& pic )
{
return (kindOf( pic ) == PICTYPE_BITMAP);
}
OLE_HANDLE handleOf( IPicture const& pic )
{
OLE_HANDLE result = 0;
const_cast< IPicture& >( pic ).get_Handle( &result )
>> isHrSuccess || throwX( "handleOf: IPicture::get_Handle failed" );
return result;
}
HBITMAP bmpHandle( IPicture const& pic )
{
assert( isBitmap( pic ) );
return reinterpret_cast< HBITMAP >( handleOf( pic ) );
}
namespace g {
winapi::ComPointer<IPicture> pPicture;
} // namespace g
INT_PTR CALLBACK demoDialogProc(
HWND const window,
UINT const messageId,
WPARAM const wParam,
LPARAM const lParam
)
{
switch( messageId )
{
case WM_INITDIALOG:
::SendDlgItemMessage(
window, IDC_PICTURE, STM_SETIMAGE,
IMAGE_BITMAP,
reinterpret_cast< LPARAM >( bmpHandle( *g::pPicture ) )
);
break;
case WM_CLOSE:
::EndDialog( window, IDCANCEL );
break;
case WM_COMMAND:
::EndDialog( window, wParam );
break;
}
return 0;
}
struct Com
{
Com() { ::CoInitialize( 0 ) >> isHrSuccess || throwX( "::CoInitialize failed" ); }
~Com() { ::CoUninitialize(); }
};
void cppMain()
{
Com usingCom;
String const picFileName = L"image.jpg";
String const picFilePath = winapi::path::combine( winapi::exeFolder(), picFileName );
::OleLoadPicturePath(
const_cast< wchar_t* >( picFilePath.c_str() ),
nullptr, 0, 0,
IID_IPicture,
g::pPicture.asOutArgument()
)
>> isHrSuccess || throwX( "OleLoadPicturePath failed" );
assert( isBitmap( *g::pPicture ) );
::DialogBox( ::GetModuleHandle( 0 ), MAKEINTRESOURCE( IDD_DEMO_DIALOG ), 0, demoDialogProc );
}
int main()
{
try
{
cppMain();
return EXIT_SUCCESS;
}
catch( exception const& x )
{
wcout << "!" << x.what() << endl;
}
return EXIT_FAILURE;
}
Related
Using the following code to update my application with an external exe file, I get paint corruption (not update or refresing) to window under -which is the main app and the caller- when I move this window. It seems that under Windows 7 works fine but under window XP I have this problem.
void CMainFrame::OnBtnUpdateApp() {
SHELLEXECUTEINFO lpExecInfo;
DWORD dwExitCode;
HINSTANCE hProcess = 0;
BOOL bResult;
ZeroMemory(&lpExecInfo,sizeof(lpExecInfo));
lpExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
lpExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
lpExecInfo.hwnd = GetSafeHwnd();
lpExecInfo.lpVerb = _T("open");
lpExecInfo.lpFile = _T("Update.exe");
lpExecInfo.lpParameters = _T("");
lpExecInfo.lpDirectory = _T("");
lpExecInfo.nShow = SW_SHOWNORMAL;
lpExecInfo.hInstApp = NULL;
lpExecInfo.hProcess = hProcess;
bResult = ShellExecuteEx(&lpExecInfo);
if(bResult) {
WaitForSingleObject( lpExecInfo.hProcess, INFINITE );
if (!GetExitCodeProcess(lpExecInfo.hProcess, &dwExitCode)) {
//failed to terminate normally
}
CloseHandle(lpExecInfo.hProcess);
} else {
//failed to execute the exe file
}
}
What seems to be wrong here ?
You're not processing any window messages during WaitForSingleObject.
Re the difference between Windows XP and Windows 7, the Desktop Window Manager technology in Windows 7 was introduced with Windows Vista, and was not available in Windows XP. Essentially it provides a layer of indirection between each app's painting actions and the result on screen.
A reasonable way to launch and wait for a program is to disable the main window the window's user interface parts and then poll the program's exit status in a peek-message loop.
Example, except that it uses CreateProcess (I coded it up without remembering to check the question, and now it's pretty late in the evening, but better with imperfect help than no help, I think):
#include <windows.h> // UNICODE, NOMINMAX, STRICT, WIN32_LEAN_AND_MEAN
#include <windowsx.h> // Message cracker macros, e.g. HANDLE_WM_DESTROY
#include <assert.h>
#include <stdexcept>
#include <string>
using namespace std;
auto hopefully( bool const condition ) -> bool { return condition; }
auto fail( string const& s ) -> bool { throw runtime_error( s ); }
struct Window_class_id
{
ATOM value;
auto as_pointer() const -> wchar_t const* { return MAKEINTATOM( value ); }
};
auto get_message( MSG& m )
-> bool
{
int const result = GetMessage( &m, 0, 0, 0 );
hopefully( result != -1 )
|| fail( "GetMessage failed" );
return !!result;
}
auto peek_message( MSG& m )
-> bool
{
int const result = PeekMessage( &m, 0, 0, 0, TRUE );
hopefully( result != -1 )
|| fail( "PeekMessage failed" );
return !!result;
}
void empty_message_queue()
{
MSG m;
while( peek_message( m ) )
{
TranslateMessage( &m );
DispatchMessage( &m );
}
}
auto dispatch_messages()
-> DWORD // Exit code from WM_QUIT
{
MSG msg;
while( get_message( msg ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
assert( msg.message == WM_QUIT );
return msg.wParam;
}
auto run( wchar_t const command[] )
-> HANDLE
{
wstring commandline = command;
hopefully( commandline.length() > 0 )
|| fail( "run: Empty command line" );
STARTUPINFO in_params = { sizeof( STARTUPINFO ) };
PROCESS_INFORMATION out_params = {};
bool const success = !!CreateProcess(
nullptr, // app name
&commandline[0],
nullptr, // process attributes
nullptr, // thread attributes
false, // inherit handles
0, // creation flags
nullptr, // environment block
nullptr, // current directory
&in_params, // startup info
&out_params // process info
);
hopefully( success )
|| fail( "run: CreateProcess failed" );
CloseHandle( out_params.hThread );
return out_params.hProcess;
}
namespace main_window
{
namespace command_id {
int const run_fun = 101;
} // namespace command
namespace run_button {
int const id = command_id::run_fun;
} // namespace run_button
namespace command {
void run_fun( HWND const window )
{
EnableWindow( GetDlgItem( window, run_button::id ), false );
UpdateWindow( window );
empty_message_queue();
HANDLE const process = run( L"notepad" );
for( ;; )
{
DWORD const result = WaitForSingleObject( process, 100 );
if( result == WAIT_OBJECT_0 )
{
break;
}
empty_message_queue();
}
CloseHandle( process );
EnableWindow( GetDlgItem( window, run_button::id ), true );
}
} // namespace command
void on_command( HWND const window, int const id )
{
switch( id )
{
case command_id::run_fun: return command::run_fun( window );
}
}
void on_wm_command(
HWND const window,
int const control_or_command_id,
HWND const control,
UINT const notification_code
)
{
if( control == 0 )
{
int const command_id = control_or_command_id;
on_command( window, command_id );
}
else
{
int const control_id = control_or_command_id;
switch( control_id )
{
case run_button::id:
if( notification_code == BN_CLICKED )
{
int const command_id = control_id;
on_command( window, command_id );
}
}
}
}
auto on_wm_create( HWND const window, CREATESTRUCT const* const p_params )
-> bool // `true` if creation succeeded.
{
(void) p_params;
HWND const button_handle = CreateWindow(
L"button", L"Run the fun", WS_CHILD | WS_VISIBLE,
10, 10, 120, 26,
window, // parent
reinterpret_cast<HMENU>( run_button::id ),
GetModuleHandle( 0 ),
0 // lpParam
);
return (button_handle != 0);
}
void on_wm_destroy( HWND const window )
{
(void) window;
PostQuitMessage( 0 );
}
auto CALLBACK message_handler(
HWND const window,
UINT const message_id,
WPARAM const word_param,
LPARAM const long_param
)
-> LRESULT
{
switch( message_id )
{
case WM_COMMAND: return HANDLE_WM_COMMAND(
window, word_param, long_param, on_wm_command );
case WM_CREATE: return HANDLE_WM_CREATE(
window, word_param, long_param, on_wm_create );
case WM_DESTROY: return HANDLE_WM_DESTROY(
window, word_param, long_param, on_wm_destroy );
}
return DefWindowProc( window, message_id, word_param, long_param );
}
} // namespace main_window
auto register_window_class()
-> Window_class_id
{
WNDCLASS params = {};
params.style = CS_DBLCLKS;
params.lpfnWndProc = main_window::message_handler;
params.hInstance = GetModuleHandle( 0 );
params.hIcon = LoadIcon( 0, IDI_APPLICATION );
params.hCursor = LoadCursor( 0, IDC_ARROW );
params.hbrBackground = reinterpret_cast<HBRUSH>( COLOR_WINDOW );
params.lpszClassName = L"MainWindow_class";
ATOM const id = RegisterClass( ¶ms );
hopefully( id != 0 )
|| fail( "RegisterClass failed" );
return {id};
}
auto create_window( Window_class_id const& class_id )
-> HWND
{
HWND const handle = CreateWindow(
class_id.as_pointer(),
L"Fun run",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 380, 221, // x, y, w, h
0, 0, // parent, menu
GetModuleHandle( 0 ),
0 // lpParam
);
hopefully( handle != 0 )
|| fail( "CreateWindow failed" );
return handle;
}
void cpp_main()
{
Window_class_id const class_id = register_window_class();
HWND const window = create_window( class_id );
ShowWindow( window, SW_SHOWDEFAULT );
int const exit_code = static_cast<int>( dispatch_messages() );
hopefully( exit_code == 0 )
|| fail( "WM_QUIT indicated failure" );
}
auto main() -> int
{
try{ cpp_main(); } catch( ... ) { return E_FAIL; }
return 0;
}
I'm new to C++, and I made myself a little program that can launch program through typing a command on the keyboard. In order to be able to launch a program whenever I want, I decided to set up a Low Level Keyboard Hook, which keep tracking key strokes and launch the specific program when the specific command was detected. The simple windows program was used to install the hook, the windows is not showed because all I need is the hook to listen in the background.
So far it works fine, however, the minor but annoying problem is I have to terminate the program through Windows Task Manager, and it's quite inconvenient. I have managed to uninstall the hook by pressing F7 key, but it seems that the windows program which is not showed is the Parent of the hook, so the hook cannot exit the windows program. While I want them both terminated through pressing a key. Hopefully I have made myself clear.
Is there any way that I could send a message from the hook to the windows program to ask it to exit? Or somehow I can terminate both of them in the hook program?
Thanks in advance.
Here is the code of the window program:
#include <windows.h>
#include "shortcut.h"
#pragma comment( lib, "libhook.dll.a") // Link Hook.lib to the project
long WINAPI WndProc(HWND hWnd, UINT wMessage, WPARAM wParam, LPARAM lParam)
{
switch(wMessage)
{
case WM_DESTROY:
InstallHook(FALSE); // Unhook
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, wMessage, wParam, lParam);
}
return 0;
}
BOOL FileExists(LPCTSTR szPath)
{
DWORD dwAttrib = GetFileAttributes(szPath);
return (dwAttrib != INVALID_FILE_ATTRIBUTES &&
!(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
}
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
{
MSG msg;
WNDCLASS wndclass;
HANDLE hMutex = NULL;
char szAppName[20] = "shortcut";
hMutex = CreateMutex(NULL,TRUE,szAppName); //启动多线程
int dwRet = GetLastError();
if (hMutex)
{
if (dwRet == ERROR_ALREADY_EXISTS)
{
MessageBox(NULL, "Program is already runing.", "Oops!", MB_OK | MB_ICONINFORMATION);
CloseHandle(hMutex);
return FALSE;
}
}
wndclass.style=0;
wndclass.lpfnWndProc=(WNDPROC)WndProc;
wndclass.cbClsExtra=0;
wndclass.cbWndExtra=0;
wndclass.hInstance=hInstance;
wndclass.hIcon=NULL;
wndclass.hCursor=LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground=(HBRUSH)GetStockObject(GRAY_BRUSH);
wndclass.lpszMenuName=NULL;
wndclass.lpszClassName=(LPSTR)szAppName;
if(!RegisterClass(&wndclass))
return FALSE;
if (!FileExists("\\ShortCuts.txt"))
{
MessageBox(NULL, "Missing file: cannot load shortcut settings file.(Shortcuts.txt)", "ERROR",MB_OK|MB_ICONINFORMATION);
exit(1);
}
if (!InstallHook(TRUE))
exit(1);
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
Here is the code of the hook program:
// Hook- a project to create the DLL and LIB files.
// Microsoft Visual C++ 6.0 and above steps:
// 1. Create a new Win32 Dynamic Link - Library project.
// 2. Add hook.cpp and hook.h to the project.
// 3. There is no step 3 :-). Just build your project and you will find
// a Hook.dll and Hook.lib file in your map.
#include <windows.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <ctime>
#include <map>
#include <process.h>
using namespace std;
HHOOK hHook;
HINSTANCE ghDLLInst=0;
const char startChar = ';';
bool bChecking = false;
string cmd;
typedef map<string,string> COMMANDMAP;
COMMANDMAP mShortcut;
string logfilename="log.txt";
ofstream LOG;
__declspec(dllexport)int InstallHook(BOOL bCode);
BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwFunction, LPVOID lpNot)
{
ghDLLInst=(HINSTANCE)hModule;
return TRUE;
}
DWORD WINAPI Runsystem(LPVOID lpParam)
{
WinExec((LPCSTR)lpParam, SW_SHOW);
}
string gettime()
{
time_t curTime;
struct tm *locTime;
char buf[80];
time(&curTime);
locTime=localtime(&curTime);
strftime(buf,80,"%Y-%m-%d %H:%M:%S",locTime);
string s=buf;
return s;
}
ostream& tout()
{
return LOG<< gettime()<< ": ";
}
void StartCheck()
{
bChecking=true;
cmd.clear();
}
void EndCheck()
{
bChecking=false;
cmd.clear();
}
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if ((wParam == WM_KEYDOWN) && (nCode >= HC_ACTION)) // Only record when key pressed
{
KBDLLHOOKSTRUCT *pStruct = (KBDLLHOOKSTRUCT*)lParam;
switch (pStruct->vkCode)
{
case VK_RETURN:
{
if (bChecking)
{
COMMANDMAP::iterator it;
it=mShortcut.find(cmd);
if (it!=mShortcut.end())
{
tout()<<"received command \'"<<cmd<<"\', executing \'"<<it->second.c_str()<<endl;
CreateThread(NULL, 0, Runsystem, (void*)it->second.c_str(),0,NULL);
}
else {
tout()<<"received command \'" <<cmd<<"\', no matching."<<endl;
}
}
EndCheck();
break;
}
case VK_F7:
{
InstallHook(false);
break;
}
default: // Normal keys, convert them
{
BYTE KeyboardState[256];
GetKeyboardState(KeyboardState);
WORD CharValue;
if(ToAscii(pStruct->vkCode, pStruct->scanCode,KeyboardState,&CharValue,0) > 0) // Convert to char.
{
char character=char(CharValue);
// tout()<<"received keyCode: "<<pStruct->vkCode<< " char: "<< character<<endl;
if (bChecking)
{
cmd+=character;
}
if (!bChecking && (character == startChar))
{
// tout()<<"Start checking..."<<endl;
StartCheck();
}
}
break;
}
}
}
return (int)CallNextHookEx(hHook, nCode, wParam, lParam);
}
bool readline(ifstream &fin,string &sline)
{
do
{
getline(fin,sline);
} while (!fin.eof() && ((sline[0]=='/' && sline[1]=='/') || sline.empty()));
return fin.eof()?false:true;
}
// __declspec(dllexport) means that this function must be exported to a dll file.
__declspec(dllexport)int InstallHook(BOOL bCode)
{
if(bCode)
{
// initialize shortcuts
ifstream fin;
LOG.open(logfilename.c_str(),ios_base::app);
tout()<<"Reading config file."<<endl;
fin.open("ShortCuts.txt");
if (fin)
{
string scmd,spath;
char oneline[256];
while(readline(fin,scmd)&&readline(fin,spath))
{
mShortcut[scmd]=spath;
// LOG<<scmd<<','<<spath<<endl;
}
fin.close();
tout()<<"OK, "<<mShortcut.size()<<" shortcuts loaded."<<endl;
}
else
{
tout()<<"ERROR"<<endl;
LOG.close();
exit(0);
}
hHook=(HHOOK)SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)KeyboardProc, // Start the keyboard hook.
(HINSTANCE)GetModuleHandle(NULL), NULL);
if(!hHook)
{
tout()<<"Install hook failed."<<endl;
return 0;
}
else
{
tout()<<"Install hook successful."<<endl;
return 1;
}
}
else
{
if (MessageBox(NULL,"Are you sure to exit KeyShortcut?","Exit",MB_YESNO|MB_ICONWARNING)==IDYES)
{
tout()<<"Uninstall hook successful."<<endl;
LOG.close();
return UnhookWindowsHookEx(hHook); // Unhook the keyboardhook.
}
}
}
For instance, you can use RegisterHotKey API function to set your own hotkey to a system and then handle this hotkey's message in your program(windowless)
Added:
If you want to send quit message from one process to another then your friend is PostThreadMessage(dwThreadId, WM_DESTROY, 0, 0);
I have a problem with EnumDisplayMonitors callbacks. I want to get the number of screens and the screen resolutions of each one. It seems that it's working using this code.
#include <windows.h>
#include <iostream>
#include <vector>
#pragma comment(lib, "user32.lib")
std::vector< std::vector<int> > screenVector;
int screenCounter = 0;
BOOL CALLBACK MonitorEnumProcCallback( _In_ HMONITOR hMonitor,
_In_ HDC hdcMonitor,
_In_ LPRECT lprcMonitor,
_In_ LPARAM dwData ) {
screenCounter++;
MONITORINFO info;
info.cbSize = sizeof(MONITORINFO);
BOOL monitorInfo = GetMonitorInfo(hMonitor,&info);
if( monitorInfo ) {
std::vector<int> currentScreenVector;
currentScreenVector.push_back( screenCounter );
currentScreenVector.push_back( abs(info.rcMonitor.left - info.rcMonitor.right) );
currentScreenVector.push_back( abs(info.rcMonitor.top - info.rcMonitor.bottom) );
std::cout << "Monitor "
<< currentScreenVector.at(0)
<< " -> x: "
<< currentScreenVector.at(1)
<< " y: "
<< currentScreenVector.at(2)
<< "\n";
}
return TRUE;
}
int main() {
BOOL b = EnumDisplayMonitors(NULL,NULL,MonitorEnumProcCallback,0);
system("PAUSE");
return 0;
}
But when I transferred everything to my actual codebase and contained inside a class, it's returning an error. I don't know if I'm doing this right.
-> Here's the snippet:
ScreenManager::ScreenManager() {
BOOL monitorInitialized = EnumDisplayMonitors( NULL, NULL, MonitorEnumProc, reinterpret_cast<LPARAM>(this) );
}
BOOL CALLBACK MonitorEnumProc( HMONITOR hMonitor,
HDC hdcMonitor,
LPRECT lprcMonitor,
LPARAM dwData ) {
reinterpret_cast<ScreenManager*>(dwData)->callback(hMonitor,hdcMonitor,lprcMonitor);
return true;
}
bool ScreenManager::callback(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor){
screenCounter++;
MONITORINFO info;
info.cbSize = sizeof(MONITORINFO);
BOOL monitorInfo = GetMonitorInfo(hMonitor,&info);
if( monitorInfo ) {
std::vector<int> currentScreenVector;
currentScreenVector.push_back( screenCounter );
currentScreenVector.push_back( abs(info.rcMonitor.left - info.rcMonitor.right) );
currentScreenVector.push_back( abs(info.rcMonitor.top - info.rcMonitor.bottom) );
}
return true;
}
I just solved my problem by changing the callback function to public.
I have two classes defined as:
class Control
{
private:
std::vector<int> Info;
public:
Control(..);
virtual ~Control();
LRESULT __stdcall SubClass(HWND Window, UINT Msg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);
};
class Button: public Control
{
//...
};
Control::Control(..)
{
SetWindowSubclass(..., SubClass, ...); //Need to pass member function as callback..
}
LRESULT __stdcall Control::SubClass(HWND Window, UINT Msg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
//Use "Info" data member in here.. thus I cannot have static callback in order to use it.
}
And so I came up with:
class Control
{
private:
std::vector<int> Info;
static LRESULT __stdcall SetCallback(void* ThisPtr) {return static_cast<Control*>(ThisPtr)->SubClass;};
public:
//all the same stuff..
};
Control::Control(..)
{
SetWindowSubclass(..., SetCallback, ...);
}
But the above throws a whole bunch of errors. Is there anyway to either have my static callback access other datamembers OR have my callback non-static?
I do not want to have to do something like the following for every instance created (which I've seen as suggestions all over the internet):
Control F;
F.SetCallback(&F::SubClass, &F); //Externally sets member as callback which I don't want.
I'm trying to keep everything in the constructor or the class itself.
This is probably the most common question when it comes to Win32 API UI programming. See:
http://msdn.microsoft.com/en-us/library/windows/desktop/ff381400(v=vs.85).aspx
Basically the trick is to call SetWindowLongPtr with GWLP_USERDATA as the first parameter and this as the second. Then in the WindowProc callback use GetWindowLongPtr to get it from the HWND.
The following shows how to pass calls to the freestanding message handler function, on to a member function of your C++ object.
It's a lot of code, but normally you would abstract this away in some reusable module, and the most basic stuff is just the little class gui::api_level::window_subclasser_t.
I haven't shown very much error handling, and neither does this code support programmatic destruction of the C++ object via external delete (I think the sane way to do this is to just DestroyWindow the API level window and let that propagate up to self-destruction of the C++ object, but it's many years since last time I did this).
#undef UNICODE
#define UNICODE
#undef NOMINMAX
#define NOMINMAX
#undef STRICT
#define STRICT
#undef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
//#include <windowsx.h>
#include <commctrl.h> // SetWindowSubclass
#include <assert.h> // assert
#include <stdexcept> // std::exception, std::runtime_error
#include <stdlib.h> // EXIT_SUCCESS, EXIT_FAILURE
#include <string> // std::string
#ifndef IS_DELETED
# define IS_DELETED = delete // C++11
#endif
namespace cpp {
using namespace std;
bool hopefully( bool condition ) { return condition; }
bool throw_x( string const& s ) { throw runtime_error( s ); }
} // namespace cpp
namespace winapi {
using cpp::hopefully;
using cpp::throw_x;
bool get( MSG& m )
{
int const code = ::GetMessage( &m, 0, 0, 0 );
hopefully( code >= 0 )
|| throw_x( "winapi::get( MSG ): GetMessage failed" );
return !!code;
}
} // namespace winapi
namespace gui {
using cpp::hopefully;
using cpp::throw_x;
namespace api_level
{
class message_handler_t
{
public:
virtual LRESULT window_proc( MSG const& message ) = 0;
};
LRESULT CALLBACK main_window_subclassproc(
HWND const window,
UINT const message_id,
WPARAM const w_param,
LPARAM const l_param,
UINT_PTR const subclass_id,
DWORD_PTR const data
)
{
(void) subclass_id; struct subclass_id;
auto const p_handler = reinterpret_cast< message_handler_t* >( data );
MSG const message = { window, message_id, w_param, l_param, DWORD(), POINT() };
return p_handler->window_proc( message );
}
class window_subclasser_t
{
private:
enum { subclass_id = 1 };
HWND window_handle_;
window_subclasser_t( window_subclasser_t const& ) IS_DELETED;
window_subclasser_t& operator=( window_subclasser_t const& ) IS_DELETED;
public:
HWND handle() const { return window_handle_; }
LRESULT pass_to_superclass( MSG const& m )
{
return ::DefSubclassProc( m.hwnd, m.message, m.wParam, m.lParam );
}
~window_subclasser_t()
{
::RemoveWindowSubclass(
window_handle_,
&main_window_subclassproc,
subclass_id
)
|| throw_x( "gui::api_level::window_subclass_t::<destroy>(): RemoveWindowSubclass failed" );
}
window_subclasser_t(
HWND const api_window,
message_handler_t* cpp_window
)
: window_handle_( api_window )
{
assert( cpp_window != 0 );
::SetWindowSubclass(
window_handle_,
main_window_subclassproc,
subclass_id,
reinterpret_cast<DWORD_PTR>( cpp_window )
)
|| throw_x( "gui::api_level::window_subclass_t::<init>(): SetWindowSubclass failed" );
}
};
ATOM create_main_window_class()
{
WNDCLASS params = {};
params.hbrBackground = reinterpret_cast<HBRUSH>( COLOR_WINDOW + 1 );
params.hCursor = ::LoadCursor( 0, IDC_ARROW );
params.hIcon = ::LoadIcon( 0, IDI_APPLICATION );
params.hInstance = ::GetModuleHandle( nullptr );
params.lpfnWndProc = &::DefWindowProc;
params.lpszClassName = L"MainWindow";
ATOM const result = ::RegisterClass( ¶ms );
hopefully( result != 0 )
|| throw_x( "gui::api_level::create_main_window_class: RegisterClass failed" );
return result;
}
ATOM main_window_class()
{
static ATOM const the_class = create_main_window_class();
return the_class;
}
HWND create_main_window()
{
HWND const window = ::CreateWindow(
MAKEINTATOM( main_window_class() ),
L"My main window",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
400, 300,
HWND(), // Parent.
HMENU(), // Menu.
::GetModuleHandle( nullptr ),
nullptr // Param.
);
hopefully( window != 0 )
|| throw_x( "gui::api_level::create_main_window: CreateWindow failed" );
return window;
}
} // api_level
class window_t
: private api_level::message_handler_t
{
private:
window_t( window_t const& ) IS_DELETED;
window_t& operator=( window_t const& ) IS_DELETED;
api_level::window_subclasser_t subclasser_;
virtual LRESULT window_proc( MSG const& m ) override
{
switch( m.message )
{
case WM_DESTROY:
delete this;
::PostQuitMessage( 0 );
return 0;
default:
return subclasser_.pass_to_superclass( m );
}
}
protected:
struct api_object_factory_t
{
virtual HWND create() const
{
return api_level::create_main_window();
}
};
virtual ~window_t() {}
window_t( api_object_factory_t const& factory )
: subclasser_( factory.create(), this )
{}
public:
HWND handle() const { return subclasser_.handle(); }
void show() { ::ShowWindow( handle(), SW_SHOW ); }
};
} // namespage gui
// ---------------------------------------------------------------------------------------
// Usage:
class main_window_t
: public gui::window_t
{
public:
main_window_t()
: gui::window_t( api_object_factory_t() )
{}
};
void cpp_main()
{
auto const main_window = new main_window_t();
main_window->show();
MSG msg;
while( winapi::get( msg ) )
{
::TranslateMessage( &msg );
::DispatchMessage( &msg );
}
assert( msg.message == WM_QUIT );
}
#include <iostream>
auto main() -> int
{
using namespace std;
try { cpp_main(); return EXIT_SUCCESS; }
catch( exception const& x ) { wcerr << "!" << x.what() << endl; }
return EXIT_FAILURE;
}
To compile this with Visual C++ 11.0, define the preprocessor symbol IS_DELETED as nothing.
I am using FindWindow in an mfc application.
HWND hWnd = ::FindWindow(NULL, _T("foobar v5"));
I would like to use FindWindow with wildcards so that I can match just foobar.
Thanks
You will have to create your own implementation which should be based on EnumWindows, GetWindowText and GetWindowTextLength which then must allow the wildcards.
#include <Windows.h>
#include <iostream>
#include <string>
#include <vector>
struct FindWindowData {
FindWindowData( TCHAR const * windowTitle )
: WindowTitle( windowTitle )
, ResultHandle( 0 )
{}
std::basic_string<TCHAR> WindowTitle;
HWND ResultHandle;
};
BOOL CALLBACK FindWindowImpl( HWND hWnd, LPARAM lParam ) {
FindWindowData * p = reinterpret_cast<FindWindowData*>( LongToPtr( lParam ) );
if( !p ) {
// Finish enumerating we received an invalid parameter
return FALSE;
}
int length = GetWindowTextLength( hWnd ) + 1;
if( length > 0 ) {
std::vector<TCHAR> buffer( std::size_t( length ), 0 );
if( GetWindowText( hWnd, &buffer[0], length ) ) {
// Comparing the string - If you want to add some features you can do it here
if( _tcsnicmp( &buffer[0], p->WindowTitle.c_str(), min( buffer.size(), p->WindowTitle.size() ) ) == 0 ) {
p->ResultHandle = hWnd;
// Finish enumerating we found what we need
return FALSE;
}
}
}
// Continue enumerating
return TRUE;
}
// Returns the window handle when found if it returns 0 GetLastError() will return more information
HWND FindWindowStart( TCHAR const * windowTitle ) {
if( !windowTitle ) {
SetLastError( ERROR_INVALID_PARAMETER );
return 0;
}
FindWindowData data( windowTitle );
if( !EnumWindows( FindWindowImpl, PtrToLong(&data) ) && data.ResultHandle != 0 ) {
SetLastError( ERROR_SUCCESS );
return data.ResultHandle;
}
// Return ERROR_FILE_NOT_FOUND in GetLastError
SetLastError( ERROR_FILE_NOT_FOUND );
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
std::cout << "HWND: " << FindWindowStart(TEXT("foobar ") );
std::cout << " GetLastError() = " << GetLastError() << std::endl;
return 0;
}
Unfortunately, FindWindow() does not support wildcards.
Did you try matching the window class name instead of its title? You can use a tool like Spy++ to find out the class name of the foobar main window.