Context menu methods in shell extension aren't being used - c++

I am trying to write a shell extension that adds a menu item to the context menu for all file types. The code for the extension (in its entirety) is located here but I'll include some of the relevant parts below as I describe the problem.
The ContextMenu class implements the IShellExtInit and IContextMenu interfaces:
class ContextMenu : public IShellExtInit, IContextMenu
{
public:
// [...]
// IShellExtInit methods
STDMETHODIMP Initialize(PCIDLIST_ABSOLUTE pidlFolder,
IDataObject *pdtobj, HKEY hkeyProgID);
// IContextMenu methods
STDMETHODIMP GetCommandString(UINT_PTR idCmd, UINT uType, UINT *pReserved,
LPSTR pszName, UINT cchMax);
STDMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO pici);
STDMETHODIMP QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst,
UINT idCmdLast, UINT uFlags);
}
All of the methods are rigged with MessageBox() calls to indicate when they are called. There is only one small problem — they are never called.
The extension includes another class that implements IClassFactory. The implementation for IClassFactory::CreateInstance() is as follows:
STDMETHODIMP ClassFactory::CreateInstance(IUnknown *pUnkOuter, REFIID riid,
LPVOID *ppvObject)
{
if (pUnkOuter) {
return CLASS_E_NOAGGREGATION;
}
if (!ppvObject) {
return E_INVALIDARG;
}
*ppvObject = NULL;
ContextMenu *contextMenu = new ContextMenu;
HRESULT hResult = contextMenu->QueryInterface(riid, ppvObject);
contextMenu->Release();
return hResult;
}
I can confirm that this method is being called and I can also confirm that ContextMenu::QueryInterface() is then being called with riid set to IID_IContextMenu.
However, nothing happens after that. None of the IContextMenu methods are called. Neither is IShellExtInit::Initialize(). Why is this happening?
Test Environment
Visual Studio 2013 Express
Windows 7 Home Premium x64
Edit: I completely forgot to describe how the extension is being registered. The DllRegisterServer() function creates the following registry keys/values and checks the error codes to confirm that they are created:
Key: HKCR\CLSID\{CLSID}, Value: NULL, Data: NitroShellExt
Key: HKCR\CLSID\{CLSID}\InprocServer32, Value: NULL, Data: [path to DLL]
Key: HKCR\CLSID\{CLSID}\InprocServer32, Value: ThreadingModel, Data: Apartment
Key: HKCR\*\ShellEx\ContextMenuHandlers\NitroShellExt, Value: NULL, Data: {CLSID}
Key: HKLM\Software\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved, Value: {CLSID}, Data: NitroShare Context Menu
...where {CLSID} is {52A10783-C811-4C45-9A3D-221A962C8640}. I then use regsvr32 to register the extension and regedit to confirm that the keys/values do indeed exist.

Related

How to use EnumWindows with a COM wrapper in VBScript

I am writing a Windows API COM wrapper to be used in VBScript, and came up with a problem with callback controlled functions such as EnumWindows.
This is what I have currently:
STDMETHODIMP CWinAPI::WinAPI_EnumWindows(BSTR lpEnumFunc, int lParam, int *Result)
{
*Result = int(EnumWindows(WNDENUMPROC(lpEnumFunc), lParam))
return S_OK;
}
But, as I expected this didn't work and when I use this with VBScript, it crashes.
How can I export EnumWindows from my COM wrapper to use in VBScript and will VBScript support using it? If so, how can I use EnumWindowsProc callback function in VBScript?
UPDATE
BSTR WindowClassName = SysAllocString(L"");
WCHAR WindowTitle[8192];
BOOL CALLBACK EnumWindowsProc(
__in HWND hWnd,
__in LPARAM lParam
)
{
RealGetWindowClass(hWnd, WindowClassName, 100);
GetWindowText(hWnd, WindowTitle, 8192);
if (0 == wcscmp(WindowClassName, L"#32768"))
{
//<< NOW, HWND need to be caught by WSH and then show it. (I.E. WScript.Echo HWND) >>
}
return TRUE;
}
STDMETHODIMP CWinAPI::WinAPI_EnumWindows(int lParam)
{
EnumWindows(EnumWindowsProc, lParam);
return S_OK;
}
Dim WINAPI: Set WINAPI = WScript.CreateObject("WinAPIWrapperLib.WINAPI")
WINAPI.WinAPI_EnumWindows 0
Now I did above, but instead of this, I need WSH to know if a handle to specified window type is found and return HWND internally and show it from WSH, not directly from C++.(such as via a Message Box).
This function's lParam parameter can be set from VBScript, but how can I set EnumWindowsProc? Can it be done using GetRef or something similar in VBSript? But GeRef allows only one parameter. I want this EnumWindowsProc callback function also to be declared in VBScript, otherwise wrapping this function becomes useless.
I read this post from #Alex.K's comment and found it very useful, but I can't understand how to use it with EnumWindows's callback EnumWindowsProc.
Please help me more on this.

Call IConnectionPoint::Advise cause a crash

In my project, I wrote a component which will be called in a service(COM server). There is another process will get this component's interface and register a callback interface through connection point. So the service could use the callback interface to do some feedback.
But I found that when I use the IConnectionPoint::Advise to register my callback interface cause a crash.
I implement the connection point manually. Here are part of my code:
class ATL_NO_VTABLE CUploadManager :
public CComObjectRootEx<CComMultiThreadModel>,
public CComCoClass<CUploadManager, &CLSID_UploadManager>,
public IUploadManager,
public IConnectionPointContainer,
public IConnectionPoint
...
// IConnectionPointContainer Functions
STDMETHODIMP EnumConnectionPoints(IEnumConnectionPoints **ppEnum);
STDMETHODIMP FindConnectionPoint(REFIID riid, IConnectionPoint **ppCP);
// IConnectionPoint Functions
STDMETHODIMP GetConnectionInterface(IID *pIID);
STDMETHODIMP GetConnectionPointContainer(IConnectionPointContainer **ppCPC);
STDMETHODIMP Advise(IUnknown *pUnkSink, DWORD *pdwCookie);
STDMETHODIMP Unadvise(DWORD dwCookie);
STDMETHODIMP EnumConnections(IEnumConnections **ppEnum);
In the client, I have get the component interface already, then I get the connection point and try to call function Advise:
...
CComPtr<IConnectionPointContainer> pCPC;
hr = pUnknown->QueryInterface(IID_IConnectionPointContainer, (LPVOID *)&pCPC);
if (FAILED(hr))
{
return ;
}
CComPtr<IConnectionPoint> pConnectionPoint;
hr = pCPC->FindConnectionPoint(__uuidof(_IEvents), &pConnectionPoint);
if (SUCCEEDED(hr))
{
DWORD dwCookie = 0;
CDataCallback* pCallback = new CDataCallback();
IUnknown* pUnknown = NULL;
pCallback->QueryInterface(IID_IUnknown, (void**)&pUnknown);
hr = pConnectionPoint->Advise(pUnknown, &dwCookie);
...
All interface pointers could be got successfully, but when I call Advise, the crash occurs. The strange thing is the crash is not happened in the Advise implementation, it seems occurs in the RPC call process, the call stack is like this:
003d0070() <----crash here
combase.dll!76eea3ab()
[Frames below may be incorrect and/or missing, no symbols loaded for combase.dll]
combase.dll!76ee9d00()
rpcrt4.dll!7612a53d()
mfc90ud.dll!CDialog::OnCmdMsg
...
But if the first parameter of Advise is NULL, the function Advise could be executed.
Here is the Sink code implemented in client:
class CDataCallback : public _IEvents
{
public:
CDataCallback() {}
~CDataCallback() {}
HRESULT __stdcall QueryInterface(REFIID iid, LPVOID* ppInterface)
{
*ppInterface = this;
return S_OK;
}
ULONG STDMETHODCALLTYPE AddRef()
{
return 1;
}
ULONG STDMETHODCALLTYPE Release()
{
return 0;
}
HRESULT __stdcall TestFunc()
{
...
return S_OK;
}
};
The interface _IEvents is generated in the component which will be used as a callback in the connection point. I just use this class to test the connection point, so the implementation is very simple.
I have no idea about how this crash occurs.
Thanks for all your help!
The problem is likely to be in your CDataCallback class. It's QueryInterface implementation is unsafe and returns interface pointer incorrectly.
class CDataCallback : public _IEvents
HRESULT __stdcall QueryInterface(REFIID iid, LPVOID* ppInterface)
{
*ppInterface = this;
return S_OK;
}
You have to check iid and return E_NOINTERFACE in case requested interface is not _IEvents. Basically you can set a breakpoint there and see if you have a call there prior to crash and check the arguments.
Your sink might be queried for other interfaces (IMarhsal etc) and you have to properly indicate that you are not implementing them, instead of returning unmatching pointer, use of which leads to undefined behavior.

Why are all references to my IDispatch object not released?

I'm hosting an IWebBrowser2 control in my C++ program using nothing but plain Win32 (no mfc, atl, wtl etc). On DISPID_NAVIGATECOMPLETE2 I add a custom object to be accessed from javascript running on the displayed webpage.
To add the custom object I call InvokeEx with DISPATCH_PROPERTYPUT and a DISPPARAMS structure with a pointer to my custom object.
During the call to InvokeEx the AddRef function of my custom object is called and I increment its reference counter. But the object never gets a call to its Release function, so the reference counter never decreases down to zero again.
Who is responsible for calling Release() after AddRef() has been called in InvokeEx?
EDIT: (Adding some code)
This is the code that adds my custom object to the IHTMLWindow2. custObj points to my custom object
IHTMLWindow2 *win = NULL;
GetDoc()->get_parentWindow(&win);
IDispatchEx *winEx = NULL;
win->QueryInterface(&winEx);
DISPID dispid;
HRESULT hr = winEx->GetDispID(objName, fdexNameEnsure, &dispid); //objName is "JSObject"
DISPID namedArgs[] = {DISPID_PROPERTYPUT};
DISPPARAMS params;
params.rgvarg = new VARIANT[1];
params.rgvarg[0].pdispVal = custObj;
params.rgvarg[0].vt = VT_DISPATCH;
params.rgdispidNamedArgs = namedArgs;
params.cArgs = 1;
params.cNamedArgs = 1;
hr = winEx->InvokeEx(dispid, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT, &params, NULL, NULL, NULL);
This is the object that I'm adding (some private members have been left out for brevity)
class JSObject : public IDispatch {
private:
long ref;
public:
JSObject();
// IUnknown
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppv);
virtual ULONG STDMETHODCALLTYPE AddRef();
virtual ULONG STDMETHODCALLTYPE Release();
// IDispatch
virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount(UINT *pctinfo);
virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT iTInfo, LCID lcid,
ITypeInfo **ppTInfo);
virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID riid,
LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId);
virtual HRESULT STDMETHODCALLTYPE Invoke(DISPID dispIdMember, REFIID riid,
LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult,
EXCEPINFO *pExcepInfo, UINT *puArgErr);
};
EDIT 2:
Now that it seems to be working like it should I decided to put it on github.
https://github.com/Tobbe/CppIEEmbed. Please fork and improve if you can :)
Well, you are assigning a property, aren't you? As long as this property exists and refers to your object, it will have a reference added.
If you want the remote object to release your reference you should assign NULL to the property, or some other object.

Providing an IDispatch implementation for a connection point client

I've written a simple COM DLL inproc server with a single simple COM object. The COM object implements a connection point.
I know how to create an ATL client that derives from IDispEventImpl, and uses a sink map to simplify this process.
But, for the purposes of demonstration, I'd like to create a win32 console application that uses a class that calls my simple COM object, then acts as a connection point sink.
I've got no idea how to provide an implementation of IDispatch - can someone recommend documentation on this, as I can't find any (I've got ATL Internals, but this doesn't seem to cover what I need ).
Here's the class I've already got:
#pragma once
#include <iostream>
using namespace std;
// Because we're implementing a connection points sink (_IPogFarmEvents)
// in a non-ATL class, we must provide implementations for IUnknown and IDispatch.
class KidWithAPogFarm : public _IPogFarmEvents
{
private:
DWORD m_dwRefCount;
LONG m_lNumPogs;
public:
KidWithAPogFarm() :
m_dwRefCount (0),
m_lNumPogs (0)
{
}
~KidWithAPogFarm()
{
}
// -- IUnknown
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject)
{
if (iid == DIID__IPogFarmEvents)
{
m_dwRefCount++;
*ppvObject = (void *)this;
return S_OK;
}
if (iid == IID_IUnknown)
{
m_dwRefCount++;
*ppvObject = (void *)this;
return S_OK;
}
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE AddRef()
{
m_dwRefCount++;
return m_dwRefCount;
}
ULONG STDMETHODCALLTYPE Release()
{
ULONG l;
l = m_dwRefCount--;
if ( 0 == m_dwRefCount)
delete this;
return l;
}
// -- IDispatch
STDMETHODIMP GetTypeInfoCount(UINT *pctinfo)
{
return E_NOTIMPL;
}
STDMETHODIMP GetTypeInfo( UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo )
{
return E_NOTIMPL;
}
STDMETHODIMP GetIDsOfNames(const IID &riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId )
{
return E_NOTIMPL;
}
STDMETHODIMP Invoke(DISPID dispIdMember, const IID &riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr )
{
return E_NOT_IMPL;
}
// -- IAntFarmEvents
STDMETHODIMP OnFarmCreated(LONG lInitialPopulation)
{
m_lNumPogs = lInitialPopulation;
cout << "The kid has a pog farm with " << m_lNumPogs << " pogs " << endl;
return S_OK;
}
};
Since you already have ATL you can examine its sources and see how IDispatchImpl does all that stuff. IDispatch methods are implemented therehby reading data from the type library in the same module since it's the easiest and most reliable way when a type library is already present.
It's also worth noting that it's a rather hard topic for making a demonstration on it - you'll need to write a lot of code that doesn't really bring any insight. IMO you'll be much better off if you implement an events interface that doesn't inherit from IDispatch but rather inherits directly from IUnknown - this will demonstrate how events work without dragging too much of attention to IDispatch inner workings.
I think the easiest way of doing this is through CreateStdDispatch
You can use this IDispatch implementation.
It's not exactly what you're looking for, but FireBreath uses IDispatchEx and connection points to provide an ActiveX control that runs in IE. Because FireBreath is an abstraction to allow plugins to be written once and used in all major browsers, the IDispatch interface needed to be written by hand -- including connection points.
The code may be a little confusing, since there is a templated mixin class used to provide IDispatch and ConnectionPoints to two different COM object classes, but it may help.
Mixin class
ActiveX Control
Second COM control (not OLE)
You've already accepted an answer, but perhaps it will still help. Sorry I didn't see the question sooner.

How to handle IHttpSecurity::OnSecurityProblem having a IWebBrowser2 object

I can't seem to understand how i give my implementation of the IHttpSecurity::OnSecurityProblem to my IWebBrowser2 object.
I know that i need to implement a class something like this:
class CServiceProvider : public IServiceProvider
{
public:
CServiceProvider();
~CServiceProvider();
// IUnknown
ULONG STDMETHODCALLTYPE AddRef();
ULONG STDMETHODCALLTYPE Release();
STDMETHODIMP QueryInterface(REFIID iid, void ** ppvObject);
//QueryService
STDMETHODIMP QueryService(REFGUID guidService,REFIID riid,void **ppv);
private:
ULONG m_ulRefCnt;
};
And in the QueryService function when it requests the IID_IHttpSecurity i return my implementation of the IHttpSecurity interface.
But my problem is how i set the my service provider implementation on the IWebBrowser2 object and when?
My code is something like this:
IWebBrowser2 *_Browser;
IServiceProvider* pServiceProvider = NULL;
_Browser->QueryInterface(
IID_IServiceProvider,
(void**)&pServiceProvider);
IHttpSecurity* pi;
pServiceProvider->QueryService(IID_IHttpSecurity, &pi);
_Browser->Navigate(url.AllocSysString(),
&flags,
&target_frame_name,
&post_data,
&headers);
The question this works like i'm thinking if yes how i do this then, and if not can you explain how this works and can be setted?
PS: i only whant to implement the IID_IHttpSecurity interface, all other interfaces requested on the QueryService should do the default implementation provided by the system...
Thanks
I already figure out how this is done.
Using MFC we only need to implement CCustomOccManager that implements the COccManager in witch the implementation of CreateSite function returns an implementation of our COleControlSite (example CCustomControlSite). In this class you will need to override at least the QueryService function of IServiceProvider interface and in this implementation supply yours IHttpSecurity implementation (when required by the interface).
In the end the we register all this in the App InitInstance using the MFC function AfxEnableControlContainer.
Code:
// declare our custom control site to serve as the client site
class CCustomControlSite:public COleControlSite
{
public:
// constructor associates this site with the container
CCustomControlSite(COleControlContainer *pCnt):COleControlSite(pCnt){}
protected:
DECLARE_INTERFACE_MAP();
BEGIN_INTERFACE_PART(ServiceProvider, IServiceProvider)
// declare the interface method(s)
STDMETHOD(QueryService) (
/* [in] */ REFGUID guidService,
/* [in] */ REFIID riid,
/* [out] */ void __RPC_FAR *__RPC_FAR *ppvObject);
END_INTERFACE_PART(ServiceProvider)
};
// declare our control container manager
class CCustomOccManager :public COccManager
{
public:
CCustomOccManager(){}
// creates an instance of our custom control site and associates it with the container
COleControlSite* CreateSite(COleControlContainer* pCtrlCont)
{
CCustomControlSite *pSite = new CCustomControlSite(pCtrlCont);
return pSite;
}
};
In the App InitInstance simple call AfxEnableControlContainer on our implementation:
// Create a custom control container manager class so we can overide the client site
CCustomOccManager *pMgr = new CCustomOccManager;
// Set our control containment up but using our control container
// management class instead of MFC's default
AfxEnableControlContainer(pMgr);
If someone has the knowledge on how this is done without using MFC please let me know.
Thanks
Judging by the remarks in the documentation for IServiceProvider, it seems like your IOleClientSite object needs to implement IServiceProvider.