2

I am trying to convert the dataObject's data to CF_HDROP format when a drag operation starts. I was able to read the byteArray, which I will store at some point, but for now I am hard-coding the path to a file that actually exists on my drive.

I have used this C# drag-drop problem as a reference.

Here my implementation for OleDragEnter function:

public int OleDragEnter(object pDataObj, int grfKeyState, long pt, ref int pdwEffect)
    {
        if (pDataObj is IDataObject dataOb)
        {
            IEnumFORMATETC formatetc = dataOb.EnumFormatEtc(DATADIR.DATADIR_GET);
            List<FORMATETC> formatetcList = GetFormatEtcList(formatetc);

            if (formatetcList.Exists(f => f.tymed == TYMED.TYMED_ISTREAM))
            {
                FORMATETC iStreamFormatetc = formatetcList.Find(f => f.tymed == TYMED.TYMED_ISTREAM);

                dataOb.GetData(ref iStreamFormatetc, out var stgmedium);
                MemoryStream memStream = GetIStream(stgmedium);

                byte[] rawData = memStream.ToArray(); //I will store this on the drive at somepoint
                var fileName = StreamHelpers.GetFullFileName(); //Constant for now
                String[] strFiles = {fileName};

                _DROPFILES dropFiles = new _DROPFILES();
                int intChar, intFile, intDataLen, intPos;
                IntPtr ipGlobal = IntPtr.Zero;

                intDataLen = 0;
                for (intFile = 0; intFile <= strFiles.GetUpperBound(0); intFile++)
                {
                    intDataLen += strFiles[intFile].Length + 1;
                }

                intDataLen++;

                var byteData = new Byte[intDataLen];
                intPos = 0;

                for (intFile = 0; intFile <= strFiles.GetUpperBound(0); intFile++)
                {
                    for (intChar = 0; intChar < strFiles[intFile].Length; intChar++)
                    {
                        byteData[intPos++] = (byte)strFiles[intFile][intChar];
                    }
                    byteData[intPos++] = 0;
                }

                byteData[intPos++] = 0;

                int intTotalLen = Marshal.SizeOf(dropFiles) + intDataLen;
                ipGlobal = Marshal.AllocHGlobal(intTotalLen);

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

                dropFiles.pFiles = Marshal.SizeOf(dropFiles);
                dropFiles.fWide = false;

                Marshal.StructureToPtr(dropFiles, ipGlobal, false);
                IntPtr ipNew = new IntPtr(ipGlobal.ToInt32() + Marshal.SizeOf(dropFiles));
                Marshal.Copy(byteData, 0, ipNew, intDataLen);

                var formatEtc = new FORMATETC
                {
                    cfFormat = (short) CLIPFORMAT.CF_HDROP, //15
                    dwAspect = DVASPECT.DVASPECT_CONTENT,
                    lindex = -1,
                    tymed = TYMED.TYMED_HGLOBAL,
                    ptd = IntPtr.Zero
                };

                var stgMedium = new STGMEDIUM
                {
                    unionmember = ipGlobal,
                    tymed = TYMED.TYMED_HGLOBAL,
                    pUnkForRelease = IntPtr.Zero
                };

                dataOb.SetData(ref formatEtc, ref stgMedium, false);
            }


        }
        return 0;
    }

I keep getting "Invalid FORMATETC structure" error on:

dataOb.SetData(ref formatEtc, ref stgMedium, false);

I have tried running the application in non-debug mode & verified the integrity of the file. I noticed that DATADIR.DATADIR_SET does not return any available formats. Could that be the problem?

Edit: It seems to also be happening when I try to use the same formatEtc Object and stgMedium Object used for reading the data without any change.

Amzraptor
  • 161
  • 3
  • 11
  • It is not clear why you are trying to do this the hard way. Consider https://msdn.microsoft.com/en-us/library/system.windows.dataobject.setfiledroplist(v=vs.110).aspx – Hans Passant Feb 15 '18 at 23:17
  • @HansPassant it is a System.__ComObject, It does not implement System.Windows.Forms.IDataObject interface so I can't use the method. – Amzraptor Feb 16 '18 at 01:12
  • Did you try `lindex = 0` instead of `-1`? Some formats require this and will cause a crash if you don't. – Glenn Slayden Jun 28 '22 at 04:53

0 Answers0