//+------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1996. // // File: ido.cpp // // Contents: Special data object implementation to optimize drag/drop // // Classes: SSharedFormats // CDragDataObject // CDragEnum // // Functions: CreateDragDataObject // CreateDragDataObject // // History: dd-mmm-yy Author Comment // 30-Sep-94 ricksa Created // // Notes: // //-------------------------------------------------------------------------- #include #include #include // Format for name of shared memory OLECHAR szSharedMemoryTemplate[] = OLESTR("DragDrop%lx"); // Maximum size of string for name of shared memory. This is the size of the // template plus the maximum number of hex digits in a long. const int DRAG_SM_NAME_MAX = sizeof(szSharedMemoryTemplate) + sizeof(DWORD) * 2; // Useful function for getting an enumerator HRESULT wGetEnumFormatEtc( IDataObject *pDataObj, DWORD dwDirection, IEnumFORMATETC **ppIEnum); //+------------------------------------------------------------------------- // // Struct: SSharedFormats // // Purpose: Is used for accessing formats in shared memory // // History: dd-mmm-yy Author Comment // 26-Sep-94 ricksa Created // //-------------------------------------------------------------------------- struct SSharedFormats { DWORD _cFormats; FORMATETC _FormatEtc[1]; }; //+------------------------------------------------------------------------- // // Class: CDragDataObject // // Purpose: Server side data object for drag that creates enumerator // for shared formats. // // Interface: QueryInterface // AddRef // Release // GetData // GetDataHere // QueryGetData // GetCanonicalFormatEtc // SetData // EnumFormatEtc // DAdvise // DUnadvise // EnumDAdvise // // History: dd-mmm-yy Author Comment // 30-Sep-94 Ricksa Created // // Notes: This class only exists for return the enumerator. For // all other operations it will simply pass the operation on // to the real data object. // //-------------------------------------------------------------------------- class CDragDataObject : public IDataObject, public CPrivAlloc { public: CDragDataObject( void *pvMarshaledDataObject, DWORD dwSmId); ~CDragDataObject(void); // // IUnknown // STDMETHODIMP QueryInterface( REFIID riid, void **ppvObject); STDMETHODIMP_(ULONG) AddRef(void); STDMETHODIMP_(ULONG) Release(void); // // IDataObject // STDMETHODIMP GetData( FORMATETC *pformatetcIn, STGMEDIUM *pmedium); STDMETHODIMP GetDataHere( FORMATETC *pformatetc, STGMEDIUM *pmedium); STDMETHODIMP QueryGetData( FORMATETC *pformatetc); STDMETHODIMP GetCanonicalFormatEtc( FORMATETC *pformatectIn, FORMATETC *pformatetcOut); STDMETHODIMP SetData( FORMATETC *pformatetc, STGMEDIUM *pmedium, BOOL fRelease); STDMETHODIMP EnumFormatEtc( DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc); STDMETHODIMP DAdvise( FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection); STDMETHODIMP DUnadvise(DWORD dwConnection); STDMETHODIMP EnumDAdvise(IEnumSTATDATA **ppenumAdvise); private: IDataObject * GetRealDataObjPtr(void); ULONG _cRefs; void * _pvMarshaledDataObject; IDataObject * _pIDataObject; DWORD _dwSmId; }; //+------------------------------------------------------------------------- // // Class: CDragEnum // // Purpose: Enumerator created above to enumerate shared formats. // // Interface: QueryInterface // AddRef // Release // Next // Skip // Reset // Clone // // History: dd-mmm-yy Author Comment // 30-Sep-94 Ricksa Created // // Notes: This class only enumerates things from shared memory // when the drag/drop operation was started. // //-------------------------------------------------------------------------- class CDragEnum : public IEnumFORMATETC, public CPrivAlloc { public: // // IUnknown // STDMETHODIMP QueryInterface( REFIID riid, void **ppvObject); STDMETHODIMP_(ULONG) AddRef(void); STDMETHODIMP_(ULONG) Release(void); // // IEnumFORMATETC // STDMETHODIMP Next( ULONG celt, FORMATETC *rgelt, ULONG *pceltFetched); STDMETHODIMP Skip(ULONG celt); STDMETHODIMP Reset(void); STDMETHODIMP Clone(IEnumFORMATETC **ppenum); private: friend CDragDataObject; // Used when unmarshaling CDragEnum(DWORD dwSharedMemoryId, HRESULT& rhr); // Used by Clone operation CDragEnum( HANDLE hSharedMemory, DWORD _cOffset, HRESULT& rhr); ~CDragEnum(void); HRESULT MapSharedReadMemory(void); DWORD _cRefs; DWORD _cOffset; SSharedFormats * _pSharedFormats; DWORD _dwSharedMemoryId; HANDLE _hSharedMemory; }; //+------------------------------------------------------------------------- // // Member: CDragDataObject::CDragDataObject // // Synopsis: Create server side object for drag // // History: dd-mmm-yy Author Comment // 30-Sep-94 Ricksa Created // //-------------------------------------------------------------------------- CDragDataObject::CDragDataObject(void *pvMarshaledDataObject, DWORD dwSmId) : _cRefs(1), _pvMarshaledDataObject(pvMarshaledDataObject), _dwSmId(dwSmId), _pIDataObject(NULL) { // Header does all the work } //+------------------------------------------------------------------------- // // Member: CDragDataObject::~CDragDataObject // // Synopsis: Free any resources connected with this object // // History: dd-mmm-yy Author Comment // 30-Sep-94 Ricksa Created // // Note: // //-------------------------------------------------------------------------- CDragDataObject::~CDragDataObject(void) { // Release held pointer since we no longer need it. if (_pIDataObject) { _pIDataObject->Release(); } // this memory was allocated in RemPrivDragDrop, getif.cxx if( _pvMarshaledDataObject ) { PrivMemFree(_pvMarshaledDataObject); } } //+------------------------------------------------------------------------- // // Member: CDragDataObject::GetRealDataObjPtr // // Synopsis: Get the pointer to the real data object from the client // // Returns: NULL - could not unmarshal drag source's data object // ~NULL - pointer to drag source's data object // // History: dd-mmm-yy Author Comment // 30-Sep-94 Ricksa Created // //-------------------------------------------------------------------------- IDataObject *CDragDataObject::GetRealDataObjPtr(void) { if (_pIDataObject == NULL) { _pIDataObject = UnmarshalDragDataObject(_pvMarshaledDataObject); LEERROR(!_pIDataObject, "Unable to unmarshal dnd data object"); } return _pIDataObject; } //+------------------------------------------------------------------------- // // Member: CDragDataObject::QueryInterface // // Synopsis: Get new interface // // Arguments: [riid] - interface id of requested interface // [ppvObject] - where to put the new interface pointer // // Returns: NOERROR - interface was instantiated // E_FAIL - could not unmarshal source's data object // other - some error occurred. // // History: dd-mmm-yy Author Comment // 30-Sep-94 Ricksa Created // // Note: // //-------------------------------------------------------------------------- STDMETHODIMP CDragDataObject::QueryInterface( REFIID riid, void **ppvObject) { if(IsEqualIID(riid, IID_IDataObject)) { *ppvObject = this; AddRef(); return NOERROR; } return (GetRealDataObjPtr() != NULL) ? _pIDataObject->QueryInterface(riid, ppvObject) : E_FAIL; } //+------------------------------------------------------------------------- // // Member: CDragDataObject::AddRef // // Synopsis: Create server side object for drag // // Returns: Current reference count // // History: dd-mmm-yy Author Comment // 30-Sep-94 Ricksa Created // //-------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CDragDataObject::AddRef(void) { DDDebugOut((DEB_ITRACE, "ADDREF == %d\n", _cRefs + 1)); return ++_cRefs; } //+------------------------------------------------------------------------- // // Member: CDragDataObject::Release // // Synopsis: Decrement reference count to the object // // Returns: Current reference count to the object // // History: dd-mmm-yy Author Comment // 30-Sep-94 Ricksa Created // //-------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CDragDataObject::Release(void) { ULONG cRefs = --_cRefs; DDDebugOut((DEB_ITRACE, "RELEASE == %d\n", cRefs)); if (cRefs == 0) { delete this; } return cRefs; } //+------------------------------------------------------------------------- // // Member: CDragDataObject::GetData // // Synopsis: Create server side object for drag // // Arguments: [pformatetcIn] - format for requested data // [pmedium] - storage medium // // Returns: NOERROR - operation was successful // Other - operation failed // // History: dd-mmm-yy Author Comment // 30-Sep-94 Ricksa Created // // Note: This just forwards the operation to the source data object // if possible. // //-------------------------------------------------------------------------- STDMETHODIMP CDragDataObject::GetData( FORMATETC *pformatetcIn, STGMEDIUM *pmedium) { return (GetRealDataObjPtr() != NULL) ? _pIDataObject->GetData(pformatetcIn, pmedium) : E_FAIL; } //+------------------------------------------------------------------------- // // Member: CDragDataObject::GetDataHere // // Synopsis: Create server side object for drag // // Arguments: [pformatetc] - format for requested data // [pmedium] - storage medium // // Returns: NOERROR - operation was successful // Other - operation failed // // History: dd-mmm-yy Author Comment // 30-Sep-94 Ricksa Created // // Note: This just forwards the operation to the source data object // if possible. // //-------------------------------------------------------------------------- STDMETHODIMP CDragDataObject::GetDataHere( FORMATETC *pformatetc, STGMEDIUM *pmedium) { return (GetRealDataObjPtr() != NULL) ? _pIDataObject->GetDataHere(pformatetc, pmedium) : E_FAIL; } //+------------------------------------------------------------------------- // // Member: CDragDataObject::QueryGetData // // Synopsis: Create server side object for drag // // Arguments: [pformatetc] - format to verify // // Returns: NOERROR - operation was successful // Other - operation failed // // History: dd-mmm-yy Author Comment // 30-Sep-94 Ricksa Created // // Note: This just forwards the operation to the source data object // if possible. // //-------------------------------------------------------------------------- STDMETHODIMP CDragDataObject::QueryGetData(FORMATETC *pformatetc) { return (GetRealDataObjPtr() != NULL) ? _pIDataObject->QueryGetData(pformatetc) : E_FAIL; } //+------------------------------------------------------------------------- // // Member: CDragDataObject::GetCanonicalFormatEtc // // Synopsis: Create server side object for drag // // Arguments: [pformatetcIn] - input format // [pformatetcOut] - output format // // Returns: NOERROR - operation was successful // Other - operation failed // // History: dd-mmm-yy Author Comment // 30-Sep-94 Ricksa Created // // Note: This just forwards the operation to the source data object // if possible. // //-------------------------------------------------------------------------- STDMETHODIMP CDragDataObject::GetCanonicalFormatEtc( FORMATETC *pformatetcIn, FORMATETC *pformatetcOut) { return (GetRealDataObjPtr() != NULL) ? _pIDataObject->GetCanonicalFormatEtc(pformatetcIn, pformatetcOut) : E_FAIL; } //+------------------------------------------------------------------------- // // Member: CDragDataObject::SetData // // Synopsis: Create server side object for drag // // Arguments: [pformatetc] - format for set // [pmedium] - medium to use // [fRelease] - who releases // // Returns: NOERROR - operation was successful // Other - operation failed // // History: dd-mmm-yy Author Comment // 30-Sep-94 Ricksa Created // // Note: This just forwards the operation to the source data object // if possible. // //-------------------------------------------------------------------------- STDMETHODIMP CDragDataObject::SetData( FORMATETC *pformatetc, STGMEDIUM *pmedium, BOOL fRelease) { return (GetRealDataObjPtr() != NULL) ? _pIDataObject->SetData(pformatetc, pmedium, fRelease) : E_FAIL; } //+------------------------------------------------------------------------- // // Member: CDragDataObject::EnumFormatEtc // // Synopsis: Create server side object for drag // // Arguments: [dwDirection] - direction of formats either set or get // [ppenumFormatEtc] - where to put enumerator // // Returns: NOERROR - operation succeeded. // // Algorithm: If format enumerator requested is for a data get, the // create our private enumerator object otherwise pass // the request to the real data object. // // History: dd-mmm-yy Author Comment // 30-Sep-94 Ricksa Created // // Note: For the data set direction, we just use the data object of // the drop source. // //-------------------------------------------------------------------------- STDMETHODIMP CDragDataObject::EnumFormatEtc( DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc) { HRESULT hr; // Create our enumerator if (dwDirection == DATADIR_GET) { // In the data get case we use our overridden enumerator. // This s/b the typical case with Drag and Drop. hr = E_OUTOFMEMORY; CDragEnum *pDragEnum = new CDragEnum(_dwSmId, hr); if (hr == NOERROR) { *ppenumFormatEtc = pDragEnum; } else { delete pDragEnum; } } else { // Call through to the real data object because this is the // set case. In general, this won't happen during Drag and Drop. hr = (GetRealDataObjPtr() != NULL) ? _pIDataObject->EnumFormatEtc(dwDirection, ppenumFormatEtc) : E_FAIL; } return hr; } //+------------------------------------------------------------------------- // // Member: CDragDataObject::DAdvise // // Synopsis: Create server side object for drag // // Arguments: [pformatetc] - format to be advised on // [advf] - type of advise // [pAdvSink] - advise to notify // [pdwConnection] - connection id for advise // // Returns: NOERROR - operation was successful // Other - operation failed // // History: dd-mmm-yy Author Comment // 30-Sep-94 Ricksa Created // // Note: This just forwards the operation to the source data object // if possible. // //-------------------------------------------------------------------------- STDMETHODIMP CDragDataObject::DAdvise( FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection) { return (GetRealDataObjPtr() != NULL) ? _pIDataObject->DAdvise(pformatetc, advf, pAdvSink, pdwConnection) : E_FAIL; } //+------------------------------------------------------------------------- // // Member: CDragDataObject::DUnadvise // // Synopsis: Create server side object for drag // // Arguments: [dwConnection] - connection id for advise // // Returns: NOERROR - operation was successful // Other - operation failed // // History: dd-mmm-yy Author Comment // 30-Sep-94 Ricksa Created // // Note: This just forwards the operation to the source data object // if possible. // //-------------------------------------------------------------------------- STDMETHODIMP CDragDataObject::DUnadvise(DWORD dwConnection) { return (GetRealDataObjPtr() != NULL) ? _pIDataObject->DUnadvise(dwConnection) : E_FAIL; } //+------------------------------------------------------------------------- // // Member: CDragDataObject::EnumDAdvise // // Synopsis: Create server side object for drag // // Arguments: [ppenumAdvise] - where to put the enumerator // // Returns: NOERROR - operation was successful // Other - operation failed // // History: dd-mmm-yy Author Comment // 30-Sep-94 Ricksa Created // // Note: This just forwards the operation to the source data object // if possible. // //-------------------------------------------------------------------------- STDMETHODIMP CDragDataObject::EnumDAdvise(IEnumSTATDATA **ppenumAdvise) { return (GetRealDataObjPtr() != NULL) ? _pIDataObject->EnumDAdvise(ppenumAdvise) : E_FAIL; } //+------------------------------------------------------------------------- // // Member: CDragEnum::CDragEnum // // Synopsis: Create enumerator object from server data object // // Arguments: [dwSharedMemoryId] - shared memory id // [rhr] - error result // // Algorithm: Initalize the object and then open the shared memory // segment and then pass the rest of the work on to // MapSharedMemory to get the memory mapped in. // // History: dd-mmm-yy Author Comment // 30-Sep-94 Ricksa Created // //-------------------------------------------------------------------------- CDragEnum::CDragEnum(DWORD dwSharedMemoryId, HRESULT& rhr) : _cRefs(1), _cOffset(0), _dwSharedMemoryId(dwSharedMemoryId), _hSharedMemory(NULL), _pSharedFormats(NULL) { // Open the shared memory OLECHAR szSharedMemoryName[DRAG_SM_NAME_MAX]; wsprintf(szSharedMemoryName, szSharedMemoryTemplate, dwSharedMemoryId); // Create the shared memory object _hSharedMemory = OpenFileMapping(FILE_MAP_READ, FALSE, szSharedMemoryName); rhr = MapSharedReadMemory(); } //+------------------------------------------------------------------------- // // Member: CDragEnum::CDragEnum // // Synopsis: Create enumerator for Clone operation // // Arguments: [hSharedMemory] - handle to shared memory for formats // [cOffset] - current offset in the enumeration // [rhr] - error result if any // // Algorithm: Initialize the object and then dupicate the input handle. // Then pass the rest of the work on to MapSharedReadMemory // to get the memory mapped in. // // History: dd-mmm-yy Author Comment // 30-Sep-94 Ricksa Created // // Note: // //-------------------------------------------------------------------------- CDragEnum::CDragEnum(HANDLE hSharedMemory, DWORD cOffset, HRESULT& rhr) : _cRefs(1), _cOffset(cOffset), _dwSharedMemoryId(0), _hSharedMemory(NULL), _pSharedFormats(NULL) { // Duplicate the handle DuplicateHandle(GetCurrentProcess(), hSharedMemory, GetCurrentProcess(), &_hSharedMemory, 0, FALSE, DUPLICATE_SAME_ACCESS); rhr = MapSharedReadMemory(); } //+------------------------------------------------------------------------- // // Member: CDragEnum::~CDragEnum // // Synopsis: Free reference to memory for formats // // History: dd-mmm-yy Author Comment // 30-Sep-94 Ricksa Created // // Note: // //-------------------------------------------------------------------------- CDragEnum::~CDragEnum(void) { // Free mapped memory if it got mapped. if (_pSharedFormats != NULL) { UnmapViewOfFile(_pSharedFormats); } // Close file mapping if it got created. if (_hSharedMemory != NULL) { CloseHandle(_hSharedMemory); } } //+------------------------------------------------------------------------- // // Member: CDragEnum::MapSharedReadMemory // // Synopsis: Map in the shared memory containing the formats // // Returns: NOERROR - could map in memory or no formats available // // Algorithm: If we have a handle to the shared memory, then map the // memory in. // // History: dd-mmm-yy Author Comment // 30-Sep-94 Ricksa Created // // Note: // //-------------------------------------------------------------------------- HRESULT CDragEnum::MapSharedReadMemory(void) { if (_hSharedMemory != NULL) { // Map in the shared memory _pSharedFormats = (SSharedFormats *) MapViewOfFile(_hSharedMemory, FILE_MAP_READ, 0, 0, 0); } // It's OK to have a null shared memory handle (indicates that no // formats were available. Not that if we're out of memory, returning // NOERROR here is going to mask that condition. However, we'll // fail soon enough anyway. return NOERROR; } //+------------------------------------------------------------------------- // // Member: CDragEnum::QueryInterface // // Synopsis: Return requested interface // // Arguments: [riid] - interface id for output interface // [ppvObject] - where to put output interface pointer // // Returns: NOERROR - could return the interface requested // E_NOINTERFACE - could not instantiate requested interface. // // History: dd-mmm-yy Author Comment // 30-Sep-94 Ricksa Created // // Note: // //-------------------------------------------------------------------------- STDMETHODIMP CDragEnum::QueryInterface( REFIID riid, void **ppvObject) { // Assume error to avoid the implicit goto of an else clause. HRESULT hr = E_NOINTERFACE; // Our enumerator only knows about two interfaces. if(IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IEnumFORMATETC)) { *ppvObject = this; AddRef(); hr = NOERROR; } return hr; } //+------------------------------------------------------------------------- // // Member: CDragEnum::AddRef // // Synopsis: Add a reference to the interface // // Returns: Current count of references // // History: dd-mmm-yy Author Comment // 30-Sep-94 Ricksa Created // //-------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CDragEnum::AddRef(void) { return ++_cRefs; } //+------------------------------------------------------------------------- // // Member: CDragEnum::Release // // Synopsis: Release a reference to the enumerator // // Returns: The current reference count // // History: dd-mmm-yy Author Comment // 30-Sep-94 Ricksa Created // //-------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CDragEnum::Release(void) { // Remember to copy reference count out because memory might go // away on the release. ULONG cRefs = --_cRefs; if (cRefs == 0) { delete this; } return cRefs; } //+------------------------------------------------------------------------- // // Member: CDragEnum::Next // // Synopsis: Return an array of formats requested // // Arguments: [celt] - number requested to return // [rgelt] - array to hold returned items // [pceltFetched] - actual number returned. // // Returns: NOERROR - number requested returned // S_FALSE - less than requested returned // E_OUTOFMEMORY - could not allocate memory to hold data // // Algorithm: Validate the input parameters. Then calculate the number // to return by taking the minimum of the items left to // enumerate and the number of items requested. Then copy // all the formatetc's from shared memory to the output // buffer. Then for each formatetc that contains a pointer // to a DVDEVICETARGET, allocate a new target buffer and // then copy the DVDEVICETARGET from shared memory. There // is a trick here where in the formatetc in shared memory // the ptd field is really an offset from the beginning of // shared memory rather than an actual pointer. This is so // we don't have to depend on the base of the shared memory. // // History: dd-mmm-yy Author Comment // 30-Sep-94 Ricksa Created // // Note: // //-------------------------------------------------------------------------- STDMETHODIMP CDragEnum::Next( ULONG celt, FORMATETC *rgelt, ULONG *pceltFetched) { if (celt == 0) { LEDebugOut((DEB_ERROR, "CDragEnum::Next requested entries returned is invalid\n")); return E_INVALIDARG; } if (!IsValidPtrOut(rgelt, sizeof(FORMATETC) * celt)) { LEDebugOut((DEB_ERROR, "CDragEnum::Next array to return entries invalid\n")); return E_INVALIDARG; } if (pceltFetched) { if (!IsValidPtrOut(pceltFetched, sizeof(*pceltFetched))) { LEDebugOut((DEB_ERROR, "CDragEnum::Next count to return invalid\n")); return E_INVALIDARG; } } else if (celt != 1) { LEDebugOut((DEB_ERROR, "CDragEnum::count requested != 1 & count fetched is NULL\n")); return E_INVALIDARG; } // handle the case where we have no data if( _pSharedFormats == NULL ) { if( pceltFetched ) { *pceltFetched = 0; } return S_FALSE; } // Calculate the maximum number that we can return ULONG cToReturn = (_cOffset < _pSharedFormats->_cFormats) ? _pSharedFormats->_cFormats - _cOffset : 0; // Are we going to return any? if (cToReturn != 0) { // If the number requested is less that the maximum number // we can return, the we will return all requested/ if (celt < cToReturn) { cToReturn = celt; } // Copy the FormatEtcs memcpy(&rgelt[0], &_pSharedFormats->_FormatEtc[_cOffset], sizeof(FORMATETC) * cToReturn); // Allocate and copy the DVTARGETDEVICE - a side effect of this // loop is that our offset pointer gets updated to its value at // the completion of the routine. for (DWORD i = 0; i < cToReturn; i++, _cOffset++) { if (_pSharedFormats->_FormatEtc[_cOffset].ptd != NULL) { // Create a pointer to the device target - Remember when // we created the shared memory block we overroad the ptd // field of the FORMATETC so that it is now the offset // from the beginning of the shared memory. We reverse // that here so we can copy the data for the consumer. DVTARGETDEVICE *pdvtarget = (DVTARGETDEVICE *) ((BYTE *) _pSharedFormats + (DWORD) _pSharedFormats->_FormatEtc[_cOffset].ptd); // Allocate a new DVTARGETDEVICE DVTARGETDEVICE *pdvtargetNew = (DVTARGETDEVICE *) CoTaskMemAlloc(pdvtarget->tdSize); // Did the memory allocation succeed? if (pdvtargetNew == NULL) { // NO! - so clean up. First we free any device targets // that we might have allocated. for (DWORD j = 0; j < i; j++) { if (rgelt[j].ptd != NULL) { CoTaskMemFree(rgelt[j].ptd); } } // Then we restore the offset to its initial state _cOffset -= i; return E_OUTOFMEMORY; } // Copy the old targetDevice to the new one memcpy(pdvtargetNew, pdvtarget, pdvtarget->tdSize); // Update output FORMATETC pointer rgelt[i].ptd = pdvtargetNew; } } } if (pceltFetched) { *pceltFetched = cToReturn; } return (cToReturn == celt) ? NOERROR : S_FALSE; } //+------------------------------------------------------------------------- // // Member: CDragEnum::Skip // // Synopsis: Skip the input number of entries in the list // // Arguments: [celt] - count of entries to skip // // Returns: NOERROR - number could be skipped // S_FALSE - skip greater than the end of the list // // Algorithm: Bump offset by count input. If this is greater than or // equal to the number of formats, return S_FALSE otherwise // return NOERROR. // // History: dd-mmm-yy Author Comment // 30-Sep-94 Ricksa Created // //-------------------------------------------------------------------------- STDMETHODIMP CDragEnum::Skip(ULONG celt) { HRESULT hr = NOERROR; _cOffset += celt; if( _pSharedFormats == NULL ) { _cOffset = 0; hr = S_FALSE; } else if (_cOffset >= _pSharedFormats->_cFormats) { _cOffset = _pSharedFormats->_cFormats; hr = S_FALSE; } return hr; } //+------------------------------------------------------------------------- // // Member: CDragEnum::Reset // // Synopsis: Reset enumeration index to the beginning // // Returns: NOERROR // // Algorithm: Just set our offset back to 0. // // History: dd-mmm-yy Author Comment // 30-Sep-94 Ricksa Created // //-------------------------------------------------------------------------- STDMETHODIMP CDragEnum::Reset(void) { _cOffset = 0; return NOERROR; } //+------------------------------------------------------------------------- // // Member: CDragEnum::Clone // // Synopsis: Create a duplicate copy of this enumeration. // // Arguments: [ppenum] - where to return the enumerator // // Returns: S_OK - could create the enumerator copy // E_OUTOFMEMORY - could not create the copy // // Algorithm: Call constructor for enumerator that dups the handle to the // shared memory. // // History: dd-mmm-yy Author Comment // 30-Sep-94 Ricksa Created // //-------------------------------------------------------------------------- STDMETHODIMP CDragEnum::Clone(IEnumFORMATETC **ppenum) { HRESULT hr = E_OUTOFMEMORY; CDragEnum *pDragEnum = new CDragEnum(_hSharedMemory, _cOffset, hr); return hr; } //+------------------------------------------------------------------------- // // Member: CreateDragDataObject // // Synopsis: Create the server side data object for format enumeration // // Arguments: [pvMarshaledDataObject] - marshaled real data object buffer // [dwSmId] - id for the shared memory // [ppIDataObject] - output data object. // // Returns: NOERROR - could create the object // E_OUTOFMEMORY - could not create the object // // // History: dd-mmm-yy Author Comment // 30-Sep-94 Ricksa Created // // Note: // //-------------------------------------------------------------------------- HRESULT CreateDragDataObject( void *pvMarshaledDataObject, DWORD dwSmId, IDataObject **ppIDataObject) { CDragDataObject *pDragDataObject = new CDragDataObject(pvMarshaledDataObject, dwSmId); if (pDragDataObject != NULL) { *ppIDataObject = pDragDataObject; } // The only thing that can fail here is the memory allocation of // CDragDataObject thus there are only two error returns. return (pDragDataObject != NULL) ? NOERROR : E_OUTOFMEMORY; } //+------------------------------------------------------------------------- // // Member: CreateDragDataObject // // Synopsis: Put the data formats for the data object in shared memory. // // Arguments: [pIDataObject] - data object to use for formats. // // Returns: NULL - could not create enumerator // ~NULL - handle to shared memory // // Algorithm: First calculate the size of the required memory by enumerating // the formats. Then allocate the memory and map it into the // process. Then enumerate the formats again placing them in // the shared memory. Finally, map the memory out of the // process and return the handle the file mapping to the // caller. // // History: dd-mmm-yy Author Comment // 30-Sep-94 Ricksa Created // //-------------------------------------------------------------------------- HANDLE CreateSharedDragFormats(IDataObject *pIDataObject) { // Handle to the shared memory for formats HANDLE hSharedMemory = NULL; // Pointer to share memory SSharedFormats *pSharedFormats = NULL; // Size required for the shared memory DWORD dwSize = 0; // Count of FORMATETCs contained in the enumerator DWORD cFormatEtc = 0; // Buffer for name of shared memory for enumerator OLECHAR szSharedMemoryName[DRAG_SM_NAME_MAX]; // Work pointer to shared memory for storing FORMATETCs from the enumerator. FORMATETC *pFormatEtc; // Work ptr to shared memory for storing DVTARGETDEVICEs from enumerator. BYTE *pbDvTarget = NULL; // // Calculate the size of the formats // // Get the format enumerator IEnumFORMATETC *penum = NULL; HRESULT hr = wGetEnumFormatEtc(pIDataObject, DATADIR_GET, &penum); FORMATETC FormatEtc; if( hr != NOERROR ) { // not all apps support enumerators (yahoo). Also, we may // have run out of memory or encountered some other error. DDDebugOut((DEB_WARN, "WARNING: Failed to get formatetc enumerator" ", error code (%lx)", hr)); goto exitRtn; } // Enumerate the data one at a time because this is a local operation // and it make the code simpler. while ((hr = penum->Next(1, &FormatEtc, NULL)) == S_OK) { // Bump the entry count cFormatEtc++; // Bump the size by the size of another FORMATETC. dwSize += sizeof(FORMATETC); // Is there a device target associated with the FORMATETC? if (FormatEtc.ptd != NULL) { // Bump the size required by the size of the target device dwSize += FormatEtc.ptd->tdSize; // Free the target device CoTaskMemFree(FormatEtc.ptd); } } // HRESULT s/b S_FALSE at the end of the enumeration. if (hr != S_FALSE) { goto errRtn; } // the enumerator may have been empty if( dwSize == 0 ) { DDDebugOut((DEB_WARN, "WARNING: Empty formatetc enumerator")); goto exitRtn; } dwSize += sizeof(SSharedFormats); // add space for _cFormats and one exter FORMATETC for FALSE in enumerator. // // Create shared memory for the type enumeration // // Build name of shared memory - make it unique by using the thread id. wsprintf(szSharedMemoryName, szSharedMemoryTemplate, GetCurrentThreadId()); // Create the shared memory object hSharedMemory = CreateFileMapping((HANDLE) 0xFFFFFFFF, NULL, PAGE_READWRITE, 0, dwSize, szSharedMemoryName); // Did the file mapping get created? if (hSharedMemory == NULL) { goto errRtn; } // Map in the memory pSharedFormats = (SSharedFormats *) MapViewOfFile( hSharedMemory, FILE_MAP_WRITE, 0, // High-order 32 bits of file offset 0, // Low-order 32 bits of file offset 0); // Number of bytes to map; 0 means all. // Could we map the memory? if (pSharedFormats == NULL) { goto errRtn; } // We can initialize the size of the array now. pSharedFormats->_cFormats = cFormatEtc; // // Copy the formats into the shared memory // // Get back to the start of the enumeration penum->Reset(); // This is the pointer to where we will copy the data from the // enumeration. pFormatEtc = &pSharedFormats->_FormatEtc[0]; // put DvTarget past last valid FormatEtc + 1 to handle S_FALSE enumerator case. pbDvTarget = (BYTE *) (&pSharedFormats->_FormatEtc[cFormatEtc + 1]); // Loop loading the formats into the shared memory. while (penum->Next(1, pFormatEtc, NULL) != S_FALSE) { // Is there a DVTARGETDEVICE? if (pFormatEtc->ptd != NULL) { // Copy the device target data memcpy(pbDvTarget,pFormatEtc->ptd,(pFormatEtc->ptd)->tdSize); // Free the target device data CoTaskMemFree(pFormatEtc->ptd); // NOTE: For this shared memory structure, we override the // FORMATETC field so that it is that offset to the DVTARGETDEVICE // from the beginning of the shared memory rather than a direct // pointer to the structure. This is because we can't guarantee // the base of shared memory in different processes. pFormatEtc->ptd = (DVTARGETDEVICE *) (pbDvTarget - (BYTE *) pSharedFormats); // Bump pointer of where to copy target to next available // byte for copy. pbDvTarget += ((DVTARGETDEVICE *) pbDvTarget)->tdSize; Assert(dwSize >= (DWORD) (pbDvTarget - (BYTE *) pSharedFormats)); } // Bug#18669 - if dwAspect was set to NULL the 16 bit dlls would // set it to content. if ( (NULL == pFormatEtc->dwAspect) && IsWOWThread() ) { pFormatEtc->dwAspect = DVASPECT_CONTENT; pFormatEtc->lindex = -1; // CorelDraw also puts up a lindex of 0 } // Bump the pointer in the table of FORMATETCs to the next slot pFormatEtc++; } Assert( dwSize >= (DWORD) ( (BYTE *) pFormatEtc - (BYTE *) pSharedFormats)); Assert( dwSize >= (DWORD) ( (BYTE *) pbDvTarget - (BYTE *) pSharedFormats)); // Successful enumeration always ends with S_FALSE. if (hr == S_FALSE) { goto exitRtn; } errRtn: if (hSharedMemory != NULL) { CloseHandle(hSharedMemory); hSharedMemory = NULL; } exitRtn: if( penum ) { // HACK ALERT: Do not release the enumerator if the calling application // was Interleaf 6.0, otherwise they will fault in the release call. if (!IsTaskName(L"ILEAF6.EXE")) { penum->Release(); } } if (pSharedFormats != NULL) { // Only remote clients will use this memory so we unmap it // out of our address space. UnmapViewOfFile(pSharedFormats); } return hSharedMemory; }