How do i extract dragged & dropped filenames from a DROPFILES struct - c++

I have a window with no controls with WS_EX_ACCEPTFILES enabled and the event triggers successfully when dragging files from explorer. What I need to do is extract the files to a vector. From what I've read, the wParam is supposed to contain the location of the files within a DROPFILES struct but I don't know how to access them.
LRESULT CALLBACK StaticWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR
uIdSubclass, DWORD_PTR dwRefData)
{
if (uMsg == WM_DROPFILES)
{
// extract files here
vector<string> files;
}
return DefSubclassProc(hwnd, uMsg, wParam, lParam);
}
I don't need to send them to any controls since my window is for an openGL application, I just need to retain them in a list, how can it be done?

Per the WM_DROPFILES documentation:
Parameters
hDrop
A handle to an internal structure describing the dropped files. Pass this handle to DragFinish, DragQueryFile, or DragQueryPoint() to retrieve information about the dropped files.
lParam
Must be zero.
Simply type-cast the wParam to HDROP and call the drag-drop functions as needed, eg:
LRESULT CALLBACK StaticWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
if (uMsg == WM_DROPFILES)
{
HDROP hDrop = reinterpret_cast<HDROP>(wParam);
// extract files here
vector<string> files;
char filename[MAX_PATH];
UINT count = DragQueryFileA(hDrop, -1, NULL, 0);
for(UINT i = 0; i < count; ++i)
{
if (DragQueryFileA(hDrop, i, filename, MAX_PATH))
files.push_back(filename);
}
DragFinish(hDrop);
return 0;
}
return DefSubclassProc(hwnd, uMsg, wParam, lParam);
}
Alternatively:
LRESULT CALLBACK StaticWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
if (uMsg == WM_DROPFILES)
{
HDROP hDrop = reinterpret_cast<HDROP>(wParam);
// extract files here
vector<string> files;
string filename;
UINT count = DragQueryFileA(hDrop, -1, NULL, 0);
for(UINT i = 0; i < count; ++i)
{
UINT size = DragQueryFileA(hDrop, i, NULL, 0);
if (size > 0)
{
filename.resize(size);
DragQueryFileA(hDrop, i, &filename[0], size+1);
files.push_back(filename);
}
}
DragFinish(hDrop);
return 0;
}
return DefSubclassProc(hwnd, uMsg, wParam, lParam);
}

Related

How to distinguish if a window is being activated by mouse click?

I'm currently hooking window activations with the following code:
extern "C" __declspec(dllexport) LRESULT CALLBACK CBTProc(
_In_ int nCode,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
if (nCode < 0) return CallNextHookEx(nullptr, nCode, wParam, lParam);
HWND hwnd = reinterpret_cast<HWND>(wParam);
switch (nCode)
{
case HCBT_ACTIVATE: // The system is about to activate a window.
{
return 0; // 0 - Allow 1 - Deny
}
}
return 0;
From the docs:
https://learn.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms644977(v=vs.85)
lParam
Specifies a long pointer to a CBTACTIVATESTRUCT structure containing the handle to the active window and specifies whether the activation is changing because of a mouse click.
How I could interpret the value of lParam and distinguish it?
As the documentation says, for HCBT_ACTIVATE the lParam specifies a pointer to a CBTACTIVATESTRUCT, so simply typecast it accordingly, just like you are doing with the wParam, eg:
extern "C" __declspec(dllexport) LRESULT CALLBACK CBTProc(
_In_ int nCode,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
if (nCode < 0) return CallNextHookEx(nullptr, nCode, wParam, lParam);
switch (nCode)
{
case HCBT_ACTIVATE: // The system is about to activate a window.
{
HWND hwnd = reinterpret_cast<HWND>(wParam);
CBTACTIVATESTRUCT* cbt = reinterpret_cast<CBTACTIVATESTRUCT*>(lParam);
// use hwnd, cbt->fMouse, and cbt->hWndActive as needed...
return 0; // 0 - Allow 1 - Deny
}
}
return 0;
}

How to create a window placeholder in the dialog editor

I apologize if I'm overlooking something, but I'm trying to just create a placeholder window within an ATL dialog, which will be used to host a preview handler. I thought placing a custom control might be the thing to do, since it's blank and would occupy a designated place, but that's causing the dialog to crash, and I get the feeling doing something with a custom control is more complicated than I'm looking for. So is there a way to just put a dummy window inside a dialog for use as a host site? Thanks for any input.
Update: I seem to have achieved the desired result using a simple blank picture control. But I'm still wondering if there's a more official way of doing this.
for placeholder we need use exactly custom control. the point - need specify window class name. and this class must be registered.
let name of class will be MyClass
so in .rc file must be
CONTROL "Custom1",IDC_CUSTOM1,"MyClass",...
and we need register "MyClass", minimal code
class MyWndCls
{
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_NCDESTROY:
delete this;
break;
}
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
}
static LRESULT CALLBACK _WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return reinterpret_cast<MyWndCls*>(GetWindowLongPtrW(hwnd, GWLP_USERDATA))->WindowProc(hwnd, uMsg, wParam, lParam);
}
static LRESULT CALLBACK StartWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg == WM_NCCREATE)
{
if (MyWndCls* p = new MyWndCls)
{
SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR)p);
SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)_WindowProc);
return p->WindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
}
inline static const WCHAR clsname[] = L"MyClass";
public:
static ULONG Register()
{
WNDCLASS wndcls = {
0, StartWindowProc, 0, 0, (HINSTANCE)&__ImageBase, 0,
LoadCursorW(0, IDC_HAND), (HBRUSH)(COLOR_INFOBK + 1), 0, clsname
};
return RegisterClassW(&wndcls) ? NOERROR : GetLastError();
}
static ULONG Unregister()
{
return UnregisterClassW(clsname, (HINSTANCE)&__ImageBase) ? NOERROR : GetLastError();
}
};
of course we need call MyWndCls::Register(); before create any dialog with this custom control

Call non-static member from WndProc

Anyone know how to call non-static member from WndProc?
Here is my WndProc prototype:
LRESULT CALLBACK System::Windows::Forms::Control::WndProc(HWND hWnd,
UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
this->OnCreate(new EventArgs(hWnd, message, wParam, lParam));
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
}
return 0;
}
And defination:
class LIBMANAGED_API Control
{
protected:
HWND hWnd;
static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
...
};
This is wrong on so many levels. What do you really want to achieve? Just from this piece of code, there's not enough info.
First, you declare this method using a mixture of C and managed C++. It either
protected virtual void WndProc(Message m) // Managed C++
as you see, NOT static method, LRESULT, HWND and so on, or
LRESULT CALLBACK WindowProc(
_In_ HWND hwnd,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
as you can see, no System namespace.
Second, where are your clases defined? I suspect you should override your method, using Managed C++, see MSDN.
You were not that far as you are already processing the WM_CREATE message.
The trick is to pass an object pointer at creation time and store it in the Window itself with SetWindowLongPtr in the WM_CREATE or WM_NCCREATE message. The you can extract it with GetWindowLongPtr and access your object from the window procedure.
Window creation (say MyWnd myWnd is the C++ object that will represent the window):
HWND hWnd = CreateWindow( m_pszClassName, "Name", WS_VISIBLE | WS_OVERLAPPED,
x, y, w, h, NULL, NULL, hInst, &myWnd);
Window procedure:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
MyWnd *myWnd;
myWnd = (MyWnd *) GetWindowLongPtr(hWnd, GWLP_USERDATA); /* to use it outside WM_CREATE */
switch (message)
{
case WM_CREATE:
CREATESTRUCT * pcs = (CREATESTRUCT*)lParam;
MyWnd* myWnd= (MyWnd*) pcs->lpCreateParams;
SetWindowLongPtr( hwnd, GWLP_USERDATA, (LONG_PTR) myWnd);
myWnd->OnCreate(new EventArgs(hWnd, message, wParam, lParam));
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
}
return 0;
}

How to handle Enter key in Win32 multiline Edit control?

I have a multiline Edit control that allow to multiline text from other source (i.e copy/paste,...) but I don't want to allow user have new line by press Enter key directly.
How can I handle Enter key in this case? Thank!
You can do this with a simple sub-class of the edit control that blocks the return key:
LRESULT CALLBACK EditSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
if (uMsg == WM_CHAR && wParam == VK_RETURN)
return 0;
LRESULT lRes = DefSubclassProc(hWnd, uMsg, wParam, lParam);
if (uMsg == WM_DESTROY)
RemoveWindowSubclass(hWnd, EditSubclassProc, 0);
return lRes;
}
To invoke it:
SetWindowSubclass(hWndEdit, EditSubclassProc, 0, 0);

Handling windows messages from a subclass

I have custom window encapsulated in a class with a static WndProc function to handle messages generated by it. Now I have a child class which implements some of the features in message handling proc differently then the parent class.
For example in the code below, what happens in WM_LBUTTONDOWN in the child class is different then what happens in the parent class.
I thought about polymorphism, but I think it won't work since the ::SetWindowLongPtr() is called from the parent class and "this" pointer passed to belongs to the parent class, correct me if I am wrong.
And if I am wrong and polymorphism will work in this case then too there are some messages which are not handled by the parent class and should be handled in the child class and putting an empty virtual function in the parent class just for that doesn't seems clean, beside its hard to put an empty virtual function for each and every message that window produce just for the sake of if in future it will be used.
There going to be several such child classes each one of them behaving differently for some messages but not all.
So, how should I go about doing it.
parent.cpp
parent::parent()
{
WNDCLASSEX wincl;
wincl.hInstance = hInstance;
wincl.lpszClassName = "parent";
wincl.lpfnWndProc = WndProc;
wincl.style = CS_BYTEALIGNWINDOW;
wincl.cbSize = sizeof (WNDCLASSEX);
wincl.hIcon = 0;
wincl.hIconSm = 0;
wincl.hCursor = ::LoadCursor (NULL, IDC_ARROW);
wincl.lpszMenuName = NULL;
wincl.cbClsExtra = 0;
wincl.cbWndExtra = 4;
wincl.hbrBackground = ::CreateSolidBrush( backgroundColor );
::RegisterClassEx ( &wincl );
hwnd = ::CreateWindowEx ( 0, "parent", txt.c_str(), WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_CHILD, x, y, width, height, parent, 0, hInstance, 0 ) ;
::SetWindowLongPtr( hwnd , GWLP_USERDATA , ( LONG ) this ) ;
}
LRESULT CALLBACK parent::WndProc ( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
{
view::parent* panel = reinterpret_cast < view::parent* > ( ::GetWindowLongPtr ( hwnd , GWLP_USERDATA ) );
switch (message)
{
case WM_CREATE:
::SendMessage ( hwnd, WM_SETFONT, ( WPARAM ) panel->hFont, ( LPARAM ) true );
break ;
case WM_COMMAND:
return panel->command ( message, wParam, lParam );
break ;
case WM_LBUTTONDOWN:
return panel->lButton ( message, wParam, lParam );
break;
case WM_RBUTTONDOWN:
return panel->rButton ( message, wParam, lParam );
break;
case WM_ERASEBKGND:
return 1;
break;
case WM_PAINT:
return panel->paint ( );
break ;
default:
return ::DefWindowProc (hwnd, message, wParam, lParam);
}
return 0 ;
};
Thanks.
Try something like this:
class parent
{
private:
// ...
static LRESULT CALLBACK WndProcCallback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
protected:
HWND m_hwnd;
// ...
virtual LRESULT WndProc(UINT message, WPARAM wParam, LPARAM lParam);
virtual LRESULT DefWndProc(UINT message, WPARAM wParam, LPARAM lParam);
virtual LRESULT command(WPARAM wParam, LPARAM lParam);
virtual LRESULT lButtonDown(WPARAM wParam, LPARAM lParam);
virtual LRESULT rButtonDown(WPARAM wParam, LPARAM lParam);
virtual LRESULT paint();
// ...
public:
parent();
virtual ~parent();
// ...
};
parent::parent()
{
WNDCLASSEX wincl = {0};
wincl.hInstance = hInstance;
wincl.lpszClassName = "parent";
wincl.lpfnWndProc = WndProcCallback;
wincl.style = CS_BYTEALIGNWINDOW;
wincl.cbSize = sizeof(WNDCLASSEX);
wincl.hIcon = 0;
wincl.hIconSm = 0;
wincl.hCursor = ::LoadCursor(NULL, IDC_ARROW);
wincl.lpszMenuName = NULL;
wincl.cbClsExtra = 0;
wincl.cbWndExtra = 4;
wincl.hbrBackground = ::CreateSolidBrush(backgroundColor);
::RegisterClassEx(&wincl);
m_hwnd = NULL;
::CreateWindowEx(0, "parent", txt.c_str(), WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_CHILD, x, y, width, height, parent, 0, hInstance, this);
}
parent::~parent()
{
if (m_hwnd)
DestroyWindow(m_hwnd);
}
LRESULT CALLBACK parent::WndProcCallback(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
parent* panel;
if (message == WM_CREATE)
{
CREATESTRUCT *cs = reinterpret_cast<CREATESTRUCT*>(lParam);
panel = static_cast<parent*>(cs->lpCreateParams);
panel->m_hwnd = hwnd;
::SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(panel));
}
else
panel = reinterpret_cast<parent*>(::GetWindowLongPtr(hwnd, GWLP_USERDATA));
if (panel)
return panel->WndProc(message, wParam, lParam);
return ::DefWindowProc(hwnd, message, wParam, lParam);
}
LRESULT parent::WndProc(UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
::SendMessage(m_hwnd, WM_SETFONT, (WPARAM) hFont, TRUE);
break ;
case WM_COMMAND:
return command(wParam, lParam);
break ;
case WM_LBUTTONDOWN:
return lButtonDown(wParam, lParam);
break;
case WM_RBUTTONDOWN:
return rButtonDown(wParam, lParam);
break;
case WM_ERASEBKGND:
return 1;
break;
case WM_PAINT:
return paint();
break;
}
return DefWndProc(message, wParam, lParam);
}
LRESULT parent::DefWndProc(UINT message, WPARAM wParam, LPARAM lParam)
{
return ::DefWindowProc(m_hwnd, message, wParam, lParam);
}
LRESULT parent::command(WPARAM wParam, LPARAM lParam)
{
return DefWndProc(WM_COMMAND, wParam, lParam);
}
LRESULT parent::lButtonDown(WPARAM wParam, LPARAM lParam)
{
return DefWndProc(WM_LBUTTONDOWN, wParam, lParam);
}
LRESULT parent::rButtonDown(WPARAM wParam, LPARAM lParam)
{
return DefWndProc(WM_RBUTTONDOWN, wParam, lParam);
}
LRESULT parent::paint()
{
return 0;
}
Not only does this embrace polymorphism and encapsulation, but making WndProc() itself virtual allows derived classes to override behavior for any received message (well, any message received after WM_CREATE that is), especially messages the parent has no concept of:
class child : public parent
{
protected:
LRESULT WndProc(UINT message, WPARAM wParam, LPARAM lParam);
};
LRESULT child::WndProc(UINT message, WPARAM wParam, LPARAM lParam)
{
if (message == WM_SOMETHING)
{
// ...
return 0;
}
return parent::WndProc(message, wParam, lParam);
}