简体   繁体   English

在Delphi中从IDataObject检索文件名

[英]Retrieving filename from IDataObject in Delphi

I'm building a Delphi XE3 application which needs to be able to have files dropped onto it. 我正在构建一个Delphi XE3应用程序,该应用程序必须能够将文件拖放到该应用程序上。 I have the Explorer > Application side of things working, but for the life of me can't figure out to get the filename when going from Application > Application. 我的工作是“资源管理器”>“应用程序”,但是从我的生活中,我一无所知,无法从“应用程序”>“应用程序”获取文件名。

Assuming one file is dropped from say Outlook (or any other application), I have this which works as long as I manually assign filename before hand. 假设从Outlook(或任何其他应用程序)中删除了一个文件,只要我手动手动分配filename就可以使用。

SetFormatEtc( FormatEtc , CF_FILECONTENTS );
OleCheck( dataObj.GetData( FormatEtc , Medium ) );
OleStream := TOleStream.Create( IUnknown( Medium.stm ) as IStream );
MemStream := TMemoryStream.Create;
OleStream.Position := 0;
MemStream.CopyFrom( OleStream , OleStream.Size );

TMemoryStream( MemStream ).SaveToFile( 'C:\' + filename );

MemStream.Free;
OleStream.Free;
ReleaseStgMedium( Medium );

CF_FILECONTENTS format can contain several stream. CF_FILECONTENTS格式可以包含多个流。 You must check CF_FILEDESCRIPTORW and CF_FILEDESCRIPTORA formats for detection of stream count and stream names. 您必须检查CF_FILEDESCRIPTORW和CF_FILEDESCRIPTORA格式以检测流计数和流名称。 Some sources: 一些来源:

function ContainFormat(ADataObject: IDataObject; AFormat: TClipFormat;
  ATymed: Longint; AAspect: LongInt = DVASPECT_CONTENT; AIndex: LongInt = -1): Boolean;
var Format: TFormatEtc;
begin
  ZeroMemory(@Format, SizeOf(Format));
  Format.cfFormat := AFormat;
  Format.dwAspect := AAspect;
  Format.lindex := AIndex;
  Format.tymed := ATymed;
  Result := ADataObject.QueryGetData(Format) = S_OK;
end;

procedure InvalidMedium;
begin
  raise Exception.Create('Invalid medium');
end;

function ExtractStream(ADataObject: IDataObject; AIndex: Integer): IStream;
var Format: TFormatEtc;
    Medium: TStgMedium;
begin
  ZeroMemory(@Format, SizeOf(Format));
  Format.cfFormat := CF_FILECONTENTS;
  Format.dwAspect := DVASPECT_CONTENT;
  Format.lindex := AIndex;
  Format.tymed := TYMED_ISTREAM;
  ZeroMemory(@Medium, SizeOf(Medium));
  OleCheck(ADataObject.GetData(Format, Medium));
  try
    if (Medium.tymed and TYMED_ISTREAM = 0) or not Assigned(Medium.stm) then
      InvalidMedium;
    Result := IStream(Medium.stm);
  finally
    ReleaseStgMedium(Medium);
  end
end;

procedure WorkWithDropObject(const AFileName: UnicodeString; AStream: IStream);
begin

end;

procedure ProcessDataObject(ADataObject: IDataObject);
var Format: TFormatEtc;
    Medium: TStgMedium;
    FGDA: PFileGroupDescriptorA;
    FGDW: PFileGroupDescriptorW;
    i: Integer;
    Stream: IStream;
begin
  if ContainFormat(ADataObject, CF_FILECONTENTS, TYMED_ISTREAM) then
    begin
      if ContainFormat(ADataObject, CF_FILEDESCRIPTORW, TYMED_HGLOBAL) then
        begin
          Format.cfFormat := CF_FILEDESCRIPTORW;
          Format.dwAspect := DVASPECT_CONTENT;
          Format.lindex := -1;
          Format.tymed := TYMED_HGLOBAL;
          ZeroMemory(@Medium, SizeOf(Medium));
          OleCheck(ADataObject.GetData(Format, Medium));
          try
            if (Medium.tymed and TYMED_HGLOBAL = 0) or (Medium.hGlobal = 0) then
              InvalidMedium;
            FGDW := GlobalLock(Medium.hGlobal);
            if not Assigned(FGDW) then
              RaiseLastOSError;
            try
              for i := 0 to FGDW.cItems - 1 do
                begin
                  Stream := ExtractStream(ADataObject, i);
                  try
                    WorkWithDropObject(FGDW.fgd[i].cFileName, Stream);
                  finally
                    Stream := nil;
                  end;
                end;
            finally
              GlobalUnlock(Medium.hGlobal);
            end;
          finally
            ReleaseStgMedium(Medium);
          end
        end
      else
        if ContainFormat(ADataObject, CF_FILEDESCRIPTORA, TYMED_HGLOBAL) then
          begin
            Format.cfFormat := CF_FILEDESCRIPTORA;
            Format.dwAspect := DVASPECT_CONTENT;
            Format.lindex := -1;
            Format.tymed := TYMED_HGLOBAL;
            ZeroMemory(@Medium, SizeOf(Medium));
            OleCheck(ADataObject.GetData(Format, Medium));
            try
              if (Medium.tymed and TYMED_HGLOBAL = 0) or (Medium.hGlobal = 0) then
                InvalidMedium;
              FGDA := GlobalLock(Medium.hGlobal);
              if not Assigned(FGDA) then
                RaiseLastOSError;
              try
                for i := 0 to FGDA.cItems - 1 do
                  begin
                    Stream := ExtractStream(ADataObject, i);
                    try
                      WorkWithDropObject(FGDA.fgd[i].cFileName, Stream);
                    finally
                      Stream := nil;
                    end;
                  end;
              finally
                GlobalUnlock(Medium.hGlobal);
              end;
            finally
              ReleaseStgMedium(Medium);
            end
          end;
    end;
end;

Also I you want to create universal software you should process the following formats: 另外,我想创建通用软件,您应该处理以下格式:

  • CF_FILENAMEW/CF_FILENAMEA CF_FILENAMEW / CF_FILENAMEA
  • CF_HDROP CF_HDROP
  • CF_IDLIST CF_IDLIST
  • CF_FILEDESCRIPTORW/CF_FILEDESCRIPTORA/CF_FILECONTENTS CF_FILEDESCRIPTORW / CF_FILEDESCRIPTORA / CF_FILECONTENTS

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM