Retrieve WTL object from handle - c++

I had to rewrite a custom file dialog (derived from MFC's CFileDialog) to WTL's CFileDialog. I have a bit of a problem to retrieve data when I don't have access to the dialog object itself. Imagine the following.
I have a member in the class
static WNDPROC m_wndProc;
I initialize it in the following static member fnct.
void CMyFileDialog::OnInitDone(LPOFNOTIFY lpon)
{
m_wndProc = (WNDPROC)::SetWindowLong(thisHWND, GWL_WNDPROC, reinterpret_cast<long>
(&CMyFileDialog::WndProcSelect));
}
The handle comes into the callback method with no problem and I can "connect" to it with CWindow
LRESULT CALLBACK CMyFileDialog::WndProcSelect(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
// ...
CWindow callerWnd(hwnd);
}
And here, I don't know the real methodology to convert the CWindow to my CMyFileDialog. As I think, this CWindow class is just connected somehow to the handle itself, but does not the same object as it was created before. So for example, if I have a CString or other members in my CMyFileDialog, it won't access its state, because it was created in another object.

I think you are doing something wrong here. You have access to the message map without having to modify the WndProc (that is something that the CFileDialogImpl will have already done).
See for example http://www.codeproject.com/Articles/12999/WTL-for-MFC-Programmers-Part-IX-GDI-Classes-Common#usingcfiledialog, where they simply
BEGIN_MSG_MAP(CMyFileDialog)
CHAIN_MSG_MAP(CFileDialogImpl<CMyFileDialog>)
END_MSG_MAP()

You could always use SetWindowLongPtr with your "this" pointer, then it would be fairly easy to extract the pointer to your CMyFileDialog.

Related

Is there a solution for this case?

This is a Windows Desktop Application project created by Visual Studio.
I have a Dialog resource created from the Resource View that has a Static Text.
I'm using this dialog in order to show errors to the user:
DialogBox(hInst, MAKEINTRESOURCE(IDD_MY_MESSAGE_BOX), hWnd, MyMessageBoxProc);
The reason I'm using a DialogBox is that I need it to stop the code execution, because the next line of code will close the application I mean the user should be aware of the error message before application exits. I know a way to change the Static Text:
HWND myMessageBox = CreateDialog(hInst, MAKEINTRESOURCE(IDD_MY_MESSAGE_BOX), nullptr, MyMessageBoxProc);
HWND staticText = GetDlgItem(myMessageBox, IDC_STATIC);
SetWindowText(staticText, L"Text changed.");
But that approach doesn't stop code execution.
Since it's a Windows Desktop Application project I cannot create MFC classes and try the following approach:
// Find the Static Text.
// If called from within MyMessageBox class.
CWnd *staticText = GetDlgItem(IDC_STATIC);
staticText->SetWindowText("Text changed.");
// If called from elsewhere.
MyMessageBox myMessageBox;
CWnd *staticText = myMessageBox.GetDlgItem(IDC_STATIC);
staticText->SetWindowText("Text changed.");
So what would be a workaround in order to change the Static Text using a DialogBox without the need of MFC classes or even another approach that allows me to change the Static Text and still stop code execution like a DialogBox.
Just change the text in your window procedure (MyMessageBoxProc) by handling WM_INITDIALOG message. If you wish to supply the text to the dialog, then create it using DialogBoxParam instead, which is then accessible via the lParam parameter.
e.g.
INT_PTR MyMessageBoxProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (message == WM_INITDIALOG) {
HWND hCtrl = GetDlgItem(hWnd, IDC_STATIC);
SetWindowText(hCtrl, reinterpret_cast<LPCTSTR>(lParam));
}
return FALSE;
}
The creation would be something like:
LPCTSTR text = _T("Text changed.");
DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_MY_MESSAGE_BOX), hWnd, MyMessageBoxProc,
reinterpret_cast<LPARAM>(text));
Note that there is a standard message box that ships with windows, which you may want to use instead of writing your own. That's available via the function MessageBox

How to pass class instance to LowLevelMouseProc?

I am implementing logic to handle global mouse clicks and I stuck at moment where I need to get data from LowLevelMouseProc. Currently, I am setting global variable at point when I am creating instance of MyClass and I able to access it from LowLevelMouseProc, but I suppose that isn't right approach.
Setting hook:
g_myClass = this;
SetWindowsHookEx(WH_MOUSE_LL, MyClass::MouseHookProc, LoadLibraryA("user32.dll"), 0);
LowLevelMouseProc:
LRESULT CALLBACK MyClass::MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam) {
MOUSEHOOKSTRUCT * pMouseStruct = (MOUSEHOOKSTRUCT *)lParam;
g_myClass.onClick(wParam, pMouseStruct->pt.x, pMouseStruct->pt.y); //isn't good
}
The low level mouse hook offers no mechanism by which you can retrieve an instance pointer. Using a global variable is often the best option.
If you cannot make your program work that way you will need to use a thunk. That technique has been discussed in many places and a web search will provide more detail. For instance a cursory search on my part yielded this: http://zabkat.com/blog/hook-callback-thunk-x64.htm

How to access Mainfrm member variable status without using ((CMainFrame*) AfxGetMainWnd ())->...?

I have a MDI appliation in MFC to modify. I want to check the value of a flag which is a member variable of MainFrm from a lower level class. But I don't want to access it using
'((CMainFrame*) AfxGetMainWnd ())->IsFlagOn()' kind of function because for that i have to give the mainfrm.h in a lower level class. I somehow feel this will create some circular reference later, after reading this Why are circular references considered harmful?
what are the other ways to get the flag value from mainfrm class.Please guide !
note: here class hierarchy is mainfrm->CTestExplorerFrame->CTestExplorerView->CTestExplorerTreeCtrl
I want to check from the lowest level about a flag that is only accessed by mainfrm
AfxGetMainWnd() returns a CWnd* that you can use to communicate with the mainframe via the Windows message system. Define a custom message and send this message to the CWnd*
#define UWM_MYREQUEST (WM_APP + 2)
int datatoget;
CWnd* pMainframe = AfxGetMainWnd();
pMainframe->SendMessage(UWM_MYREQUEST, (WPARAM)&datatoget, 0);
The mainframe needs code like this to receive and handle the custom message:
ON_MESSAGE(UWM_MYREQUEST, OnMyRequest)
LRESULT CMainFrame::OnMyRequest(WPARAM wparam, LPARAM lparam)
{
int* ptoget = (int*)wparam;
*ptoget = m_datarequested;
return 0;
}
I would declare an (pure virtual) interface class where you have a pure virtual call to get the value of the flag you are interested in at CTestExplorerTreeCtrl. Then the MainFrame implements this interface class and passes a pointer to CTestExplorerTreeCtrl. This way you can avoid any references to the MainFrame class.

SetWindowLongPtr doesnt work properly

I want to subclass RichEdit in my program (here is c++ code: http://dumpz.org/46182/). _native_log is a hwnd of richedit. At first all works fine and LogWindow::wndProc callback called normal, but if i set some text in RichEdit or click on them LogWindow::wndProc stops work (there no any further calls of it). Is there any thoughts what's i do wrong?
void LogWindow::replaceNativeLog(HWND native_log_handle) {
_native_log = native_log_handle;
SendMessage(_native_log, EM_GETOLEINTERFACE, 0, (LPARAM) &_rich_edit_ole);
_old_wnd_proc = (WNDPROC) SetWindowLongPtr(_native_log, GWLP_WNDPROC, (LONG) &wndProc);
}
LRESULT LogWindow::wndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) {
switch (Msg) {
case EM_STREAMIN:
break;
case WM_SETTEXT:
break;
};
return CallWindowProc(_old_wnd_proc, _native_log, Msg, wParam, lParam);
}
Starting with Common Controls version 6 the procedure of subclassing windows has been revised to eliminate the issues with previous versions. In particular it is no longer a problem if a control is subclassed more than once.
A comparison between subclassing pre-v6 Common Controls and the v6 way of doing things can be found at "Subclassing Controls". Instead of calling SetWindowLongPtr to replace the window procedure there is SetWindowSubclass which in addition to replacing the window procedure does all the internal bookkeeping. A consequence of the redesign is that you do not have to store a pointer to the previous window procedure either; if you need to call into the original window procedure there is DefSubclassProc at your disposal.
This of course will only help if all competing clients trying to subclass the a control all agree on using the v6 style subclassing.
Finally, I found the problem. I actually develop a plugin for Miranda IM, and there was another function trying to subclass richedit i want. So there is a kind of conflict between my and that functions. Thanks all for trying to help.

CEdit, WM_PASTE

let's say I've got a handler of the wm_paste message in a CEdit descendant:
LRESULT CMyEdit::OnPaste(WPARAM wParam, LPARAM lParam)
{
//do some processing
return 0;
}
and let's say that in some cases I want to trigger the default behaviour for paste
from this method. How do I do it? CEdit::OnPaste does not exist...
Cheers
Call CWnd::DefWindowProc, passing it WM_PASTE, wParam and lParam.
Typically the OnXxx handlers in base classes consist of a single line that calls DefWindowProc -- if CEdit::OnPaste existed, that's what it would do.
You can also simply call CWnd::Default. This function, which is defined in wincore.cpp, uses _afxThreadState.GetData() to obtain the information on the message that is currently being processed and then calls CWnd::DefWindowProc.
I mention that because if you used the ON_WM_PASTE() macro in the message map and thus have no parameters to the OnPaste function then the solution mentioned by Tim Robinson will not work since there are no wParam and lParam parameters to pass to CWnd::DefWindowProc.