Top / JUNK / VirtualDataObject2

VirtualDataObject のソースを少し改造します。

DataObject に Stream を継承したクラスオブジェクトを保存すると、GMEM_DDESHARE なグローバルメモリを確保してすべてのデータを書き込み、ドロップ先に渡します。

メモリサイズが小さければ大丈夫ですが、大きいサイズになるとメモリの確保が出来なくなる可能性があります。

そこで、CFSTR_FILECONTENTS が要求されたら IStream を返すよう改造します。

まず System.IO.Stream のラッパークラスを作成し System.Runtime.InteropServices.ComTypes.IStream を実装します。

ManagedIStream のソースはこちら

そして IComDataObject.GetData を

List<ManagedIStream> comStreams = new List<ManagedIStream>();

[DebuggerStepThrough]
void IComDataObject.GetData(ref FORMATETC format, out STGMEDIUM medium) {
    if (format.cfFormat == NativeMethods.CF_FILEDESCRIPTORW) {
        GetFileDescriptor();
    }
    if (format.cfFormat == NativeMethods.CF_FILECONTENTS) {
        if (format.tymed.HasFlag(TYMED.TYMED_ISTREAM)) {
            var entry = dataEntries[format.lindex];
            medium = new STGMEDIUM();
            medium.tymed = TYMED.TYMED_ISTREAM;
            var comStream = new ManagedIStream(entry.Stream);
            medium.unionmember = comStream.GetComInterfaceForObject();
            comStreams.Add(comStream);
            return;
        }
    }
    comDataObject.GetData(ref format, out medium);
}

FilContents が要求されたら、IStream をサポートしているか確認し、サポートしていれば ManagedIStream を作成し、COM のインターフェイスを取得して medium 構造体に返します。

このようにすると、省メモリで転送が行えます。 積み上げた comStreams は SetData で CFSTR_PERFORMEDDROPEFFECT が来た時クリアします。

[DebuggerStepThrough]
void IComDataObject.SetData(ref FORMATETC format, ref STGMEDIUM medium, bool release) {
    if (format.cfFormat == NativeMethods.CF_TARGETCLSID) {
        SetDataTargetClsId(ref medium);
    }
    if (format.cfFormat == NativeMethods.CF_PERFORMEDDROPEFFECT) {
        comStreams.Clear();
    };
    comDataObject.SetData(ref format, ref medium, release);
}



トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   最終更新のRSS
Last-modified: 2020-03-31 (火) 23:41:06 (56d)