Dear MFC/ActiveX/COM cracks, I have 'inherited' the source of an old MFC application (originally created with Visual Studio 6)
which builds and runs so far in VS 2010, but has embedded some ActiveX controls as source code, apparently generated by the
Visual Studio wizard (.h and .cpp files, see below);
however not in an own subproject so that a .dll or .ocx file are generated.
Here is the relevant part of the header file of one such control:
#if !defined(AFX_CHARTFX_H__F8A080E0_0647_11D4_92B0_0000E886CDCC__INCLUDED_)
#define AFX_CHARTFX_H__F8A080E0_0647_11D4_92B0_0000E886CDCC__INCLUDED_
#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
// Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++
// NOTE: Do not modify the contents of this file. If this class is regenerated by
// Microsoft Visual C++, your modifications will be overwritten.
/////////////////////////////////////////////////////////////////////////////
// CChartfx wrapper class
class CChartfx : public CWnd
{
protected:
DECLARE_DYNCREATE(CChartfx)
public:
CLSID const& GetClsid()
{
static CLSID const clsid
= { 0x8996b0a1, 0xd7be, 0x101b, { 0x86, 0x50, 0x0, 0xaa, 0x0, 0x3a, 0x55, 0x93 } };
return clsid;
}
virtual BOOL Create(LPCTSTR lpszClassName,
LPCTSTR lpszWindowName, DWORD dwStyle,
const RECT& rect,
CWnd* pParentWnd, UINT nID,
CCreateContext* pContext = NULL)
{ return CreateControl(GetClsid(), lpszWindowName, dwStyle, rect, pParentWnd, nID); }
BOOL Create(LPCTSTR lpszWindowName, DWORD dwStyle,
const RECT& rect, CWnd* pParentWnd, UINT nID,
CFile* pPersist = NULL, BOOL bStorage = FALSE,
BSTR bstrLicKey = NULL)
{ return CreateControl(GetClsid(), lpszWindowName, dwStyle, rect, pParentWnd, nID,
pPersist, bStorage, bstrLicKey); }
//rest of header file omitted
Note that this class inherits from CWnd and not some
OCX class. But since all MFC windows are COM components (as I read somewhere) and this is generated
code it should have worked some time ago. I also read that this may be really a migration gap
which occurred somewhere before 2005.
Also note the DECLARE_DYNCREATE, so I think this is late binding, using the IDispatch interface.
So MFC will call a Create() function for us.
The above control is used via aggregation by an encompassing CDialog (also created with VS wizard):
//... analysedlg.h - leading auto-generated stuff omitted
class CAnalyseDlg : public CDialog
{
CChartfx m_chhrtfx;
//... enum for resource ID, DoDataExchange, message map, other members…
}
The dialog, in turn, is embedded in a view class of the application (again, via a member variable) and
created by invoking DoModal() in a menu item event handler.
So, when I click on the corresponding menu item, I get an m_hWnd NULL assertion and when hitting
'retry' in the popped up dialogue, the following stack (excerpt):
mfc100d.dll!COleControlContainer::FillListSitesOrWnds(_AFX_OCC_DIALOG_INFO * pOccDlgInfo) line 925 + 0x23 Bytes C++
mfc100d.dll!COccManager::CreateDlgControls(CWnd * pWndParent, const char * lpszResourceName, _AFX_OCC_DIALOG_INFO * pOccDlgInfo) line 410 C++
mfc100d.dll!CDialog::HandleInitDialog(unsigned int __formal, unsigned int __formal) line 715 + 0x22 Bytes C++
mfc100d.dll!CWnd::OnWndMsg(unsigned int message, unsigned int wParam, long lParam, long * pResult) line 2383 + 0x11 Bytes C++
mfc100d.dll!CWnd::WindowProc(unsigned int message, unsigned int wParam, long lParam) line 2087 + 0x20 Bytes C++
mfc100d.dll!AfxCallWndProc(CWnd * pWnd, HWND__ * hWnd, unsigned int nMsg, unsigned int wParam, long lParam) line 257 + 0x1c Bytes C++
mfc100d.dll!AfxWndProc(HWND__ * hWnd, unsigned int nMsg, unsigned int wParam, long lParam) line 420 C++
mfc100d.dll!AfxWndProcBase(HWND__ * hWnd, unsigned int nMsg, unsigned int wParam, long lParam) line 420 + 0x15 Bytes C++
user32.dll!766162fa()
[missing frames omitted by me]
mfc100d.dll!CWnd::CreateDlgIndirect(const DLGTEMPLATE * lpDialogTemplate, CWnd * pParentWnd, HINSTANCE__ * hInst) line 366 + 0x2a Bytes C++
mfc100d.dll!CDialog::DoModal() line 630 + 0x20 Bytes C++
In the VS debug output there are the following lines:
CoCreateInstance of OLE control {8996B0A1-D7BE-101B-8650-00AA003A5593} failed.
>>> Result code: 0x80040154
>>> Is the control is properly registered?
Warning: Resource items and Win32 Z-order lists are out of sync. Tab order may be not defined well.
So apparently the call to CoCreateInstance had already been done and silently failed without an assertion
which would have been nice to have had. Does anybody know where this is?
My central question is whether it is correct that in this case normally MFC would take care for
registering the control even if it is not in an .dll or .ocx project and that it must have worked
like this in the past. I read somewhere that CreateDlgIndirect with a DialogTemplate is a way of
creating ActiveX controls without needing a .dll or .ocx file. In the above stack, this is called,
too, but not for the ActiveX control, but for the dialogue instead.
Does anyone know more about this issue and how to fix it?
If I do have to manually register the controls, e.g. using regsvr32.exe or via source code,
is there a way without .dll or .ocx files? Or do I have to repackage the ActiveX components in
their own projects (what would be more component-based/modular anyway)?
I hope my problem description is precise enough and I would be very thankful for any answer.
Kind regards.
I've just run into this when using an old ActiveX control. Apparently it was apartment threaded and I was trying to call CoInitializeEx() with COINIT_MULTITHREADED.
Related
I am trying to use UrlDownloadToFile OR InternetOpenUrl to visit some link on the Internet from an DLL file. While it works on an .exe file, but it didn't work from a DLL file, and even no any error information. It just failed without any information.
Anyone could give me any help? Thanks in advance.
My code are as below:
extern "C" __declspec(dllexport) int __stdcall Hello()
{
HINTERNET hInt=NULL, hUrl=NULL;
hInt = InternetOpenA("Test Agent", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
hUrl = InternetOpenUrlA(hInt, "http://www.google.com.au", NULL, 0, INTERNET_FLAG_RELOAD | INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_NO_CACHE_WRITE, 0);
if (hUrl)
{
InternetCloseHandle(hUrl);
}
InternetCloseHandle(hInt);
return 0;
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
Hello();
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
It failed at:
hUrl = InternetOpenUrlA(hInt, "http://www.google.com.au", NULL, 0, INTERNET_FLAG_RELOAD | INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_NO_CACHE_WRITE, 0);
Or:
typedef HRESULT (__stdcall * lpURLDownloadToFile) (LPUNKNOWN pCaller, LPCTSTR szURL, LPCTSTR szFileName, DWORD dwReserved, LPBINDSTATUSCALLBACK lpfnCB);
extern "C" __declspec(dllexport) int __stdcall Hello()
{
HMODULE hModule = LoadLibraryW(L"urlmon.dll");
lpURLDownloadToFile urlD = (lpURLDownloadToFile)GetProcAddress( hModule, "URLDownloadToFileW" );
HRESULT aa = urlD(NULL, L"http://www.google.com.au", L"C:\\Test\\a.html", 0, NULL);
return 0;
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
Hello();
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
It failed at:
HRESULT aa = urlD(NULL, L"http://www.google.com.au", L"C:\\Test\\a.html", 0, NULL);
Update:
If I insert a line like "MessageBox" just above where it fails, the MessageBox will be displayed successfully.
If I insert a line like "MessageBox" just after where it fails, the MessageBox will not be displayed. And there is no any error code returned if I tried to display "hUrl" or "aa".
Don't do that in DllMain. See DllMain entry point
The entry-point function should perform only simple initialization or
termination tasks. It must not call the LoadLibrary or LoadLibraryEx
function (or a function that calls these functions), because this may
create dependency loops in the DLL load order. This can result in a
DLL being used before the system has executed its initialization code.
EDIT, as you want to inject the Dll and run code in it.
One way to make an injected Dll to start executing code, without relying on DllMain is as follow:
Use a message hook, limited to one thread.
Find a HWND belonging to the process you want to inject. For Internet Explorer, you may enumerate the Top Level Windows, using EnumWindows A main IE Windows has a class IEframe. Use EnumChildWindows to find a window of class Internet_Explorer Server. Use GetWindowThreadProcessId to get the associated TID (Thread Identifier).
Use SetWindowsHookEx to install a thread hook. You may choose a WH_CALLWNDPROC
or a WH_GETMESSAGE hook. Pass the TID obtained in 1. Your DLL is injected, and is processing messages.
Use PostMessage or SendMessage or PostThreadMessage, depending on the hook type you choose in 2, with a registered message. See RegisterWindowMessage
In your hook function, filter for the registered message (obtain it's value in your DllMain and store it in a global variable) and when this message is received, call your custom code.
Warning: this technique is well suited for short living code, you are in a hook function. That's maybe not the place for downloading from the Internet.
Another way is to create a thread in DllMain, using _beginthreadex
In the thread, you may have a classic RegisterClass / CreateWindow / GetMessage/ DispatchMessage sequence, and your EXE will be able to Send/Post messages to your Dll.
Warning: depending on how you injected the Dll, you must be very carreful about premature unloading of your Dll. If the thread still runs, there may be crashes. Being clean and stable with theses things is not easy. But, if you are just playing/experimenting, don't bother and just LoadLibrary (not in DllMain) you own library a second time, it will stay here forever.
You can mix the two techniques, that is: use a thread message hook to inject the Dll and start a thread in the hook function.
I have a few datamodules, created with C++ Builder 6. Each of them uses another datamodule that initializes the connection with the database. I'm trying to make a DLL out of those datamodules.
The error is thrown on creation of DataModule_Users and says 'Abnormal program termination'.
Where do I go wrong?
Thanks in advance
datamodule_dll.bpf
USEFORM("DataModule_Connection.cpp", DataModule_Connection); /* TDataModule: File Type */
USEFORM("DataModule_Users.cpp", DataModule_Users); /*TDataModule: File Type */
//------------------------------------------------------------------
This file is used by the project manager only and should be treated like the project file
DllEntryPoint
datamodule_DLL.cpp
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
return 1;
}
extern "C" __declspec(dllexport) const char * GetUserName(const char * ID);
const char * GetUserName(const char * ID) {
CoInitialize(NULL); // datasets use COM
// This is used by DataModule_Users (normally this is done with Application->CreateForm();
DataModule_Connection = new DataModule_Connection( 0 /* Owner */ );
DataModule_Users = new DataModule_Users( 0 /* Owner */ );
return DataModule_Users->GetUserName(ID);
}
I will quote Remy Lebeau:
COM is initialized on a per-thread basis. Once a thread's COM model
(apartment vs multithreaded) has been set, it cannot be changed later.
If your DLL calls CoInitialize() before the caller does, your
parameters would take priority, which might not meet the caller's
needs. If you want to control the COM settings for your DMs without
affecting the caller, you have to move the DMs to their own thread.
Besides, DllEntryPoint() is not an appropriate place to initialize
them anyway. The OS restricts what DllEntryPoint() is allowed to do.
This solved the issue. I had to call coInitialize() before I load the library.
I'm using a local hook (WH_KEYBOARD) with ms word (OpusApp). Well, as far as I know a 32bit app with a 32bit DLL must work only with 32bit target applications. The weird thing is that the program only works with 64bits apps!!! That is it, only with 64bits APPS! For example, it works with IE 64 but not with IE 32!
The app and dll are 32bit compiled with radstudio XE2, I confirmed the version into PE header.
In 32bit OSs, the app and dll doesn´t work.
I found no solutions on net and see no starting point to solve this weird problem.
The DLL code:
// Exported functions
extern "C" __declspec(dllexport)bool __stdcall InstallMouseHook(unsigned long, void *);
extern "C" __declspec(dllexport)bool __stdcall RemoveMouseHook();
// Callback Procedure Declaration
LRESULT CALLBACK HookProc(int code, WPARAM wParam, LPARAM lParam);
// Global variables
HHOOK HookHandle;
HINSTANCE DllInstance;
typedef void (__stdcall *CALLIT)(int,WPARAM,LPARAM);
CALLIT callIt = NULL;
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*)
{
DllInstance=hinst;
return 1;
}
bool __stdcall InstallMouseHook(unsigned long pid, void *function)
{
callIt = ( CALLIT ) function;
if (function == NULL) {
ShowMessage("function is null!");
} else if (callIt == NULL) {
ShowMessage("callIt is null!");
}
HookHandle=SetWindowsHookEx(WH_KEYBOARD ,reinterpret_cast<HOOKPROC> (HookProc),DllInstance,pid);
if (HookHandle==NULL)return false;
else return true;
}
bool __stdcall RemoveMouseHook()
{
if(UnhookWindowsHookEx(HookHandle)==0)
{
return false;
}
else return true;
}
LRESULT CALLBACK HookProc(int code, WPARAM wParam, LPARAM lParam)
{
if (code<0) {
return CallNextHookEx(HookHandle,code,wParam,lParam);
}
if (callIt != NULL) {
callIt(code,wParam,lParam);
} else {
ShowMessage("HookProc - no function to execute OR 32/64 bits problem!");
}
//Call the next hook in the chain
return CallNextHookEx(HookHandle,code,wParam,lParam);
}
The EXE calling code:
void __fastcall TfrmMouseHook::btnHookAppDllClick(TObject *Sender)
{
HWND hWindow;
unsigned long pid;
String s = "MouseHookDLL.dll";
DllHandle=LoadLibrary(s.w_str());
MOUSEHOOKFCT_2 InstHook=reinterpret_cast<MOUSEHOOKFCT_2> (GetProcAddress(DllHandle,"InstallMouseHook"));
hWindow = FindWindow(ComboBox1->Text.w_str(),NULL);
if (!hWindow) {
msg("hWindow fail");
return;
}
pid = GetWindowThreadProcessId(hWindow ,0);
if (!pid) {
msg("pid fail");
return;
}
if(!InstHook(pid, (void *) callIt )) {
msg("Unable to install hook!");
} else {
msg(" #### hook INSTALLED! ####");
}
}
CALLIT callIt(code,wParam,lParam) {
frmMouseHook->msg("hook callit: code="+IntToStr(code) +" wparam="+IntToStr(wParam)+" lparam="+IntToStr(lParam) );
}
Call IT is a function pointer to a hooker app function.
Any ideas will be very wellcome!
It is physically impossible for a 32-bit app to install a 32-bit hook DLL and have it executed in 64-bit processes. A 32-bit DLL simply cannot be injected into a 64-bit process. Period. MSDN says this in multiple places, including in the SetWindowsHookEx() documentation:
SetWindowsHookEx can be used to inject a DLL into another process. A
32-bit DLL cannot be injected into a 64-bit process, and a 64-bit DLL
cannot be injected into a 32-bit process. If an application requires
the use of hooks in other processes, it is required that a 32-bit
application call SetWindowsHookEx to inject a 32-bit DLL into 32-bit
processes, and a 64-bit application call SetWindowsHookEx to inject a
64-bit DLL into 64-bit processes. The 32-bit and 64-bit DLLs must have
different names.
Because hooks run in the context of an application, they must match
the "bitness" of the application. If a 32-bit application installs a
global hook on 64-bit Windows, the 32-bit hook is injected into each
32-bit process (the usual security boundaries apply). In a 64-bit
process, the threads are still marked as "hooked." However, because a
32-bit application must run the hook code, the system executes the
hook in the hooking app's context; specifically, on the thread that
called SetWindowsHookEx. This means that the hooking application must
continue to pump messages or it might block the normal functioning of
the 64-bit processes.
If a 64-bit application installs a global hook on 64-bit Windows, the
64-bit hook is injected into each 64-bit process, while all 32-bit
processes use a callback to the hooking application.
The fact that you say your app and DLL do not work on 32-bit OS versions suggests your hooking code is flawed to begin with. But you have not shown enough code to diagnose that one way or the other.
What happens? Besides MSDN or anyone else says, there are some bug in XE6, compiling DLL in newer versions of IDE make this behavior disappears, in fact, the new DLL crash and hook nothing.
As Remy noted, by test I passed a function pointer to the DLL, one wrong thing to do but, when added with the wrong thing done by Embarcadero, sort of functioned.
By now, and I know people will get mad, I put both methods (the wrong and the correct hooks) in the same DLL and in my application and... get crazy... could hook into 32 and 64 bits app with only one DLL.
Don't believe? Install XE6 and try!
And Works in windows 10 as well in windows 7.
We have an out of process COM application that was written in C++ that implements are networking protocol. When a packet of data is received a callback is invoked into the application that registered for the packet.
The callback interface is defined as such:
[helpstring("method MessageHandler")] HRESULT MessageHandler([in,size_is(nSize)] char * szBuf, int nSize, DWORD dwTransCode, DWORD dwSenderID, BSTR bstrFromIP);
Using this in C++ has not been an issue. We now have a case where we have a C++/CLI application that needs to receive callbacks. After hacking away until the compiler was happy, I arrived at the following implementation:
ref class MessageHandlerClass : public MessageRouterCallback
{
public:
virtual void MessageHandler(signed char %buffer, int size, unsigned int msgId, unsigned int fromId, System::String^ fromIp)
{
switch (msgId)
{
case MaintenanceMsgs::maintenance_event_message::ID:
{
SomeStructure msg;
myHandler->HandleMaintenanceEvent(&msg);
}
}
}
This is my first foray into C++/CLI.
First Question: What they heck does '%' mean in 'signed char %buffer'?
Second Question: I can place a breakpoint and see that the callback is getting called. I can look at the 'buffer' argument in the memory debugger and it contains the data I expect. I have been VERY unsuccessful at pulling that data out and placing it into the variable 'msg'. I know I can't do a cast like in C++, but every example I've been tried (Mostly InteropServices::Marshal and some pin_ptr stuff) doesn't seem to get me anywhere.
SomeStructure is declared in a header file and is included by both the C++ and the C++/CLI application. SomeStructure contains 2 unsigned shorts followed by three character arrays.
Any direction on where to go from here would be greatly appreciated.
Ok. It just 'clicked'... So I'll answer my own question here.
First Question: What they heck does '%' mean in 'signed char %buffer'?
The '%' just means its 'tracked' and will be garbage collected, or at least that's what I think it means :)
Second Question: How to marshal.
First I had to get to the 'internal pointer' and C++/CLI provides the & operator for that. Then I was able to simply memcpy the data over.
pin_ptr<signed char> p = &buffer;
MaintenanceMsgs::maintenance_event_message msg;
memcpy((void*)&msg, (void*)p, sizeof(msg));
myHandler->HandleMaintenanceEvent(&msg);
Is this safe?
i have got a ScreenCameraSDK and it comes with a 11kb dll file, it has a documentation too which lists the functions which can be used. It says
ScreenCamera SDK ActiveX Reference Documentation
ActiveX Reference
The ActiveX ID on the system is: ScreenCameraSDK.RemoteControl
Every method on the interface returns FAIL or SUCCESS. (0 or 1).
Create an instance of the ActiveX on your application, and then call InitializeScreenCameraRemoteControl. If the return value is SUCCESS then ScreenCamera is properly installed and you can then call any other method on the ActiveX's interface. If not ScreenCamera could not be found and you should contact support.**
Now my question is, i have the dll and no other files. How can i use the functions inside it in a VC++ Project with Visual Studio 2008.
Thanks
I TRIED THE FOLLOWING CODE BUT GOT COMPILATION ERROR OF UNDEFINED IDENTIFIER
#include <stdio.h>
// This is the path for your DLL.
// Make sure that you specify the exact path.
#import "e:\ScreenCameraSDK.dll" no_namespace
void main()
{
BSTR bstrDesc;
try
{
CoInitialize(NULL);
short st = 2;
short st1;
// Declare the Interface Pointer for your Visual Basic object. Here,
// _Class1Ptr is the Smart pointer wrapper class representing the
// default interface of the Visual Basic object.
_Class1Ptr ptr;
// Create an instance of your Visual Basic object, here
// __uuidof(Class1) gets the CLSID of your Visual Basic object.
ptr.CreateInstance(__uuidof(Class1));
st1 = ptr->MyVBFunction(&st);
}
catch(_com_error &e)
{
bstrDesc = e.Description();
}
CoUninitialize();
}
it says _Class1Ptr is unknown!
BSTR bstrDesc;
try
{
HRESULT hr= CoInitialize(NULL);
CLSID clsid;
hr = CLSIDFromProgID(OLESTR("<complete class name as see in registry>"),&clsid);
short st = 2;
short st1;
//nameOfClassInOCX is placeholder for explanation. If you OCX com class name is blabla
//use _blabla and so on.
_nameOfClassInOCX * ptr;
hr = CoCreateInstance(clsid,NULL,CLSCTX_INPROC_SERVER,__uuidof(_nameOfClassInOCX ),(LPVOID*)&ptr);
cout << ptr->GetFees("hi") <<endl;
ptr->Release();
}
catch(_com_error &e)
{
bstrDesc = e.Description();
}
CoUninitialize();
First of all you have to do this is #import the dll, and the compiler will automatically generate all required definitions from it. Then create objects from the library by using either smart pointers, or CreateInstance().
#import "C:\files\test.dll" no_namespace rename("EOF", "EOFile")
...
int main() {
if (FAILED(::CoInitialize(NULL)))
return 0;
........
::CoUninitialize();
return 0;
}