The point is that you should not introduce the CLR into the shell, what you
are doing is exactly that, the fact that you call C# code through COM
interop or not doesn't matter, you load the CLR into the shell which is what
you shouln't do.
As the blog says:
Unfortunately unmanaged C++ is really the only way to go here.
Willy.
[quoted text, click to view] "gilad" <gilad@arbingerBADSPAMBOTsys.com> wrote in message
news:ukL$FCJPGHA.3016@tk2msftngp13.phx.gbl...
| Hi, I am trying to get an unmanaged C++ Shell Extension Handler to act
| as a COM client to a C# COM object. Since it is recommended to not do
| managed Shell Extension Handlers--
|
|
http://blogs.msdn.com/junfeng/archive/2005/11/18/494572.aspx |
| --and since I prefer to program as much in C# as I can, I came up with
| the idea to create the shell handler in C++, and register a C# COM
| object that the handler can call to do the rest of work.
|
| I've successfully created the C# COM object, and tested it with an
| unmanaged C++ executable acting as the COM client (importing the .TLB,
etc).
|
| Now that I've incorporated it into my handler code, the "FAILED(hr)"
| test after CoCreateInstance() happens. Is there something I'm
| missing? Here is what I've got, in abbreviated form:
|
| The C# COM object is simple and exposes a single method whose signature is
|
|
| void ShowDialog(string sText);
|
|
| The C++ handler/COM client header file is
|
|
| #pragma once
| #define STRICT
| #ifndef _WIN32_WINNT
| #define _WIN32_WINNT 0x0400
| #endif
| #define _ATL_ATTRIBUTES
| #define _ATL_APARTMENT_THREADED
| #define _ATL_NO_AUTOMATIC_NAMESPACE
| #include <atlbase.h>
| #include <atlcom.h>
| #include <atlwin.h>
| #include <atltypes.h>
| #include <atlctl.h>
| #include <atlhost.h>
|
| // Shell features
|
| #include <shlobj.h>
|
|
|
| // Here is where I import the Type Libraries,
| // including the C# COM TLB.
|
| #import <mscorlib.tlb> raw_interfaces_only
|
| #import "CSharpCOMWin.tlb" no_namespace named_guids
|
|
|
| using namespace ATL;
|
|
|
|
| // The module attribute is specified in order to implement DllMain,
| // DllRegisterServer and DllUnregisterServer
| [ module(dll, name = "MyShellHandler", helpstring = "MyShellHandler 1.0
| Type Library") ];
| [ emitidl ];
|
|
|
|
| // CMyShellHandler object declaration
| [
| coclass,
| com_interface_entry ("COM_INTERFACE_ENTRY_IID(IID_IContextMenu,
| IContextMenu)"),
| threading("apartment"),
| vi_progid("MyShellHandler.TagSet"),
| progid("MyShellHandler.TagSet.1"),
| version(1.0),
| uuid("8D1733BD-1AB4-4e26-85A8-CFD39C003C3D"),
| helpstring("MyShellHandler Class")
| ]
| class ATL_NO_VTABLE CMyShellHandler :
| public IShellExtInit,
| public IContextMenu
| {
| public:
|
| LPITEMIDLIST m_pIDFolder; //The folder's PIDL
| TCHAR m_szFile[MAX_PATH]; //The file name
| IDataObject *m_pDataObj; //The IDataObject pointer
| HKEY m_hRegKey; //The file or folder registry key
|
|
| // Constructor
|
| CMyShellHandler()
| { }
|
|
|
| DECLARE_PROTECT_FINAL_CONSTRUCT()
|
| HRESULT FinalConstruct()
| {
| return S_OK;
| }
|
| void FinalRelease()
| { }
|
|
| // IShellExtInit
| STDMETHOD(Initialize)(
| LPCITEMIDLIST pIDFolder, IDataObject *pDataObj, HKEY hRegKey );
|
|
| // IContextMenu
| STDMETHOD(GetCommandString)(
| UINT_PTR idCmd, UINT uFlags, UINT *pwReserved,
| LPSTR pszName, UINT cchMax );
|
| STDMETHOD(InvokeCommand)( LPCMINVOKECOMMANDINFO pici );
|
| STDMETHOD(QueryContextMenu)(
| HMENU hmenu, UINT indexMenu, UINT idCmdFirst,
| UINT idCmdLast, UINT uFlags );
|
|
| };
|
|
|
| Then, in the "InvokeCommand()" method of the handler, I have the
| following code, which *should* send the C# COM object the path of the
| file that has been right-clicked, but instead fails:
|
|
|
| STDMETHODIMP
| CMyShellHandler::InvokeCommand ( LPCMINVOKECOMMANDINFO pici )
| {
|
| // If lpVerb really points to a string, ignore this
| // function call and bail out.
|
| if ( 0 != HIWORD( pici->lpVerb ))
| return E_INVALIDARG;
|
| // Get the command index - the only valid one is 0.
|
| switch ( LOWORD( pici->lpVerb ))
| {
| case 0:
| {
|
| // Message box test...
| TCHAR szMsg [MAX_PATH + 32];
|
|
| // instantiate my C# COM object
|
| ICSharpCOM *cpi = NULL;
|
|
| // Initialize COM and create an instance of the
| // InterfaceImplementation class:
|
| CoInitialize(NULL);
| HRESULT hr = CoCreateInstance(
| CLSID_CSharpCOMWin,
| NULL, CLSCTX_INPROC_SERVER,
| IID_ICSharpCOM, reinterpret_cast<void**>(&cpi));
|
|
| // This error occurs when the handler is executed
|
| if (FAILED(hr))
| {
| MessageBox (NULL, "FAILED(hr)" , "err", 0);
| }
| else
| {
|
| // This is what I want to happen:
| // (m_szFile is gotten from DragQueryFile() in the Initialize() method)
| // of the handler)
|
| cpi->ShowDialog(m_szFile);
|
|
| cpi->Release();
| cpi = NULL;
| }
|
| // Be a good citizen and clean up COM:
| CoUninitialize();
|
| return S_OK;
| }
| break;
|
| default:
| return E_INVALIDARG;
| break;
| }
|
|
| }
|
|
| The above code is essentially the same as what I did in my initial test
| (which worked), so I don't know what might be the problem. It compiles
| without problems, registers fine, everything. Any help would be
appreciated.
|
| Thanks,
|
| JA