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.
Related
I am working on a C++ project based on COM, My Code has a function with an out parameter which takes an object as input and assigns a new instance of a class into it. But when I used CRT Debugging I found some memory leak in the function, Here is the code of the function.
bool __stdcall FluentCompositor::CreateCompositionHost(HWND hwnd, ICompositionHost** compositionHost)
{
if (compositionHost != nullptr)
{
*compositionHost = reinterpret_cast<ICompositionHost*>(new CompositionHost(hwnd));
if (compositionHost != nullptr)
{
return true;
}
}
else
{
return false;
}
return false;
}
This function takes an object of ICompositionHost and initialize it with CompositionHost object, Where should I need to free the memory to avoid memory leak.
I Call the function using ComPtr, but still there is memory leak
ComPtr<ICompositionHost> host;
compositor->CreateCompositionHost(hwnd,host.GetAddressOf());
The Complete Code:
FluentCompositor.cpp
#include "pch.h"
#include "ICompositionHost.h"
#include "IFluentCompositor.h"
#include "CompositionHost.h"
#include "FluentCompositor.h"
FluentCompositor::FluentCompositor() :ref(1)
{
}
ulong __stdcall FluentCompositor::AddRef()
{
return (++ref);
}
ulong __stdcall FluentCompositor::Release()
{
if (--ref == 0)
{
delete this;
return 0;
}
return ref;
}
HRESULT __stdcall FluentCompositor::QueryInterface(REFIID iid, LPVOID* ppv)
{
if (iid == IID_IFluentCompositor || iid == IID_IUnknown)
{
*ppv = (void*)this;
AddRef();
}
else
{
*ppv = NULL;
}
return (*ppv == NULL) ? E_NOINTERFACE : S_OK;
}
HRESULT __stdcall CreateFluentCompositor(void** compositor)
{
if (compositor != nullptr)
{
*compositor = reinterpret_cast<void*>(new FluentCompositor());
if (compositor != nullptr)
{
return S_OK;
}
}
else
{
return E_INVALIDARG;
}
return E_FAIL;
}
bool __stdcall FluentCompositor::CreateCompositionHost(HWND hwnd, ICompositionHost** compositionHost)
{
if (compositionHost != nullptr)
{
*compositionHost = reinterpret_cast<ICompositionHost*>(new CompositionHost(hwnd));
if (compositionHost != nullptr)
{
return true;
}
}
else
{
return false;
}
return false;
}
MainWindow.cpp
#include "pch.h"
#include "MainWindow.h"
int __stdcall wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int)
{
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
const wchar_t className[] = L"Fluent Compositor";
WNDCLASS wc = {
.lpfnWndProc = WndProc,
.hInstance = reinterpret_cast<HINSTANCE>(&__ImageBase),
.hCursor = LoadCursor(nullptr, IDC_ARROW),
.lpszClassName = className,
};
RegisterClass(&wc);
HWND hwnd = CreateWindowEx(WS_EX_NOREDIRECTIONBITMAP, className, L"Fluent Compositor Sample", WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, wc.hInstance, nullptr);
if (hwnd == nullptr)
{
return 0;
}
CreateCompositionEffect(hwnd);
MSG msg = { };
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
_CrtDumpMemoryLeaks();
return 0;
}
bool CreateCompositionEffect(HWND hwnd)
{
auto fluentCompositorLib = LoadLibrary(L"FluentCompositor.dll");
if (!fluentCompositorLib)
{
return false;
}
CreateCompositor = (CreateFluentCompositor)GetProcAddress(fluentCompositorLib, "CreateFluentCompositor");
if (!CreateCompositor)
{
return false;
}
CreateCompositor(&compositor);
if (compositor == nullptr)
{
return false;
}
ComPtr<ICompositionHost> host;
compositor->CreateCompositionHost(hwnd,&host);
return true;
}
LRESULT __stdcall WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
switch (msg)
{
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
}
return DefWindowProc(hwnd, msg, wparam, lparam);
}
MainWindow.h
#pragma once
#include "IFluentCompositor.h"
using namespace Microsoft::WRL;
extern "C" IMAGE_DOS_HEADER __ImageBase;
ComPtr<IFluentCompositor> compositor;
typedef BOOL(__stdcall* CreateFluentCompositor)(IFluentCompositor** compositor);
CreateFluentCompositor CreateCompositor;
bool CreateCompositionEffect(HWND hwnd);
LRESULT __stdcall WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
Your use of reinterpret_cast (and type-casts in general) is simply wrong. If your classes implement the correct interfaces, there is no need to cast them manually (except maybe in QueryInterface()), the compiler will perform the correct conversions implicitly for you.
Also, you are not checking the return value of new correctly. Or, for that matter, handling the possibility that new throws an exception on failure by default, not returns nullptr. If you want a nullptr on falilure, use the nothrow version of new instead.
Also, when using ComPtr, should should be using its overloaded operator& rather than its GetAddressOf() method. Especially if the ComPtr already holds an interface. GetAddressOf() will not release the interface (that is why there is a separate ReleaseAndGetAddressOf() method), but operator& will.
Try this instead:
#include <new>
HRESULT __stdcall FluentCompositor::QueryInterface(REFIID iid, LPVOID* ppv)
{
if (!ppv) return E_POINTER;
if (iid == IID_IFluentCompositor)
{
*ppv = static_cast<IFluentCompositor*>(this);
/* alternatively:
IFluentCompositor *comp = this;
*ppv = comp;
*/
}
else if (iid == IID_IUnknown)
{
*ppv = static_cast<IUnknown*>(static_cast<IFluentCompositor*>(this));
/* alternatively:
IFluentCompositor *comp = this;
IUnknown *unk = comp;
*ppv = unk;
*/
}
else
{
*ppv = nullptr;
}
if (!*ppv)
return E_NOINTERFACE;
AddRef();
return S_OK;
}
// similar for CompositionHost::QueryInterface() ...
HRESULT __stdcall CreateFluentCompositor(void** compositor)
{
if (!compositor) return E_POINTER; // not E_INVALIDARG
// make sure FluentCompositor has a refcount of 1 when created!
*compositor = static_cast<IFluentCompositor*>(new(std::nothrow) FluentCompositor);
return (*compositor) ? S_OK : E_FAIL;
}
bool __stdcall FluentCompositor::CreateCompositionHost(HWND hwnd, ICompositionHost** compositionHost)
{
if (!compositionHost) return false;
// make sure CompositionHost has a refcount of 1 when created!
*compositionHost = new(std::nothrow) CompositionHost(hwnd);
return (*compositionHost);
}
ComPtr<ICompositionHost> host;
compositor->CreateCompositionHost(hwnd, &host);
Alternatively, consider using ComPtr internally when creating your objects, eg:
#include <new>
HRESULT __stdcall CreateFluentCompositor(void** compositor)
{
if (!compositor) return E_POINTER; // not E_INVALIDARG
// make sure FluentCompositor has a refcount of 0 when created,
// as the ComPtr constructor will increment it!
ComPtr<IFluentCompositor> obj(new(std::nothrow) FluentCompositor);
return (obj) ? obj->QueryInterface(IID_IFluentCompositor, compositor) : E_FAIL;
}
bool __stdcall FluentCompositor::CreateCompositionHost(HWND hwnd, ICompositionHost** compositionHost)
{
// make sure CompositionHost has a refcount of 0 when created,
// as the ComPtr constructor will increment it!
ComPtr<ICompositionHost> obj(new(std::nothrow) CompositionHost(hwnd));
return ((obj) && (obj->QueryInterface(IID_ICompositionHost, reinterpret_cast<void**>(compositionHost)) == S_OK));
}
It is a good idea to have your objects start with a reference count of 0 rather than 1, because they don't know if they are going to be used with interface pointers or object pointers (if they are even used with pointers at all). Don't increment an object's reference count unless it is actually assigned to an interface pointer that is AddRef()'ed and needs to be Release()'d.
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 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 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;
}
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.