Welcome to shell: revealed Sign in | Join | Help
in Search

Drag & drop works in XP, not in Vista - help?

Last post 05-23-2008, 12:03 AM by pauljlucas. 0 replies.
Sort Posts: Previous Next
  •  05-23-2008, 12:03 AM 7941

    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

View as RSS news feed in XML
Powered by Community Server, by Telligent Systems © 2006 Microsoft Corporation. All rights reserved. Terms of Use | Trademarks | Privacy Statement.