|
Thanks
My DoModal is being called from
My CMainFrame once returning to DoModal via EndDialog the Dialog box is destroyed but the class/object is still around ( I created the modal Dialog on the stack ) so the data in the class is still available until I exit the CMainFrame Routine
Also the only way to have a bad return code from UpdateData is to call pDx->fail which has the side effect of an exception which I would have to delete. if everything is okay I just call EnDialog notifying the CMainFrame which called DoModal of my selection
Thanks
|
|
|
|
|
Hi,
I am happy to hear that you have it working.
ForNow wrote: Also the only way to have a bad return code from UpdateData is to call pDx->fail which has the side effect of an exception which I would have to delete. if everything is okay I just call EndDialog notifying the CMainFrame which called DoModal of my selection
OK, let me know if you have any problems here. But from what you've described it sounds like the desired outcome.
Best Wishes,
-David Delaune
|
|
|
|
|
only one Issue UpdateData seems to always return TRUE even if I call pDX->fail
maybe I should set a global BOOL in my Modal Dialog Class and bypass checking return code from UpdateData
Thanks
|
|
|
|
|
ForNow wrote: only one Issue UpdateData seems to always return TRUE
That means UpdateData() succeeded. Can you explain to me why you need UpdateData to fail?
ForNow wrote: even if I call pDX->fail
With my experience I am going to make a strong inference that your pDX variable is a pointer to a CDataExchange object. Can you explain to me why you need this to fail? If this fails a runtime error will be thrown... I can't even think of a valid reason you would want this.
The source for UpdateData() is inside wincore.cpp and you will find that the UpdateData() function constructs a new CDataExchange object and attaches it to your Cwnd object and performs DDX through there.
In other words... your line of code inside your class:
pDX->Fail();
You should to open [Your Visual Studio Path]\VC\atlmfc\src\mfc\wincore.cpp and scroll down to the Updatedata() implementation where you will immediately understand why UpdateData() always returns TRUE; It creates a new CDataExchange object inside the function. You cannot force UpdateData() to fail by manipulating an external object.
Best Wishes,
-David Delaune
|
|
|
|
|
ForNow wrote: only one Issue UpdateData seems to always return TRUE even if I call pDX->fail
maybe I should set a global BOOL in my Modal Dialog Class and bypass checking return code from UpdateData
Why do you need the "return code from UpdateData"?
Why do you need the UpdateData at all? There was a great essay about Avoid UpdateData of Joe Newcomer. I'd recommend you to check it out!
|
|
|
|
|
Hi Victor,
I've been meaning to tell you that I am happy to see you have finally moved over here from CodeGuru. I followed Chris over to his new site some 18+ years ago soon after Zafir Anjum sold codeguru and I rarely go back to the old site anymore.
Victor Nijegorodov wrote: Why do you need the UpdateData at all? There was a great essay about Avoid UpdateData of Joe Newcomer. I'd recommend you to check it out!
Actually in this case he may need to call UpdateData() because he is bypassing both the CWnd::OnOk and also exiting the dialog with EndDialog(SOME_RADIO_ID); With that knowledge go and read the final two paragraphs in the debate between Doug Harrison and Dr. Newcomer.
If we are going to suggest that the poster "ForNow" avoid using UpdateData() then we need to ensure that he is using control variables.
Best Wishes,
-David Delaune
P.S.
I haven't used MFC in nearly 10 years, not sure why I even remember these things.
|
|
|
|
|
Greetings.
I'm a newbie here and also into C++ programming but I would like to say this is a very helpful site to watch and learn and I would like to thank to all you out there for sharing your knowledge.
As part of my interests about C++ and COM objects I was looking some tutorials and I have found this one nicely done:
COM from scratch - PART TWO[^]
I'm trying to re-create the client part of the improved example but it's not working. When I tried to do some debugging I was looking at some values and I've found this:
hr=-2147221164
Looking for some explanation I made some research and I understood that -among other things- this might be happening because of some uninitialized pointers, but I tried that suggestion and still no luck with MSVS 2008 and this simple code for a client-server application.
void main()
{
HRESULT hr;
IUnknown* pIUnknown;
IComponent* pIComponent;
IClassFactory* pIClassFactory;
::CoInitialize(NULL);
hr=CoGetClassObject(CLSID_Component,CLSCTX_INPROC_SERVER,
NULL,IID_IClassFactory,(void**)&pIClassFactory);
if (SUCCEEDED(hr))
{
hr=pIClassFactory->CreateInstance(NULL,
IID_IComponent,(void**)&pIComponent);
if(SUCCEEDED(hr))
pIComponent->Print("COM from scratch.");
}
::CoUninitialize ();
}
What could be the reason(s) this
hr variable is returning that value and how to fix it? Thank you in advance
|
|
|
|
|
Perhaps there is something useful in this[^] thread.
"the debugger doesn't tell me anything because this code compiles just fine" - random QA comment
"Facebook is where you tell lies to your friends. Twitter is where you tell the truth to strangers." - chriselst
"I don't drink any more... then again, I don't drink any less." - Mike Mullikins uncle
|
|
|
|
|
Hey, thank you very much for that fast reply.
I saw that discussion and I see all those errors are related to a poor server registration. In my case, I double checked that my server is registered when I was doing some debugging. If you see the paths provided in the sources there is certainly something like this:
REGEDIT
HKEY_CLASSES_ROOT\Codeproject.Component.1 =
Codeproject Component Version 1.0
HKEY_CLASSES_ROOT\Codeproject.Component.1\CLSID =
{49BF12F1-5041-48da-9B44-AA2FAA63AEFB}
HKEY_CLASSES_ROOT\Codeproject.Component = Codeproject Component
HKEY_CLASSES_ROOT\Codeproject.Component\CurVer = Codeproject.Component.1
HKEY_CLASSES_ROOT\CLSID\{49BF12F1-5041-48da-9B44-AA2FAA63AEFB} =
Codeproject Component 1.0
HKEY_CLASSES_ROOT\CLSID\{49BF12F1-5041-48da-9B44-AA2FAA63AEFB}\InprocServer32 =
c:\codeproject\component.dll
HKEY_CLASSES_ROOT\CLSID\{49BF12F1-5041-48da-9B44-AA2FAA63AEFB}\ProgID =
Codeproject.Component.1
HKEY_CLASSES_ROOT\CLSID\{49BF12F1-5041-48da-9B44-AA2FAA63AEFB}\
VersionIndependentProgID = Codeproject.Component
All my entries are OK with my server registered so I suppose the problem is somewhere but I can't find it because my lack of expertise. Looking at the MSDN/documentation the value expected should be one of these:
S_OK
Location and connection to the specified class object was successful.
REGDB_E_CLASSNOTREG
The CLSID is not properly registered. This error can also indicate that the value you specified in dwClsContext is not in the registry.
E_NOINTERFACE
Either the object pointed to by ppv does not support the interface identified by riid, or the QueryInterface operation on the class object returned E_NOINTERFACE.
REGDB_E_READREGDB
There was an error reading the registration database.
CO_E_DLLNOTFOUND
Either the in-process DLL or handler DLL was not found (depending on the context).
CO_E_APPNOTFOUND
The executable (.exe) was not found (CLSCTX_LOCAL_SERVER only).
E_ACCESSDENIED
There was a general access failure on load.
CO_E_ERRORINDLL
There is an error in the executable image.
CO_E_APPDIDNTREG
The executable was launched, but it did not register the class object (and it may have shut down).
and not that negative value
hr=-2147221164
What could be happening with this variable
hr if all variables/pointers are initialized and the server/COM Object is well registered with its CLSID for a Win32 app target?
|
|
|
|
|
From MSDN:
Quote: REGDB_E_CLASSNOTREG
0x80040154
Class not registered
Haven't you registered it?
Or did you mix something related 32/64bit?
|
|
|
|
|
Hey Victor, nice to see you around.
Yes, I have registered the server. First, I did it with the script provided by the tutorial (you may take a look at my previous messages), then I made a double check manually comparing the registry entries and it was running perfectly. I'm using for this project MSVS 2008 to avoid problems because the tutorial is very old (2004) and everything is kind of mandatory with the Win32 target (no x64 builds). I'm confused, if not registered (but it is), I should get the something like this
REGDB_E_CLASSNOTREG
This is ackward for
hr=-2147221164 and a successful server/COM Object registration.
|
|
|
|
|
It is not a negative integer, it is a hexadecimal status code. Convert it to its proper value and you can see what it represents.
|
|
|
|
|
And get into the habit of doing that all the time also.
|
|
|
|
|
I have been, for more than 20 years.
|
|
|
|
|
I don't know how to fix it, but you can find ot more about the error code by converting it to hex (e. g. with the Windows calculator:
-2147221164 corresponds to 0x80040154
Then go to this page[^] to find this code and look up its meaning:
This error code is listed as REGDB_E_CLASSNOTREG , which means "Class not registered."
[edit]
P.S.: Only now I see that this is what you've been discussing with Victor above. Sometimes I'm blind....
[/edit]
GOTOs are a bit like wire coat hangers: they tend to breed in the darkness, such that where there once were few, eventually there are many, and the program's architecture collapses beneath them. (Fran Poretto)
modified 1-Jul-19 9:05am.
|
|
|
|
|
Hello Stefan, thank you very much for your inputs. By the way, I've been out of town this weekend, I apologize for not being around on time in my own discussion. Many thanks to Richard McCutchan and jschell as well.
Stefan, all that makes sense. This error (or status) code is trown at the
CoGetClassObject function. As I'm following the tutorial instructions, and even the original sources to be sure I'm learning step by step, my guess is that there is something missing with the registration required and those what you can find in the typical .reg file provided. Yes, it's a 15 years old (really good) tutorial and maybe Windows 10 doesn't get along with all those old keys and need something else (I don't know, just guessing, he he). I'm going to make a more in deep research about this because, clearly, the COM Object needs more "registration" somewhere.
Kind regards.
|
|
|
|
|
Member 14499563 wrote: ...15 years old (really good) tutorial and [...] Windows 10...
I strongly suspect that this combination is at least part of the problem (also, I think that, indeed, tutorials used to be better in the past - but that is just my subjective impression )
Unfortunately my knowledge on this topic is no more up to date than this tutorial. I hope you can resolve this anyway.
GOTOs are a bit like wire coat hangers: they tend to breed in the darkness, such that where there once were few, eventually there are many, and the program's architecture collapses beneath them. (Fran Poretto)
|
|
|
|
|
I believe that too.A lot of things have happened in so many years and likely that's not a very good combination in this case, specially when it comes to Windows and its sometimes "very tricky" registry. I've tried three different tutorials (unfortunately all of them very old too) and I got the same result at the same point and the same function, so maybe there is something I have to fix behind the scenes of the new Windows 10 registry and well, I'll -try to- work on it.
Don't feel sorry for yourself, I really appreciate your input: we can't have all the answers
TY Stefan_Lang
|
|
|
|
|
Hello!
I'm new to the topic "Hooks" and a lot of C++ is new to me. I working on a small application to capture messages, which are send to a "log" window of another application. First I used Spy++ to analyze the messages, which showed me a bunch of WM_SETTEXT messages and that's what I want.
from Spy++:
<000001> 0000000000021E4E S WM_SETTEXT lpsz:03B50000 ("18.18s [INFO]: NC: ;Note...Rev: C00 - MAA...")
I created a DLL, which is injected into the application and a console application to create the hook. At the moment the DLL is just writing some data(Handle, Msg, ThreadID, Title) into a text file and I see, that something is getting logged, which belongs to the same thread, but the part I need is missing. When I start the application the log window and it's app freezes. Normally I see text getting added all the time. Once I close the app, it continues.
I'm using Visual Studio 2015 on Win7 64bit. Apps are all 64bit.
This is the DLL code:
HHOOK hHook = 0;
extern "C" __declspec(dllexport) LRESULT CALLBACK GetMsgProc(INT nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode < 0)
{
CallNextHookEx(hHook, nCode, wParam, lParam);
return 0;
}
CWPSTRUCT* pCwp = (CWPSTRUCT*)lParam;
TCHAR tcWinTitle[255];
int len = GetWindowTextLength(pCwp->hwnd) + 1;
GetWindowText(pCwp->hwnd, tcWinTitle, len);
std::wstring wStr = tcWinTitle;
std::string strWinTitle = std::string(wStr.begin(), wStr.end());
TCHAR tcWinHandle[256];
wsprintf(tcWinHandle, L"0x%08p", pCwp->hwnd);
wStr = tcWinHandle;
std::string strWinHandle = std::string(wStr.begin(), wStr.end());
DWORD dwThreadId = GetWindowThreadProcessId(pCwp->hwnd, NULL);
ofstream myfile;
myfile.open("c:\\temp\\example.txt", ios::app);
myfile << " Handle ::: " << strWinHandle << " Msg ::: " << std::to_string(pCwp->message) << " Title ::: " << strWinTitle << " ThreadID ::: " << std::to_string(dwThreadId) << "\n";
myfile.close();
HWND hBingo = FindWindow(L"#32770", L"Bingo");
if (hBingo == 0)
{
HWND hWndOutputParent = FindWindow(L"#32770", L"[Output Window]");
HWND hWndOutput = FindWindowEx(hWndOutputParent, 0, L"Edit", NULL);
if ((pCwp->message == WM_SETTEXT) && (pCwp->hwnd == hWndOutput))
{
MessageBox(hWndOutput, L"Got it", L"Bingo", MB_OK);
return 0;
}
}
return CallNextHookEx(hHook, nCode, wParam, lParam);
This is my console application:
int main()
{
HMODULE dll = LoadLibrary(L"C:\\Projects\\ConsoleApplication1\\x64\\Debug\\WinMsgHookLib.dll");
if (dll == NULL) {
printf("The DLL could not be found.\n");
getchar();
return -1;
}
HOOKPROC addr = (HOOKPROC)GetProcAddress(dll, "GetMsgProc");
if (addr == NULL) {
printf("The function was not found.\n");
getchar();
return -1;
}
HWND hWndOutputParent = FindWindow(L"#32770", L"[Output Window]");
HWND hWndOutput = FindWindowEx(hWndOutputParent, 0, L"Edit", NULL);
DWORD dwThreadId = GetWindowThreadProcessId(hWndOutput, NULL);
HHOOK handle = SetWindowsHookEx(WH_CALLWNDPROC, addr, dll, dwThreadId);
if (handle == NULL) {
printf("Messages could not be hooked.\n");
return -1;
}
printf("Program successfully hooked.\nPress enter to unhook the function and stop the program.\n");
getchar();
UnhookWindowsHookEx(handle);
return 0;
}
Thank you very much for your help!
Mark
|
|
|
|
|
It can't be done anymore on a console application for security to stop stupid hacker keyloggers which basically would only then require minimalistic access. Don't think you can do any of this stuff since Window7 or maybe Vista.
Think you need the minimum of a windows message loop handler which has a valid windows thread id which basically means it must be a windows app or service. That means the hook can't hide, windows knows about it and registered it.
In vino veritas
modified 27-Jun-19 13:19pm.
|
|
|
|
|
Thank you for your reply!
Are you sure about this? I'm using "SetWindowsHookEx" to set the hook, so Windows knows it anyway and the console is also a window. Please correct me, if I'm wrong.
I made one mistake. I think using GetWindowTextLength & GetWindowText are not a good idea in the hook. The application is waiting for the hook and the hook is waiting to get an answer from the application now. I removed it and the app does not freezing anymore.
The handle and message in "CWPSTRUCT* pCwp = (CWPSTRUCT*)lParam;" are good, but I'm having a hard time getting the string from the message.
WM_SETTEXT message ::: lParam = A pointer to a null-terminated string that is the window text. In this case this should be pCwp->lParam It looks like the pointer address is different from the one I see in Spy++, but I'm not sure if I even convert it right.
I tried this to get the pointer address as string, but it seems to be wrong
wsprintf(tcTemp, L"0x%08p", pCwp->lParam);
wStrTemp = tcTemp;
std::string strHexParam = std::string(wStrTemp.begin(), wStrTemp.end());
I tried this to get the message string, but it's not working as well
LPCTSTR lpszString = (LPCTSTR)pCwp->lParam;
COPYDATASTRUCT cds;
cds.dwData = 0;
cds.cbData = sizeof(TCHAR)* (wcslen(lpszString) + 1);
cds.lpData = (PVOID)lpszString;
|
|
|
|
|
Mark_G00 wrote:
wsprintf(tcTemp, L"0x%08p", pCwp->lParam);
wStrTemp = tcTemp;
std::string strHexParam = std::string(wStrTemp.begin(), wStrTemp.end());
I tried this to get the message string, but it's not working as well
LPCTSTR lpszString = (LPCTSTR)pCwp->lParam;
COPYDATASTRUCT cds;
cds.dwData = 0;
cds.cbData = sizeof(TCHAR)* (wcslen(lpszString) + 1);
cds.lpData = (PVOID)lpszString;
Why are you mixing the UNICODE strings with ANSI ones?
|
|
|
|
|
Do you know, what I have to use and what is working?
|
|
|
|
|
At least you have to not mix UNICODE and ANSI functions/variables.
|
|
|
|
|
I already got this with your previous message. I would not ask, if I not totally lost. I only need some direction.
Thank you!
|
|
|
|
|