Component Object Model via C++ - object

I want to use object of my software using COM interface my code is :
::CLSIDFromProgID(OLESTR("SGNSAutomation.SGNSApplication"), &clsid);
IID iid;
HRESULT hr = CoCreateInstance(clsid, NULL, CLSCTX_ALL,
IID_IDispatch, (LPVOID*)&pWMPDispatch);
IDispatch * pdisp = (IDispatch *)NULL;
DISPID dispid;
DISPPARAMS params = {NULL};
OLECHAR * Name = OLESTR("addSimulationCase");
HRESULT hresult =pWMPDispatch->GetIDsOfNames(IID_NULL,
&Name,1,LOCALE_SYSTEM_DEFAULT,&dispid);
hresult =pWMPDispatch->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT,
DISPATCH_METHOD, &params, NULL, NULL,
NULL);
//pdisp IDispatch
_ASSERT(hr==S_OK);
I don't know what is exactly param that is one of input argument of invoke.
please Help me I am a dummy in C++.

Related

dynamic_cast of CWnd to CComboBox is yeilding a null pointer in OnSize function

Code:
void CChristianLifeMinistryEditorDlg::OnSize(UINT nType, int cx, int cy)
{
CResizingDialog::OnSize(nType, cx, cy);
const CWnd* pFocus = GetFocus();
CComboBox* pFocusCombo = nullptr;
if (pFocus != nullptr)
{
if (pFocus->GetParent()->IsKindOf(RUNTIME_CLASS(CComboBox)))
{
pFocusCombo = dynamic_cast<CComboBox*>(GetFocus()->GetParent());
}
}
for (CWnd* pWnd = GetWindow(GW_CHILD); pWnd != nullptr; pWnd = pWnd->GetNextWindow(GW_HWNDNEXT))
{
if (pWnd == pFocusCombo)
{
// TODO: Sadly, by now, the control has already got all the text selected.
//pFocusCombo->SetEditSel(LOWORD(dwEditSel), HIWORD(dwEditSel));
}
else if (pWnd->IsKindOf(RUNTIME_CLASS(CComboBox)))
{
// This only works for combo boxes that are bound to controls
auto* pCombo = dynamic_cast<CComboBox*>(pWnd);
pCombo->SetEditSel(-1, -1);
}
else
{
CString strClassName;
if (::GetClassName(pWnd->GetSafeHwnd(), strClassName.GetBuffer(_MAX_PATH), _MAX_PATH))
{
if (strClassName == _T("ComboBox"))
{
auto* pCombo = (CComboBox*)pWnd;
//auto* pCombo = dynamic_cast<CComboBox*>(pWnd);
pCombo->SetEditSel(-1, -1);
}
}
strClassName.ReleaseBuffer();
}
}
if (m_pHtmlPreview != nullptr)
{
m_lblHtmlPreview.GetWindowRect(m_rctHtmlPreview);
ScreenToClient(m_rctHtmlPreview);
m_pHtmlPreview->MoveWindow(m_rctHtmlPreview);
}
}
I display the whole function for context. But I am specifically interested in this bit:
CString strClassName;
if (::GetClassName(pWnd->GetSafeHwnd(), strClassName.GetBuffer(_MAX_PATH), _MAX_PATH))
{
if (strClassName == _T("ComboBox"))
{
auto* pCombo = (CComboBox*)pWnd;
//auto* pCombo = dynamic_cast<CComboBox*>(pWnd);
pCombo->SetEditSel(-1, -1);
}
}
strClassName.ReleaseBuffer();
During code analysis updates I had many situations where I had to update C-Style casts. A lot of the time I was able to use static_cast, but, in some instances the compiler would then tell me I should use dynamic_cast.
I then found that my application was not working correctly and in debug mode isolated it to this bit:
//auto* pCombo = (CComboBox*)pWnd;
auto* pCombo = dynamic_cast<CComboBox*>(pWnd);
It turned out that the cast pointer pCombo was null. Yet, this never happens when I use the C-Style cast. As a result I have reverted to the C-Style cast. I saw this discussion (MFC Classes and C++ style casts) but I can't see that this is the reason (temporary pointers).
What cast should I be using that I can rely on in this situation?
C-style casting will try different c++ casting, it may choose reinterpret_cast static_cast. This is converting CWnd* to CComboBox*, for example:
CWnd* wnd = GetDlgItem(IDC_COMBO1);
CComboBox* combo = (CComboBox*)wnd;
In general, parent class can't "always" be converted to child. It depends if CComboBox m_combobox; for that ID was created.
A) m_combobox does exist:
In this case our wnd can be a reference to m_combobox.
CWnd::GetDlgItem etc. cast &m_combobox to CWnd*, they pass it around.
dynamic_cast checks it and converts back to CComboBox*.
MFC's IsKindOf will confirm if m_combobox was created.
B) m_combobox doesn't exist:
In this case our wnd is CWnd* object. MFC never created CComboBox for that control.
dynamic_cast tests it, can't convert to CComboBox*
static_cast works if wnd's classname is "ComboBox"
The code below should be okay. In this case you can skip dynamic_cast if you want, rely on static_cast. But it's better to use dynamic_cast if possible.
CComboBox* ptr = nullptr;
if (wnd->IsKindOf(RUNTIME_CLASS(CComboBox)))
ptr = dynamic_cast<CComboBox*>(wnd);
if(!ptr)
{
CString classname;
::GetClassName(wnd->m_hWnd, classname.GetBuffer(_MAX_PATH), _MAX_PATH);
classname.ReleaseBuffer();
if(classname == L"ComboBox")
ptr = static_cast<CComboBox*>(wnd);
}

::CoResumeClassObect() fails on Windows Server 2012 R2 with HRESULT : 0x800706c6(The array bounds are invalid)

I have a COM Server , and I want to use it as a service. My application has a installer component which creates a user (CN_Service) in local system and install this COM server as a service using below command:
Connect.exe /service /noreinstall /user:CN_Service /password:somePassword /depends:lanmanworkstation
I have another component, which is responsible for starting this installed service. In its winmain(), I am using below code to register the COM server class objects (in SUSPENDED mode), it successfully registers the objects and returns HRESULT as S_OK which is as expected.
int CAppModule::WinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR /* lpCmdLine */, int nShowCmd)
{
::AfxSetResourceHandle(hInstance);
_strServiceName.LoadString(IDS_SRVL_SERVICENAME);
_strDisplayName.LoadString(IDS_SRVL_DISPLAYNAME);
VERIFY(gNTEventLog.SetSource(_strDisplayName));
// Copy parameters
m_hInstance = hInstance;
m_nCmdShow = nShowCmd;
_strCmdLine = ::GetCommandLine();
_qappmodel->InitCOMSupport(); //::CoInitializeEx(NULL, COINIT_MULTITHREADED);
// Process command line options
bool bContinue = true;
int nExitCode = 0;
if (ProcessCommandLine(_strCmdLine, &bContinue) && bContinue)
{
if (_patlmodule != NULL)
{
//_patlmodule is an interface pointer and private member of CAppModule
HRESULT hr = _patlmodule->RegisterClassObjects(CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER, REGCLS_MULTIPLEUSE | REGCLS_SUSPENDED);
if (FAILED(hr))
{
ASSERT_NOT_REACHED();
gNTEventLog.LogHR(_T("Failed to register the class objects"), hr);
return 2;
}
}
nExitCode = InternalWinMain();
if (_patlmodule != NULL)
{
_patlmodule->RevokeClassObjects();
}
}
_qappmodel->UninitCOMSupport();
// When we get here, the service has been stopped
return nExitCode;
}
But when I try to resume the registered class objects using ::CoResumeClassObjects(), it throws an error ‘Failed to resume class objects’ with HRESULT value:
800706c6 (The array bounds are invalid)
I am using below code to resume the class objects:
BOOL CAppModule::InitInstance()
{
// Increment usage count
if (_patlmodule != NULL)
{
_patlmodule->Lock();
HRESULT hr = ::CoResumeClassObjects(); //Fails here
if (FAILED(hr))
{
ASSERT_NOT_REACHED();
if (hr == CO_E_WRONG_SERVER_IDENTITY)
{
gNTEventLog.LogHR(_T("Failed to resume class objects (registered as a service?)"), hr);
}
else
{
gNTEventLog.LogHR(_T("Failed to resume class objects"), hr);
}
return FALSE;
}
}
return TRUE;
}
Problem Statement: The important thing is that, I want to run this code on Windows Server 2012 R2 machine, where the method ::CoResumeClassObjects() fails. This same piece of code runs fine on Windows Server 2008 machine.
Please suggest me whether server2012 box has anything to do with ::CoResumeClassObjects() method.
Also I am creating a separate local user(which is an app requirement) for registering the exe as service in code and responsible for starting/stopping service. Can It be a problem on win server 2012 ?
Any help would be appreciated…

IXMLDOMDocument memory Leak Issue

I have a COM inproc server test application that uses IXMLDOMDocument to write data and send it back to COM client.I uses get_xml() to get BSTR. But when applications ends it's consuming almost > 20 MB memory while if I don't use COM inproc server it uses < 1 MB.
My COM Server Interface method is
[
object,
uuid(BF798ED1-DCDD-4B29-B552-3A17F1D7E4CF),
dual,
nonextensible,
pointer_default(unique)
]
interface IMoLauncher : IDispatch{
[id(1)] HRESULT GetXML([out] BSTR* bStr);
};
it's code is
STDMETHODIMP CMoLauncher::GetXML(BSTR* bStr)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
BOOL result = FALSE;
IXMLDOMDocument* pDoc = NULL;
HRESULT hr = CoCreateInstance(CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER,
IID_IXMLDOMDocument, (void**)&pDoc);
if ( SUCCEEDED(hr) )
{
result = TRUE;
IXMLDOMNode* pEntityNode = InsertDOMElement(pDoc, NULL, L"Entity", NULL);
SerializeXML(pDoc, pEntityNode);
pDoc->get_xml(bStr);
pDoc->Release();
}
return result;
}
And usage code in client is
CoInitialize(NULL);
IMoLauncher* launcher = NULL;
IUnknown* unknown = NULL;
HRESULT result = CoCreateInstance(CLSID_MoLauncher,NULL,CLSCTX_INPROC_SERVER,IID_IMoLauncher,(void**)&launcher);
if(result==S_OK)
{
for(int i=0;i<iterationCount;i++)
{
BSTR bStr;
launcher->GetXML( &bStr);
printf("Iteration %d\n",i);
::SysFreeString(bStr);
}
}
launcher->Release();
CoUninitialize();
You Need to release pEntityNode too!
Every COM pointer returned by an Interface or COM function must be released. You may use smart pointers to avoid such mistakes.
The IXMLDOMNode* returned from CMoLauncher::InsertDOMElement is never released, that's a big leak.
You need to add Release calls for:
The first InsertDOMElement call in CMoLauncher::SerializeXML.
The InsertDOMElement calls in the loop in the same function (adding a local variable in order to do so (return value of InsertDOMElement)
The InsertDOMElement call in CMoLauncher::GetXML (spotted by xMRI)

My BHO does not work properly. DocumentComplete does not trigger

I am doing a BHO for Internet Explorer. The problem is only the SetSite is working. BUt the DocumentComplete does not been triggered. I need some help in pointing me what is I am doing wrong.
Here is what I declared inside my header file:
class ATL_NO_VTABLE CStockBar :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CStockBar, &CLSID_StockBar>,
public IDeskBand,
public IObjectWithSite,
public IObjectWithSiteImpl<CStockBar>,
public IInputObject,
public IDispatchImpl<IStockBar, &IID_IStockBar, &LIBID_MOTLEYFOOLLib>,
public IDispEventImpl<1, CStockBar, &DIID_DWebBrowserEvents2, &LIBID_SHDocVw, 1, 1>
{
public:
CStockBar();
DECLARE_REGISTRY_RESOURCEID(IDR_STOCKBAR)
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_CATEGORY_MAP(CStockBar)
// IMPLEMENTED_CATEGORY(CATID_InfoBand)
// IMPLEMENTED_CATEGORY(CATID_CommBand)
// IMPLEMENTED_CATEGORY(CATID_DeskBand)
END_CATEGORY_MAP()
BEGIN_COM_MAP(CStockBar)
COM_INTERFACE_ENTRY(IStockBar)
// COM_INTERFACE_ENTRY(IInputObject)
COM_INTERFACE_ENTRY(IOleWindow)
COM_INTERFACE_ENTRY_IID(IID_IDockingWindow, IDockingWindow)
COM_INTERFACE_ENTRY(IObjectWithSite)
COM_INTERFACE_ENTRY_IID(IID_IDeskBand, IDeskBand)
COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()
BEGIN_SINK_MAP(CStockBar)
SINK_ENTRY_EX(1, DIID_DWebBrowserEvents2, DISPID_DOCUMENTCOMPLETE, OnDocumentComplete)
END_SINK_MAP()
Here is my SetSite and DocumentComplete functions:
STDMETHODIMP CStockBar::SetSite(IUnknown* pUnkSite)
{
//If a site is being held, release it.
if(m_pSite)
{
m_ReflectWnd.GetToolBar().SetBrowser(NULL);
m_pSite->Release();
m_pSite = NULL;
}
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
{
if (m_fAdvised)
{
DispEventUnadvise(m_spWebBrowser);
m_fAdvised = FALSE;
}
m_spWebBrowser.Release();
}
//If punkSite is not NULL, a new site is being set.
if(pUnkSite)
{
//Get the parent window.
IOleWindow *pOleWindow = NULL;
m_hWndParent = NULL;
if(SUCCEEDED(pUnkSite->QueryInterface(IID_IOleWindow, (LPVOID*)&pOleWindow)))
{
pOleWindow->GetWindow(&m_hWndParent);
pOleWindow->Release();
}
if(!::IsWindow(m_hWndParent))
return E_FAIL;
if(!RegisterAndCreateWindow())
return E_FAIL;
//Get and keep the IInputObjectSite pointer.
if(FAILED(pUnkSite->QueryInterface(IID_IInputObjectSite, (LPVOID*)&m_pSite)))
{
return E_FAIL;
}
IWebBrowser2* s_pFrameWB = NULL;
IOleCommandTarget* pCmdTarget = NULL;
HRESULT hr = pUnkSite->QueryInterface(IID_IOleCommandTarget, (LPVOID*)&pCmdTarget);
if (SUCCEEDED(hr))
{
IServiceProvider* pSP;
hr = pCmdTarget->QueryInterface(IID_IServiceProvider, (LPVOID*)&pSP);
pCmdTarget->Release();
if (SUCCEEDED(hr))
{
hr = pSP->QueryService(SID_SWebBrowserApp, IID_IWebBrowser2, (LPVOID*)&s_pFrameWB);
pSP->Release();
_ASSERT(s_pFrameWB);
m_ReflectWnd.GetToolBar().SetBrowser(s_pFrameWB);
s_pFrameWB->Release();
}
}
}
return S_OK;
}
void STDMETHODCALLTYPE CStockBar::OnDocumentComplete(IDispatch *pDisp, VARIANT *pvarURL)
{
// Retrieve the top-level window from the site.
HWND hwnd;
HRESULT hr = m_spWebBrowser->get_HWND((LONG_PTR*)&hwnd);
if (SUCCEEDED(hr))
{
// Output a message box when page is loaded.
MessageBox(hwnd,"Hello World!","BHO", MB_OK);
}
}
You should use SINK_ENTRY_INFO with IDispEventImpl as pointed in
http://msdn.microsoft.com/en-us/library/2wt7d0s4(v=vs.80).aspx
You are probably running your code in release as otherwise you would have get a assertion because idispeventimpl wouldn't be able to retrieve the typelib for DIID_DWebBrowserEvents2. DIID_DWebBrowserEvents2 doesn't have a typelib because it's a disp interface.
Declare in your header:
extern ATL::_ATL_FUNC_INFO DocumentComplete2Struct;
BEGIN_SINK_MAP(CStockBar)
SINK_ENTRY_INFO(1, __uuidof(DWebBrowserEvents2), DISPID_DOCUMENTCOMPLETE, OnDocumentComplete, &DocumentComplete2Struct);
END_SINK_MAP()
In your CPP :
ATL::_ATL_FUNC_INFO DocumentComplete2Struct = {CC_STDCALL, VT_EMPTY, 2, {VT_DISPATCH, VT_BYREF|VT_VARIANT}};
I can't see anything that stands out as definably incorrect, so here is another example hacked out of some working code, includes only the bits needed for site to keep it simple.
One thing that may be an issue is - m_spWebBrowser if this is the ATL class then it doesn't like you overwriting existing using the address of once it is set. It may be returning false at which point you won't be running advise.
HRESULT hr = pUnkSite->QueryInterface(IID_IWebBrowser2, (void**)&m_spWebBrowser);
declaration h
class ATL_NO_VTABLE CStockBar:
public CComObjectRootEx<CComGlobalsThreadModel>,
public CComCoClass<CStockBar, &CLSID_StockBar>,
public IObjectWithSiteImpl<CStockBar>,
public IDispEventImpl<1, CStockBar, &__uuidof(DWebBrowserEvents2), &LIBID_SHDocVw, 1, 0>{
protected:
typedef IDispEventImpl<1, CStockBar, &__uuidof(DWebBrowserEvents2), &LIBID_SHDocVw, 1, 0> base_BrowserDispEvents;
typedef IObjectWithSiteImpl<CStockBar> base_objectWithSite;
BEGIN_SINK_MAP(CStockBar)
// we use this variation - think it resolves the same
SINK_ENTRY_EX(1, (__uuidof(DWebBrowserEvents2)), DISPID_DOCUMENTCOMPLETE, OnDocumentComplete)
SINK_ENTRY_EX(1, DIID_DWebBrowserEvents2, DISPID_DOCUMENTCOMPLETE, OnDocumentComplete)
END_SINK_MAP()
CComQIPtr<IWebBrowser2> m_spBrowser;
Implementation cpp
STDMETHODIMP CStockBar::SetSite(IUnknown* pUnkSite) {
// Detach the web browser and site
if (m_spBrowser) {
base_BrowserDispEvents::DispEventUnadvise(m_spBrowser);
m_spBrowser.Release();
}
if (pUnkSite) {
m_spBrowser = pUnkSite;
if (m_spBrowser)
{
base_BrowserDispEvents::DispEventAdvise(m_spBrowser);
}
}
return base_objectWithSite::SetSite(pUnkSite);

How to find the function name, which is going to be invoked?

I got:
InvokeHelper(0x18, DISPATCH_METHOD, VT_I4, (void*)&result, NULL);
How to get function name, if we have the object method or property
specified by dwDispID = 0x18?
void AFX_CDECL InvokeHelper(
DISPID dwDispID,
WORD wFlags,
VARTYPE vtRet,
void* pvRet,
const BYTE* pbParamInfo,
...
);
Here's a simple sample of how to fetch the name
void CTestDlg::OnTypeinfo()
{
HRESULT hr = S_OK;
COleDispatchDriver sc;
sc.CreateDispatch("Omtool.ServConnect.1"); // change for your type
CComPtr<ITypeInfo> pti;
hr = sc.m_lpDispatch->GetTypeInfo(0, GetUserDefaultLCID(), &pti);
ASSERT(SUCCEEDED(hr));
CComBSTR bstrName;
UINT nCount = 0;
hr = pti->GetNames(0x2, &bstrName, 1, &nCount); // change 0x2 for your ID
ASSERT(SUCCEEDED(hr));
}
I would try to get a ITypeInfo interface on the object (CWnd::GetControlUnknown, IUnknown::QueryInterface). Then you can use the ITypeInfo::GetNames function with your member ID (0x18) to get the name of the method.

Resources