Does anyone know what relationship can exist between contactless COM and the drag and drop function?
In particular, we have a huge C ++ CAD / CAM application that includes several EXEs and several hundred DLLs. Many of them are COM servers (both inside and outside processes) and / or clients, and they also implement ActiveX controls.
Most ActiveX controls and the main CMDIFrameWnd single window of one of the EXE implement drag and drop functions. ActiveX controls implement both drop and drop sources, and the main window is just the target point, in particular for files from Windows Explorer.
The drag / drop implementation is fairly standard and is based on two data elements derived from COleDataSource and COleDropTarget for the drop source and drop target, respectively. The COleDropTarget element is registered by the corresponding window in the OnCreate method of the window. It also overrides the OnDragEnter , OnDragOver and OnDrop similar way. Namely, the COleDataObject parameter set by the system is requested for a specific format (in particular, CF_HDROP), and in the case of a positive response, data (for example, the path to the file) is extracted from the clipboard. The code is as follows:
static FORMATETC g_FileFmt = {CF_HDROP, 0, DVASPECT_CONTENT, 0, TYMED_HGLOBAL}; .... // Inside OnDragEnter, OnDragOver or OnDrop method STGMEDIUM stgmedium = {0,0,0}; if (pDataObject->IsDataAvailable(g_FileFmt.cfFormat)) { HRESULT hr = pDataObject->GetData(g_FileFmt.cfFormat, &stgmedium); HDROP hdrop = (HDROP)GlobalLock(stgmedium.hGlobal); if (hdrop != 0) { int FilesCount = DragQueryFile(hdrop, (UINT)-1, 0, 0); if (FilesCount != 0) { TCHAR FileName[_MAX_PATH]; DragQueryFile(hdrop, 0, FileName, _MAX_PATH); // Check file extension and store the file name for farther use. } GlobalUnlock(hdrop); } }
The implementation of the return source is also simple and looks like this:
void CDmDocListCtrl::OnBeginDrag(NMHDR* pNMHDR, LRESULT* pResult) { NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; if (pNMListView->iItem != -1 && m_pOleDataSource && prv_BeginDrag()) { DROPEFFECT DE = m_pOleDataSource->DoDragDrop( DROPEFFECT_COPY | DROPEFFECT_MOVE | DROPEFFECT_LINK, 0); } *pResult = 0; }
where the prv_BeginDrag() function collects the dragged data, packs it and puts it on the clipboard by calling the SetData method from the m_pOleDataSource object IDataObject .
All this worked perfectly until it was decided to make a free registration of the entire application. It took me three months for the application to be isolated (without registering COM components), deploying manifests, launching COM servers out of turn on request and changing the CLSID of some classes to separate instances of the same server running from different folders. Finally, it starts to work, but without the drag and drop functionality, even though my changes were not affected.
On the target side of the drag and drop, when I drag the file from Windows Explorer, pictured above, calling COleDataObject::IsDataAvailable returns false, although before my changes came back. At the same time, if I add one line of code " DragAcceptFiles(); " to the main OnCreate window, the drag and drop starts working through the standard CFrameWnd WM_DROPFILE message handler.
On the transfer source side, the dragged data is successfully packed and placed on the clipboard, but the COleDataSource::DoDragDrop fails because calling API ::DoDragDrop inside the MFC implementation returns the result REGDB_E_CLASSNOTREG "Class not registered".
This means that activating COM somehow influences the drag and drop behavior. How?
PS 1) EXE, to which I drag and drop files from Windows Explorer, has in its properties the project "Runtime level UAC = asInvoker". As far as I understand, it reports that the EXE will start at the same UAC level as Windows Explorer at startup by double-clicking the file.
2). Quite unexpectedly, despite the fact that the drag / drop stopped working with the symptoms described above, Copy / Paste continues to work well, despite the fact that both technologies have a similar implementation.
3) I believe that if you find out when :: DoDragDrop API returns the error "Class is unregistered" and what class it is looking for, it would be possible to solve the problem.
Thanks for the help, Ilia.