Проблема с перетаскиванием C #

#c# #drag-and-drop

#c# #перетаскивание

Вопрос:

У меня есть приложение на C # .NET 3.5, которое позволяет перетаскивать элементы из дерева и помещать их в папку в виде файла. Вот мой код

 String absolutePathToFile=...get absolute path
DataObject dataObject = new DataObject();
StringCollection paths = new StringCollection();
paths.Add(absolutePathToFile);
dataObject.SetFileDropList(paths);
DoDragDrop(dataObject, DragDropEffects.Copy);
  

Это работает довольно хорошо, за исключением случаев, когда взаимодействует с другим приложением C #, которое принимает файлы с помощью перетаскивания, другое приложение C # имеет следующий обработчик для перетаскивания

 if ((e.Data is DataObject) amp;amp; (e.Data as DataObject).ContainsFileDropList())
{
    e.Effect = DragDropEffects.Copy;
}
  

Блок никогда не выполняется с момента e.Данные — это __ComObject, а не DataObject. Интересно, что когда я перетаскиваю файл из папки во второе приложение, оно видит его как DataObject.

Как сделать так, чтобы объект DataObject из первого приложения C # отображался как объект DataObject во втором приложении C #?

Комментарии:

1. Попробуйте применить e. Данные в DataObject. Например: DataObject obj = e.Data as DataObject; if (obj != null) { //Your code }

2. @fardjad если (e.Data is DataObject) равно false, то при попытке безопасного приведения e.Data к DataObject оно будет равно null.

3. e.Данные — это COM-объект и In the Microsoft .NET Framework, the GetType.Type operator for a COM object will return the System.__ComObject class. In some coding scenarios, you may have to know the specific class for an object. [ support.microsoft.com/kb/320523 ] Конечно, вы должны преобразовать эти e.Data в DataObject или другой класс.

4. Позвольте мне прояснить: это второе приложение, которое получает файлы, является иностранным приложением, с которым нам необходимо интегрироваться. Я не могу его изменить. Я использовал Reflector для извлечения кода, а затем создал тестовое приложение. Тестовое приложение показывает, что приложение видит DataObject, когда я перетаскиваю файл из проводника, но когда я инициирую перетаскивание из приложения C #, как указано выше, оно видит __ComObject. Более того, локальное перетаскивание в приложении C # возвращает DataObject из e.Data, в то время как перетаскивание через границы процесса создает __ComObject . Перетаскивание из проводника и собственных приложений создает DataObject. Я пытаюсь

Ответ №1:

Я решил реализовать IDataObject с помощью .СЕТЕВОЕ взаимодействие, начиная с IDataObjec t-реализации отсюда. Затем я определил DROPFILES структуру

 [StructLayoutAttribute(LayoutKind.Sequential)]
internal struct _DROPFILES
{
    public Int32 pFiles;
    public Int32 X;
    public Int32 Y;
    public bool fNC;
    public bool fWide;
}
  

и реализуйте код, который заполняет все структуры OLE. Приведенная ниже функция возвращает IDataObject, который я использую в DoDragDrop:

DoDragDrop(GetDataObject(new String[] { file name }), DragDropEffects.Copy);

 DataObject2 GetDataObject(String[] strFiles)
{
    byte[] bData;
    _DROPFILES df = new _DROPFILES();
    int intChar, intFile, intDataLen, intPos;
    IntPtr ipGlobal = IntPtr.Zero;

    // Calculate total data length
    intDataLen = 0;
    for (intFile = 0; intFile <= strFiles.GetUpperBound(0);intFile  )
    {
        intDataLen  = strFiles[intFile].Length   1;
    }
    // Terminating double zero
    intDataLen  ;

    bData = new Byte[intDataLen];
    intPos = 0;

    // Build null terminated list of files
    for (intFile = 0; intFile <= strFiles.GetUpperBound(0); intFile  )
    {
        for (intChar = 0; intChar < strFiles[intFile].Length;intChar  )
        {
            bData[intPos  ] = (byte)strFiles[intFile][intChar];
        }
        bData[intPos  ] = 0;
    }
    // Terminating double zero
    bData[intPos  ] = 0;

    // Allocate and get pointer to global memory
    int intTotalLen = Marshal.SizeOf(df)   intDataLen;
    ipGlobal = Marshal.AllocHGlobal(intTotalLen);

    if (ipGlobal == IntPtr.Zero)
    {
        return null;
    }

    // Build DROPFILES structure in global memory.
    df.pFiles = Marshal.SizeOf(df);
    df.fWide = false;
    Marshal.StructureToPtr(df, ipGlobal, true);
    IntPtr ipNew = new IntPtr(ipGlobal.ToInt32()   Marshal.SizeOf(df));
    Marshal.Copy(bData, 0, ipNew, intDataLen);

    short CF_HDROP = 15;
    System.Runtime.InteropServices.ComTypes.FORMATETC formatEtc;
    System.Runtime.InteropServices.ComTypes.STGMEDIUM stgMedium;

    formatEtc = new System.Runtime.InteropServices.ComTypes.FORMATETC();
    formatEtc.cfFormat = CF_HDROP;
    formatEtc.dwAspect = System.Runtime.InteropServices.ComTypes.DVASPECT.DVASPECT_CONTENT;
    formatEtc.lindex = -1;
    formatEtc.tymed = System.Runtime.InteropServices.ComTypes.TYMED.TYMED_HGLOBAL;

    stgMedium = new System.Runtime.InteropServices.ComTypes.STGMEDIUM();
    stgMedium.unionmember = ipGlobal;
    stgMedium.tymed = System.Runtime.InteropServices.ComTypes.TYMED.TYMED_HGLOBAL;
    DataObject2 dobj = new DataObject2();
    dobj.SetData(ref formatEtc, ref stgMedium, false);
    return dobj;

}
  

С новым кодом второе приложение видит DataObject в e.Data , и я могу перетащить файл в любое приложение. За исключением того, что теперь Explorer не принимает файлы. Я что-то упускаю в своей реализации?

Комментарии:

1. Мое приложение было 64-разрядным. Это не сработало. После некоторой трассировки я обнаружил, что код разбился на IntPtr ipNew = new IntPtr(ipGlobal.ToInt32() Marshal.SizeOf(df)); из-за переполнения. Я изменил ToInt32() на ToInt64() , и тогда это сработало.