Ureader.com  
Microsoft software help and Community
   home   |   control panel login   |   archive   |  
 
platform
active.directory
adsi
adsi.iis-admin
base
com_ole
complus_mts
component_svcs
database
directx
gdi
graphics_mm
internet.client
internet.server
internet.server.isapi-dev
localization
mapi
messaging
msi
mslayerforunicode
multimedia
networking
networking.ipv6
sdk_install
security
shell
telephony.tapi_2
telephony.tapi_3
telephony.tsp
telephony.wte
tools
ui
ui_shell
win_base_svcs
win16
  
 
date: Thu, 22 May 2008 20:58:38 -0700,    group: microsoft.public.platformsdk.shell        back       


Drag & drop works in XP, not in Vista - help?   
I have code that implements drag & drop for a ShowPicturesOnArrival event.
The code works fine under Windows XP but fails under Vista with an:

	Invalid FORMATETC structure

error.  For completeness, the relevant Registry keys I've added are below.
Items preceeded by a "v" are values for the above key, not subkeys.

	HKEY_CLASSES_ROOT
	  MyApp
	    shell
	      open
	        DropTarget
	        v CLSID [REG_SZ] = {My-GUID}

	HKEY_LOCAL_MACHINE
	  SOFTWARE
	    Classes
	      CLSID
	        {My-GUID}
	        v (default) [REG_SZ] MyApp
	          InprocServer32
	          v (default) [REG_SZ] = C:\path\to\My.dll
	          v ThreadingModel [REG_SZ] = Apartment
	    Microsoft
	      Windows
	        CurrentVersion
	          Explorer
	            AutoplayHandlers
	              EventHandlers
	                ShowPicturesOnArrival
	                v MyApp [REG_SZ]
	              Handlers
	                MyApp
	                v Action [REG_SZ] = "Copy pictures ..."
	                v DefaultIcon [REG_SZ] = C:\path\to\MyApp.exe,0
	                v InvokeProgID [REG_SZ] = MyApp
	                v InvokeVerb [REG_SZ] = open
	                v Provider [REG_SZ] = MyApp's name

My code follows.  (Yes, I know it's a lot to look through, but any help much
appreciated.  The failure occurs where the comment containing "fails" below
is.)  First, I have a utility reference-counting class:

	class LC_DLLRefCount {
	public:
	    static ULONG get() {
	        return m_refCount;
	    }
	protected:
	    LC_DLLRefCount()  { ++m_refCount; }
	    ~LC_DLLRefCount() { --m_refCount; }
	private:
	    static ULONG volatile m_refCount;
	};
	
	ULONG volatile LC_DLLRefCount::m_refCount;

Next, my IClassFactory implementation:

	class LC_ClassFactory : public IClassFactory, public LC_DLLRefCount {
	public:
	    LC_ClassFactory() : m_refCount( 0 ) { }
	
	    ULONG STDMETHODCALLTYPE AddRef() {
	        return ++m_refCount;
	    }
	
	    ULONG STDMETHODCALLTYPE Release() {
	        ULONG const remaining = --m_refCount;
	        if ( !remaining )
	            delete this;
	        return remaining;
	    }
	
	    HRESULT STDMETHODCALLTYPE CreateInstance( IUnknown*, REFIID,
	                                              LPVOID* );
	    HRESULT STDMETHODCALLTYPE LockServer( BOOL );
	    HRESULT STDMETHODCALLTYPE QueryInterface( REFIID, LPVOID* );
	private:
	    ULONG volatile m_refCount;
	};
	
	HRESULT STDMETHODCALLTYPE LC_ClassFactory::CreateInstance
	    ( IUnknown *pUnkOuter, REFIID iid, LPVOID *ppv )
	{
	    if ( ::IsBadWritePtr( ppv, sizeof( LPVOID ) ) )
	        return E_POINTER;
	    if ( pUnkOuter )
	        return CLASS_E_NOAGGREGATION;
	    *ppv = NULL;
	    LC_AutoplayHandler *const handler = new LC_AutoplayHandler();
	    if ( !handler )
	        return E_OUTOFMEMORY;
	    HRESULT result = handler->QueryInterface( iid, ppv );
	    if ( FAILED( result ) )
	        delete handler;
	    return result;
	}
	
	HRESULT STDMETHODCALLTYPE LC_ClassFactory::LockServer( BOOL lock ) {
	    if ( lock )
	        ++m_refCount;
	    else
	        --m_refCount;
	    return S_OK;
	}
	
	HRESULT STDMETHODCALLTYPE LC_ClassFactory::QueryInterface
	    ( REFIID iid, LPVOID *ppv )
	{
	    if ( ::IsBadWritePtr( ppv, sizeof( LPVOID ) ) )
	        return E_POINTER;
	    if ( ::IsEqualIID( iid, IID_IUnknown ) )
	        *ppv = dynamic_cast<IUnknown*>( this );
	    else if ( ::IsEqualIID( iid, IID_IClassFactory ) )
	        *ppv = dynamic_cast<IClassFactory*>( this );
	    else {
	        *ppv = NULL;
	        return E_NOINTERFACE;
	    }
	    AddRef();
	    return S_OK;
	}

Next, my IDropTarget implementation:

	class LC_AutoplayHandler : public IDropTarget, public LC_DLLRefCount {
	public:
	    LC_AutoplayHandler() : m_refCount( 0 ) { }
	
	    ULONG STDMETHODCALLTYPE AddRef() {
	        return ++m_refCount;
	    }
	
	    ULONG STDMETHODCALLTYPE Release() {
	        ULONG const remaining = --m_refCount;
	        if ( !remaining )
	            delete this;
	        return remaining;
	    }
	
	    HRESULT STDMETHODCALLTYPE QueryInterface( REFIID, LPVOID* );
	
	    HRESULT STDMETHODCALLTYPE Drop( LPDATAOBJECT, DWORD, POINTL,
	                                    PDWORD );
	    HRESULT STDMETHODCALLTYPE DragEnter( LPDATAOBJECT, DWORD, POINTL,
	                                         PDWORD );
	    HRESULT STDMETHODCALLTYPE DragLeave();
	    HRESULT STDMETHODCALLTYPE DragOver( DWORD, POINTL, PDWORD );
	private:
	    ULONG volatile m_refCount;
	};
	
	HRESULT STDMETHODCALLTYPE LC_AutoplayHandler::DragEnter
	    ( LPDATAOBJECT, DWORD, POINTL, PDWORD pEffect )
	{
	    *pEffect = DROPEFFECT_COPY;
	    return S_OK;
	}
	
	HRESULT STDMETHODCALLTYPE LC_AutoplayHandler::DragLeave() {
	    return S_OK;
	}
	
	HRESULT STDMETHODCALLTYPE LC_AutoplayHandler::DragOver
	    ( DWORD, POINTL, PDWORD pEffect )
	{
	    *pEffect = DROPEFFECT_COPY;
	    return S_OK;
	}
	
	HRESULT STDMETHODCALLTYPE LC_AutoplayHandler::Drop
	    ( LPDATAOBJECT pDO, DWORD, POINTL, PDWORD )
	{
	    UINT autoplayShellIDLists = ::RegisterClipboardFormat(
	        TEXT("Autoplay Enumerated IDList Array")
	    );
	    if ( !autoplayShellIDLists )
	        return ::GetLastError();

	    FORMATETC formatEtc = {
	        autoplayShellIDLists, NULL, DVASPECT_CONTENT, -1,
	        TYMED_HGLOBAL
	    };
	    STGMEDIUM medium = { 0 };
	
	    HRESULT result = pDO->GetData( &formatEtc, &medium );
	    if ( FAILED( result ) )
	        return result;

	    // The call to GetData() above fails with:
	    //
	    //     Invalid FORMATETC structure
	    //

	    // ... elided ...

	    ::ReleaseStgMedium( &medium );
	    return result;
	}
	
	HRESULT STDMETHODCALLTYPE LC_AutoplayHandler::QueryInterface
	    ( REFIID iid, LPVOID *ppv )
	{
	    if ( ::IsBadWritePtr( ppv, sizeof( LPVOID ) ) )
	        return E_POINTER;
	    if ( ::IsEqualIID( iid, IID_IUnknown ) )
	        *ppv = dynamic_cast<IUnknown*>( this );
	    else if ( ::IsEqualIID( iid, IID_IDropTarget ) )
	        *ppv = dynamic_cast<IDropTarget*>( this );
	    else {
	        *ppv = NULL;
	        return E_NOINTERFACE;
	    }
	    AddRef();
	    return S_OK;
	}

Finally, my Dll* functions implementation:

	#define LC_DLL_EXPORT(T) extern "C" __declspec(dllexport) T __stdcall
	
	LC_DLL_EXPORT(HRESULT) DllCanUnloadNow() {
	    bool const canUnload = LC_DLLRefCount::get() == 0;
	    return canUnload ? S_OK : S_FALSE;
	}
	
	LC_DLL_EXPORT(HRESULT) DllGetClassObject( REFCLSID clsid, REFIID iid,
	                                          LPVOID *ppv ) {
	    if ( !::IsEqualCLSID( clsid, LC_AP_GUID ) )
	        return CLASS_E_CLASSNOTAVAILABLE;
	    if ( ::IsBadWritePtr( ppv, sizeof( LPVOID ) ) )
	        return E_POINTER;
	    *ppv = NULL;
	    LC_ClassFactory *const factory = new LC_ClassFactory();
	    if ( !factory )
	        return E_OUTOFMEMORY;
	    factory->AddRef();
	    HRESULT result = factory->QueryInterface( iid, ppv );
	    factory->Release();
	    return result;
	}

Are there any mistakes in the above code but it just happens to work in XP
but not Vista?  How can this be made to work in Vista?  Thanks.

- Paul
date: Thu, 22 May 2008 20:58:38 -0700   author:   Paul J. Lucas

Google
 
Web ureader.com


    COPYRIGHT 2007, YARDI TECHNOLOGY LIMITED, ALL RIGHT RESERVE  |   contact us