|
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!
|
|
|
|
|
A console window is not a normal window in any way, underneath they are very different at the thread and message queue level.
The old console sits on the CSRSS subsystem
Client/Server Runtime Subsystem - Wikipedia[^]
It was officially abandonded since Windows 7 and the console is nothing more than a subprocess with drawing capabilities which has now even been extended to hosting ubuntu linux console on Windows 64.
If you want to see how shutdown the message loop is you can't even use spy++ on the messages in a console window.
Anyhow you want to waste your time .. good luck.
In vino veritas
|
|
|
|
|
I just used a console application to set the hook, which will inject the dll with the callback. I'm getting a valid handle and the hook is executed in the address space of the target application. There are no messages to or from the console application. I'm not trying to spy anything on a console window. Maybe that was not clear.
I get a "CWPSTRUCT" with the right message code and I have trouble to convert the message/pointer to a string and write it to a file. All of this is done in the dll. I don't know, how to setup the debugger to stop inside the dll. It's more like a try and error at the moment and that can be frustrating. I don't see this as a waste of time, because I'm also learning.
I appreciate your time and help! Thank you!
|
|
|
|
|
<pre>I am implementing a MS Word report program (in MFC c++) which uses MS Word to produce some kind of report from my program.
A document that is produced is based on a template "mytemplate.dot" or "mytemplate.dotm" .
When creating "mytemplate" in MS Word, I insert an enhanced metafile picture (via clippboard) from my program. This enhanced metafile has a unique signature text "XYZ" (example).
"mytemplate' is stored in both "dot" and "dotm" formats. Any new file created in Word (2007,20016) based on these tempaltes opens correctly and I can see my enhanced metafile picture correctly displayed in Word and my unique "XYZ" is there.
Now I create a "mytemplated" based document in my c++ program (using msword.olb type library).
m_doc = documents.Add(& mytemplate,....)
Then I enumarete through inlineshapes to find the wdInlineShapePicture type (which for the test purpose is the only inlineshape in document). I find the inlineshape object without any problem ("myinlineshape"). I do myinlineshape.Copy() and then use the clipboard to copy the enhanced metafile picture to my c++ program:
OpenClipboard(AfxGetMainWnd()->m_hWnd);
HANDLE hclip = GetClipboardData (CF_ENHMETAFILE ); //first I check if CF_ENMETAFILE is available in the clippboard
everything is OK till now
Now when I use the "mytemplate.dot" format the enhanced metafile in my program is exactly the same as it in Word - (the size and number of segments is exactly the same).
When I use the "mytemplate.dotm" format, the metafile is changed - the size is different, number of segments is suddently quite small (like 19 vs 5000 in original). The picture shows the same contents but it is more like bitmap not a metafile.
Can anybody explain what can be wrong?</pre>
|
|
|
|
|
Is there any point to create a CStringList class member on heap (with new) if this member has a lot of elements ? Or is enough to declare it on stack ?
modified 19-Jun-19 6:12am.
|
|
|
|
|
Sorry? What are you trying to do, really? Could you please provide an example?
|
|
|
|
|
protected:
CStringList m_List1;
CStringList m_List2;
CStringList m_List3;
CStringList m_List4;
COutputWnd::COutputWnd() noexcept
{
m_List1.AddTail(_T("Item 1"));
m_List1.AddTail(_T("Item 1"));
m_List1.AddTail(_T("Item 1"));
m_List1.AddTail(_T("Item 1"));
m_List1.AddTail(_T("Item 1"));
m_List1.AddTail(_T("Item 1"));
m_List2.AddTail(_T("Item 2"));
m_List2.AddTail(_T("Item 2"));
m_List2.AddTail(_T("Item 2"));
m_List2.AddTail(_T("Item 3"));
m_List2.AddTail(_T("Item 55"));
m_List2.AddTail(_T("Item 44"));
....
}
or should I do a CSringList* m_pList1, and in c-tor I create m_pList1 = new CStringList ? That was the question.
|
|
|
|
|
There is no point (as Maximilen alrady stated) in using the heap in such a scenario.
|
|
|
|
|
no point, really.
Anyway, stop using CStringList and use a std::vector instead.
I'd rather be phishing!
|
|
|
|
|
Thank you. I would let this CStringList as it is now. I still have a question: Why should I use std::vector instead of CStringList ? Is there a plus ? Please note that my app is VC++/MFC, and CStringList is part of MFC.
|
|
|
|
|
If you are using MFC then it is fine to use its classes. However for most cases it is better to allocate most objects on the heap. Save the stack for values, pointers and very short term objects,
|
|
|
|
|
In my experience, if there is a class for your purpose to be found in STL, then it's much better to use that than a corresponding MFC class. The only exception is when you need the MFC structure to interface with a function from a third party library. (e. g. to pass it as a function argument)
The 'plus' is that
- you could port the code to any platform that does not have or use MFC
- you can use other third party libraries that don't use MFC (e. g. most third party libraries using strings in their API will use std::string, not CString)
- it's easy to find plenty of documentation and tutorials on the web, and they are all accurate, because existing behaviour of STL types never changes
- the types and functions will work very efficiently and not carry around needless ballast related to Windows stuff
- your global namespace doesn't get cluttered with symbols and macros
- you don't suffer from header dependencies, and don't need to care about order of include statements
The 'minus' is that
- for some types the STL equivalent provides less utility functions (e. g. std::string vs. CString)
- if you're already using MFC types elsewhere and don't intend to change all of them, you may need to convert data between MFC- and non-MFC types.
As for using std::vector instead of std::list, the reason is that as long as you don't delete items in the mid or at the start of the vector, it is much faster than a list.
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)
|
|
|
|
|
Stefan_Lang wrote: - you could port the code to any platform that does not have or use MFC
In my experience in non-trivial (legacy) applications that possibility does not exist unless one refactors the entire code base.
That of course precludes those cases where the application, from its inception, was written to support multiple platforms.
|
|
|
|
|