Cocreateinstance consuming high cpu - c++

I am using a LOGSERVICELib.dll exposed interface methods as logging method in main project. There is abc.h file in main project where it create instance of LOGSERVICELib.dll and uses it's exposed methods to log main project errors. I recently observed that it's making process too slow ,after profiling the code, I found that cocreate instance consuming high cpu along with other CStdio functions* why Cstdio funcitons taking high cpu time(70-80%)?
Cstdiofile::Readstring()
Cstdiofile::writeString()
Cstdiofile::flush()
LogHelper.h( external .h file)
class LogHelper
{
public:
LogHelper()
{
CoInitialize(NULL);
};
~LogHelper()
{
CoUninitialize();
};
static void LogMessage(_bstr_t eventName, _bstr_t logFilePath, _bstr_t logFileName, _bstr_t message)
{
HRESULT hr = S_OK ;
try
{
CComPtr<LOGSERVICELib::ILogUtility> ILog;
if(ILog == NULL)
hr = ILog.CoCreateInstance(__uuidof(LOGSERVICELib::LogUtility));
if( SUCCEEDED( hr ) )
{
hr = pILog->PostMessage( logFilePath, logFileName, eventName, message, L"", L"");
}
}
catch( _com_error& )
{
// forget it
}
}}
stdAfx.h(Main project)
#define LOG_THIS(x) LogHelper::LogMessage( L"Service", _Module.m_bstrLogHelper, _Module.m_LogHelperLogFile, x)
Service.cpp:
void publish()
{
LOG_THIS("published new service");
}

hr = ILog.CoCreateInstance(__uuidof(LOGSERVICELib::LogUtility));
Clearly this code belongs in the constructor of LogHelper. Profiler guided optimization for the win, and you already used the profiler. Good for you. While you're at it, get rid of the f(ILog == NULL) altogether and move the declaration to your class constructor. This way the code that tries to create it always runs.
CComPtr auto-frees the object.
Unfortunately LogMethod is currently static. To fix the performance the available choices are refactor until it isn't static anymore or implement LOGSERVICELib::LogUtility yourself.

Related

IDispatch::Invoke Returning E_INVALIDARG

I have an ATL COM component which raises a few events which are handled by managed (C# and VB.NET) code. The component is currently used by a VS2005 VB.NET project (as an ActiveX control) and all of the events are raised and everything works.
However, in porting some of the code to C#, I noticed that all but one of the events are never raised. The only event which is raised passes no arguments back to the handler. All others do.
// this function is auto-generated
HRESULT Fire_SomeEvent(VARIANT_BOOL inOriginated, IUserType * inUserType)
{
CComVariant varResult;
T* pT = static_cast<T*>(this);
int nConnectionIndex;
CComVariant* pvars = new CComVariant[2];
int nConnections = m_vec.GetSize();
for (nConnectionIndex = 0; nConnectionIndex < nConnections; nConnectionIndex++)
{
pT->Lock();
CComPtr<IUnknown> sp = m_vec.GetAt(nConnectionIndex);
pT->Unlock();
IDispatch* pDispatch = reinterpret_cast<IDispatch*>(sp.p);
if (pDispatch != NULL)
{
VariantClear(&varResult);
pvars[1] = inOriginated;
pvars[0] = inUserType;
DISPPARAMS disp = { pvars, NULL, 2, 0 };
pDispatch->Invoke(0x7, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &disp, &varResult, NULL, NULL);
}
}
delete[] pvars;
return varResult.scode;
}
Invoke is returning 0x80070057 (E_INVALIDARG). Yet, in VB land, when used via the ActiveX wrapper, it works. Now, I'm no COM wizard by any means, and I just don't get it. I haven't been able to find anything applicable anywhere.
I thought that perhaps it had something to do with passing a UDT, but no; an almost identical version, with the IUserType replaced by a LONG also returns E_INVALIDARG. Again, the single event which passes no arguments works.
A short example of how it may be used by the managed code. Nothing crazy here.
class Program
{
private ComType _c;
static void Main(string[] args)
{
_c = new ComType();
_c.SomeEvent += _c_SomeEvent;
_c.DoSomethingWhichRaisesSomeEvent();
}
static void _c_SomeEvent(bool b, IUserType udt)
{
// never called
}
}
I would normally spend more time debugging before reaching out here, but I have to make a call here soon. I either have to fix this, or abandon this interface and use another (which is sub-optimal for my purpose). So, hoping some of you COM pros have run into this before.
Double-check your vt values in your dispparam variants; many IDispatch implementations are quite particular about having everything line up.

Loading CLR in C++, Start() problem

So I'm trying to load up the .NET 4 runtime and run my own C# DLL. The Start() method is throwing a HRESULT=0x1 error. If I comment out the start code, the C# DLL loads and executes, then the Stop() method throws a HRESULT=0x8000ffff error. I've looked for hours and all the code looks like what I have below (I left out all my debugging/error handling). Thank you very much for any tips in advance! =)
void DotNetLoad()
{
ICLRRuntimeHost *pClrHost = NULL;
ICLRMetaHost *lpMetaHost = NULL;
MessageBox(0, L"Creating CLR instance.", L"Bootstrap Message", 0);
HRESULT hr = CLRCreateInstance(
CLSID_CLRMetaHost,
IID_PPV_ARGS(&lpMetaHost));
ICLRRuntimeInfo *lpRuntimeInfo = NULL;
hr = lpMetaHost->GetRuntime(L"v4.0.30319",
IID_PPV_ARGS(&lpRuntimeInfo));
hr = lpRuntimeInfo->GetInterface(
CLSID_CLRRuntimeHost,
IID_ICLRRuntimeHost,
(LPVOID *)&pClrHost);
hr = pClrHost->Start();
DWORD dwRet = 0;
hr = pClrHost->ExecuteInDefaultAppDomain(
pwzTargetDll,
pwzNamespaceClass, pwzFunction, L"pwzArgument", &dwRet);
hr = pClrHost->Stop();
hr = pClrHost->Release();
}
I understand the bit about decoupling the init, .NET call, and deinit, but what do you mean by app startup and shutdown? Right now I have DotNetLoad being called from a DLL method that is injected into a remote process. Basically:
extern "C" __Declspec(dllexport) void Initialize()
{
DotNetLoad(params); //ex.
}
By combining runtime init with the assembly method call, followed by runtime deinit, you are executing this code on every call to DotNetLoad().
See the important block here. This leads me to believe that once you load the runtime into your process you don't want to do it again.
Split your initialization / deinitialization out of the method used to call the .NET assembly. Do the initialization only once (at app startup and prior to making the call), and do the deinitialization only once (at app shutdown). I tested this and it worked without error.

COM Initialization and Use in Win32 C++ DLL

I am writing a Win32 C++ DLL that uses the COM to query WMI. How can I programmatically determine if COM has already been initialized? Thanks.
Mark Ransom is right
the straightforward, clean and simple solution is to require COM initialization by the caller.
Ugly hack
You can try your first call - likely CoCreateInstance, and if it returns CO_E_NOTINITIALIZED, run CoInitialize yourself (and don't forget to uninit in that case)
However, it is still problematic to "inject" a CoInitialize into a caller thread from a DLL. So there's a
Clean Solution
Let the DLL create a worker thread (which means the DLL needs Init and Teardown calls), CoInitializeEx in this thread yourself, and move all the COM calls to that separate thread.
The easiest way is not to bother, just make it a requirement of anybody using your DLL that they initialize COM first. Otherwise you run the risk of messing up their own initialization if they perform it after yours.
On the other hand if your flags to CoInitializeEx match those of the application, you should be fine. From the CoInitializeEx documentation:
Multiple calls to CoInitializeEx by
the same thread are allowed as long as
they pass the same concurrency flag,
but subsequent valid calls return
S_FALSE.
It follows #peterchen clean solution as I coded it for a thread-safe COM logger component that I wanted to wrap:
IComLoggerPtr _logger;
_bstr_t _name;
HANDLE _thread;
HANDLE _completed;
Logger::Logger(_bstr_t name)
{
_name = name;
_completed = ::CreateEvent(NULL, false, false, NULL);
if (_completed == NULL)
::AtlThrowLastWin32();
// Launch the thread for COM interation
DWORD threadId;
_thread = ::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)(this->threadRun),
(LPVOID)this, 0, &threadId);
// Wait object initialization
HRESULT hr = ::WaitForSingleObject(_completed, INFINITE);
if (FAILED(hr))
AtlThrow(hr);
}
Logger::~Logger()
{
::SetEvent(_completed);
CloseHandle(_thread);
CloseHandle(_completed);
}
DWORD WINAPI Logger::threadRun(LPVOID opaque)
{
Logger *obj = (Logger *)opaque;
// Init Free-Threaded COM subsystem
HRESULT hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
if (FAILED(hr))
::AtlThrow(hr);
hr = obj->_logger.CreateInstance(__uuidof(ComLogger));
if (FAILED(hr))
::AtlThrow(hr);
obj->_logger->Init(obj->_name);
// Initialization completed
bool success = ::SetEvent(obj->_completed);
if (!success)
::AtlThrowLastWin32();
// Wait release event
hr = ::WaitForSingleObject(obj->_completed, INFINITE);
if (FAILED(hr))
AtlThrow(hr);
obj->_logger.Release();
// Release COM subsystem
::CoUninitialize();
}
HRESULT Logger::Log(_bstr_t description)
{
return _logger->Log(description);
}
CoInitializeEx\CoUninitialize should only be called by threads (not by Dll-calls).
BTW ,you should not Use CoInitializeEx\CoUninitialize in DllMain !

API Hook on a COM object function?

Greetings StackOverflowians,
As discovered here, Windows 7 features a bug in which the DISPID_BEFORENAVIGATE2 event does not fire for Windows Explorer instances. This event allows shell extensions to be notified when a navigation is about to take place, and (most importantly for me) have the opportunity to cancel the navigation. I've been looking for a workaround for quite some time, and I think I found one. But, I'd like to get some opinions on how safe it is.
I've been playing with API hooking a lot lately, and I'm already using it to hook a few functions for my extension. I noticed that there is a function in IShellBrowser that controls navigation. At first I thought you couldn't hook something like that, but upon reading about the layout of a COM object I realized it should be possible by just grabbing the right function pointer out of the vtable of any active instance. Sure enough, it works like a dream. After the hook is set, all navigations in all Explorer windows run right through my detour function, and I can decide whether to reject them based on their target pidl.
So my question is, is there any reason I should NOT do this? I've never heard of API hooking used to hook COM object functions. Are there circumstances it which it wouldn't work? Is it dangerous? (Any more than regular API hooking, at least)
The relevant code follows. I'm using MinHook, a minimalistic hooking library that uses the tried-and-true method of trampoline functions.
typedef HRESULT (WINAPI *BROWSEOBJECT)(IShellBrowser*, PCUIDLIST_RELATIVE, UINT);
HRESULT WINAPI DetourBrowseObject(IShellBrowser* _this, PCUIDLIST_RELATIVE pidl, UINT wFlags);
BROWSEOBJECT fpBrowseObject = NULL;
BROWSEOBJECT ShellBrowser_BrowseObject = NULL;
bool Initialize() {
if(MH_Initialize() != MH_OK) {
return false;
}
// Get a reference to an existing IShellBrowser. Any instance will do.
// ShellBrowser enum code taken from The Old New Thing
IShellWindows *psw;
BOOL fFound = FALSE;
if (SUCCEEDED(CoCreateInstance(CLSID_ShellWindows, NULL, CLSCTX_ALL, IID_IShellWindows, (void**)&psw))) {
VARIANT v;
V_VT(&v) = VT_I4;
IDispatch *pdisp;
for (V_I4(&v) = 0; !fFound && psw->Item(v, &pdisp) == S_OK; V_I4(&v)++) {
IWebBrowserApp *pwba;
if (SUCCEEDED(pdisp->QueryInterface(IID_IWebBrowserApp, (void**)&pwba))) {
IServiceProvider *psp;
if (SUCCEEDED(pwba->QueryInterface(IID_IServiceProvider, (void**)&psp))) {
IShellBrowser *psb;
if (SUCCEEDED(psp->QueryService(SID_STopLevelBrowser,IID_IShellBrowser, (void**)&psb))) {
fFound = true;
// Grab the 11th entry in the VTable, which is BrowseObject
void** vtable = (*(void***)(psb));
ShellBrowser_BrowseObject = (BROWSEOBJECT)(vtable[11]);
psb->Release();
}
psp->Release();
}
pwba->Release();
}
pdisp->Release();
}
psw->Release();
}
if(fFound) {
if(MH_CreateHook(ShellBrowser_BrowseObject, &DetourBrowseObject, reinterpret_cast<void**>(&fpBrowseObject)) != MH_OK) {
return false;
}
if(MH_EnableHook(ShellBrowser_BrowseObject) != MH_OK) {
return false;
}
}
return true;
}
HRESULT WINAPI DetourBrowseObject(IShellBrowser* _this, PCUIDLIST_RELATIVE pidl, UINT wFlags) {
if(NavigateIsOkay(pidl, wFlags)) {
return fpBrowseObject(_this, pidl, wFlags);
}
else {
return S_FALSE;
}
}
I've never heard of API hooking used
to hook COM object functions.
Member functions of COM Objects are not really that different and can actually be hooked just fine if you stick to the usual guidelines for hooking. A few years ago, I had to hook COM components of a proprietary CRM solution to connect it to a database server. The application worked fine and has been running quite stable for several years.

Comparing objects with IDispatch to get main frame only (BHO)

I don't know if anyone familiar with BHO (Browser Helper Object), but an expert in c++ can help me too.
In my BHO I want to run the OnDocumentComplete() function only on the main frame - the first container and not all the Iframes inside the current page. (an alternative is to put some code only when this is the main frame).
I can't find how to track when is it the main frame that being populated.
After searching in google I found out that each frame has "IDispatch* pDisp", and I have to compare it with a pointer to the first one.
This is the main function:
STDMETHODIMP Browsarity::SetSite(IUnknown* pUnkSite)
{
if (pUnkSite != NULL)
{
// Cache the pointer to IWebBrowser2.
HRESULT hr = pUnkSite->QueryInterface(IID_IWebBrowser2, (void **)&m_spWebBrowser);
if (SUCCEEDED(hr))
{
// Register to sink events from DWebBrowserEvents2.
hr = DispEventAdvise(m_spWebBrowser);
if (SUCCEEDED(hr))
{
m_fAdvised = TRUE;
}
}
}
else
{
// Unregister event sink.
if (m_fAdvised)
{
DispEventUnadvise(m_spWebBrowser);
m_fAdvised = FALSE;
}
// Release cached pointers and other resources here.
m_spWebBrowser.Release();
}
// Call base class implementation.
return IObjectWithSiteImpl<Browsarity>::SetSite(pUnkSite);
}
This is where I want to be aware whether its the main window(frame) or not:
void STDMETHODCALLTYPE Browsarity::OnDocumentComplete(IDispatch *pDisp, VARIANT *pvarURL)
{
// as you can see, this function get the IDispatch *pDisp which is unique to every frame.
//some code
}
I asked this question on Microsoft forum and I got an answer without explaining how to actually implement that: http://social.msdn.microsoft.com/Forums/en-US/ieextensiondevelopment/thread/7c433bfa-30d7-42db-980a-70e62640184c
What jeffdav suggested is, to test wether the pDisp supports IWebBrowser2 via QueryInterface(), and if so, to check wether it is the same object as the one you stored in SetSite().
The QueryInterface() rules only require that a QI for IUnknown always results in the same pointer value, so you have to additionally QI to IUnknown and compare the resulting pointers.
This would lead to something like this in OnDocumentComplete():
IWebBrowser2* pBrowser = 0;
IUnknown *pUnk1=0, *pUnk2=0;
if( SUCCEEDED(pDisp ->QueryInterface(IID_IWebBrowser2, (void**)&pBrowser))
&& SUCCEEDED(pDisp ->QueryInterface(IID_IUnknown, (void**)&pUnk1))
&& SUCCEEDED(m_spBrowser->QueryInterface(IID_IUnknown, (void**)&pUnk2))
&& (pUnk1 == pUnk2))
{
// ... top-level
}
... or if you are using ATL (as m_spWebBrowser suggests):
CComQIPtr<IWebBrowser2> spBrowser(pDisp);
if(spBrowser && spBrowser.IsEqualObject(m_spWebBrowser)) {
// ...
}
Notice that I did not test this, I'm only rewriting what the guy on msdn said.
In ::SetSite you get an IUnknown pointer. Call IUnknown::QueryInterface on it (just like you're already doing), but instead use IID_IDISPATCH. Save this pointer somewhere, this pointer is the top level frame.
In ::OnDocumentComplete you're getting a IDispatch pointer, compare this one to the previous saved ptr and voĆ­la, if there is a match you're in the top level.