本帖最后由 Dreamia 于 2013-12-08 15:03:07 编辑

解决方案 »

  1.   

    不符合用户习惯啊。用户更习惯Ctrl+C,Ctrl+V
      

  2.   

    俺也没做过此类应用,稍微帮你搜了搜,具体得自己查MSDN
    http://www.delphigroups.info/2/5d/414002.html
    shlobj 单元中的 IDataObject 接口提供了QueryGetData方法,通过QueryGetData可以获取到一个FileGroupDescriptor 文件组描述结构体的指针,由此来判断3,如何让窗体本身接受Ctrl+V事件并在事件发生时,进行指定操作?
    可以对该窗体定义热键ctrl+v,当该热键按下时做处理
    MSDN中也提供了一个综合各种剪贴板操作的示例Example of a Clipboard Viewer
    The following example shows a simple clipboard viewer application. HINSTANCE hinst; 
    UINT uFormat = (UINT)(-1); 
    BOOL fAuto = TRUE; 
     
    LRESULT APIENTRY MainWndProc(hwnd, uMsg, wParam, lParam) 
    HWND hwnd; 
    UINT uMsg; 
    WPARAM wParam; 
    LPARAM lParam; 

        static HWND hwndNextViewer; 
     
        HDC hdc; 
        HDC hdcMem; 
        PAINTSTRUCT ps; 
        LPPAINTSTRUCT lpps; 
        RECT rc; 
        LPRECT lprc; 
        HGLOBAL hglb; 
        LPSTR lpstr; 
        HBITMAP hbm; 
        HENHMETAFILE hemf; 
        HWND hwndOwner; 
     
        switch (uMsg) 
        { 
            case WM_PAINT: 
                hdc = BeginPaint(hwnd, &ps); 
     
                // Branch depending on the clipboard format. 
     
                switch (uFormat) 
                { 
                    case CF_OWNERDISPLAY: 
                        hwndOwner = GetClipboardOwner(); 
                        hglb = GlobalAlloc(GMEM_MOVEABLE, 
                            sizeof(PAINTSTRUCT)); 
                        lpps = GlobalLock(hglb); 
                        memcpy(lpps, &ps, sizeof(PAINTSTRUCT)); 
                        GlobalUnlock(hglb); 
     
                        SendMessage(hwndOwner, WM_PAINTCLIPBOARD, 
                            (WPARAM) hwnd, (LPARAM) hglb); 
     
                        GlobalFree(hglb); 
                        break; 
     
                    case CF_BITMAP: 
                        hdcMem = CreateCompatibleDC(hdc); 
                        if (hdcMem != NULL) 
                        { 
                            if (OpenClipboard(hwnd)) 
                            { 
                                hbm = (HBITMAP) 
                                    GetClipboardData(uFormat); 
                                SelectObject(hdcMem, hbm); 
                                GetClientRect(hwnd, &rc); 
     
                                BitBlt(hdc, 0, 0, rc.right, rc.bottom, 
                                    hdcMem, 0, 0, SRCCOPY); 
                                CloseClipboard(); 
                            } 
                            DeleteDC(hdcMem); 
                        } 
                        break; 
     
                    case CF_TEXT: 
                        if (OpenClipboard(hwnd)) 
                        { 
                            hglb = GetClipboardData(uFormat); 
                            lpstr = GlobalLock(hglb); 
     
                            GetClientRect(hwnd, &rc); 
                            DrawText(hdc, lpstr, -1, &rc, DT_LEFT); 
     
                            GlobalUnlock(hglb); 
                            CloseClipboard(); 
                        } 
                        break; 
     
                    case CF_ENHMETAFILE: 
                        if (OpenClipboard(hwnd)) 
                        { 
                            hemf = GetClipboardData(uFormat); 
                            GetClientRect(hwnd, &rc); 
                            PlayEnhMetaFile(hdc, hemf, &rc); 
                            CloseClipboard(); 
                        } 
                        break; 
     
                    case 0: 
                        GetClientRect(hwnd, &rc); 
                        DrawText(hdc, "The clipboard is empty.", -1, 
                            &rc, DT_CENTER | DT_SINGLELINE | 
                            DT_VCENTER); 
                        break; 
     
                    default: 
                        GetClientRect(hwnd, &rc); 
                        DrawText(hdc, "Unable to display format.", -1, 
                            &rc, DT_CENTER | DT_SINGLELINE | 
                            DT_VCENTER); 
                } 
                EndPaint(hwnd, &ps); 
                break; 
     
            case WM_SIZE: 
                if (uFormat == CF_OWNERDISPLAY) 
                { 
                    hwndOwner = GetClipboardOwner(); 
                    hglb = GlobalAlloc(GMEM_MOVEABLE, sizeof(RECT)); 
                    lprc = GlobalLock(hglb); 
                    GetClientRect(hwnd, lprc); 
                    GlobalUnlock(hglb); 
     
                    SendMessage(hwndOwner, WM_SIZECLIPBOARD, 
                        (WPARAM) hwnd, (LPARAM) hglb); 
     
                    GlobalFree(hglb); 
                } 
                break; 
     
            case WM_CREATE: 
     
                // Add the window to the clipboard viewer chain. 
     
                hwndNextViewer = SetClipboardViewer(hwnd); 
                break; 
     
            case WM_CHANGECBCHAIN: 
     
                // If the next window is closing, repair the chain. 
     
                if ((HWND) wParam == hwndNextViewer) 
                    hwndNextViewer = (HWND) lParam; 
     
                // Otherwise, pass the message to the next link. 
     
                else if (hwndNextViewer != NULL) 
                    SendMessage(hwndNextViewer, uMsg, wParam, lParam); 
     
                break; 
     
            case WM_DESTROY: 
                ChangeClipboardChain(hwnd, hwndNextViewer); 
                PostQuitMessage(0); 
                break; 
     
            case WM_DRAWCLIPBOARD:  // clipboard contents changed. 
     
                // Update the window by using Auto clipboard format. 
     
                SetAutoView(hwnd); 
     
                // Pass the message to the next window in clipboard 
                // viewer chain. 
     
                SendMessage(hwndNextViewer, uMsg, wParam, lParam); 
                break; 
     
            case WM_INITMENUPOPUP: 
                if (!HIWORD(lParam)) 
                    InitMenu(hwnd, (HMENU) wParam); 
                break; 
     
            case WM_COMMAND: 
                switch (LOWORD(wParam)) 
                { 
                    case IDM_EXIT: 
                        DestroyWindow(hwnd); 
                        break; 
     
                    case IDM_AUTO: 
                        SetAutoView(hwnd); 
                        break; 
     
                    default: 
                        fAuto = FALSE; 
                        uFormat = LOWORD(wParam); 
                        InvalidateRect(hwnd, NULL, TRUE); 
                } 
                break; 
     
            default: 
                return DefWindowProc(hwnd, uMsg, wParam, lParam); 
        } 
        return (LRESULT) NULL; 

     
    void WINAPI SetAutoView(HWND hwnd) 

        static UINT auPriorityList[] = { 
            CF_OWNERDISPLAY, 
            CF_TEXT, 
            CF_ENHMETAFILE, 
            CF_BITMAP 
        }; 
     
        uFormat = GetPriorityClipboardFormat(auPriorityList, 4); 
        fAuto = TRUE; 
     
        InvalidateRect(hwnd, NULL, TRUE); 
        UpdateWindow(hwnd); 

     
    void WINAPI InitMenu(HWND hwnd, HMENU hmenu) 

        UINT uFormat; 
        char szFormatName[80]; 
        LPCSTR lpFormatName; 
        UINT fuFlags; 
        UINT idMenuItem; 
     
        // If a menu is not the display menu, no initialization is necessary. 
     
        if (GetMenuItemID(hmenu, 0) != IDM_AUTO) 
            return; 
     
        // Delete all menu items except the first. 
     
        while (GetMenuItemCount(hmenu) > 1) 
            DeleteMenu(hmenu, 1, MF_BYPOSITION); 
     
        // Check or uncheck the Auto menu item. 
     
        fuFlags = fAuto ? MF_BYCOMMAND | MF_CHECKED : 
            MF_BYCOMMAND | MF_UNCHECKED; 
        CheckMenuItem(hmenu, IDM_AUTO, fuFlags); 
     
        // If there are no clipboard formats, return. 
     
        if (CountClipboardFormats() == 0) 
            return; 
     
        // Open the clipboard. 
     
        if (!OpenClipboard(hwnd)) 
            return; 
     
        // Add a separator and then a menu item for each format. 
     
        AppendMenu(hmenu, MF_SEPARATOR, 0, NULL); 
        uFormat = EnumClipboardFormats(0); 
     
        while (uFormat) 
        { 
            // Call an application-defined function to get the name 
            // of the clipboard format. 
     
            lpFormatName = GetPredefinedClipboardFormatName(uFormat); 
     
            // For registered formats, get the registered name. 
     
            if (lpFormatName == NULL) 
            { 
                if (GetClipboardFormatName(uFormat, szFormatName, 
                        sizeof(szFormatName))) 
                    lpFormatName = szFormatName; 
                else 
                    lpFormatName = "(unknown)"; 
            } 
     
            // Add a menu item for the format. For displayable 
            // formats, use the format ID for the menu ID. 
     
            if (IsDisplayableFormat(uFormat)) 
            { 
                fuFlags = MF_STRING; 
                idMenuItem = uFormat; 
            } 
            else 
            { 
                fuFlags = MF_STRING | MF_GRAYED; 
                idMenuItem = 0; 
            } 
            AppendMenu(hmenu, fuFlags, idMenuItem, lpFormatName); 
     
            uFormat = EnumClipboardFormats(uFormat); 
        } 
        CloseClipboard(); 
     

     
    BOOL WINAPI IsDisplayableFormat(UINT uFormat) 

        switch (uFormat) 
        { 
            case CF_OWNERDISPLAY: 
            case CF_TEXT: 
            case CF_ENHMETAFILE: 
            case CF_BITMAP: 
                return TRUE; 
        } 
        return FALSE; 
      

  3.   

    感谢!这个帖子之前我也有研究过,经过一番借鉴和改进,现在的代码如下:unit Unit1;interfaceuses
      Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Olectrls,ActiveX,Data.DSUtil,
      Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Clipbrd, Vcl.StdCtrls, Vcl.Buttons, shellapi, Winapi.ShlObj,System.Win.ComObj;var
            CF_FILEGROUPDESCRIPTORA: UINT = 0;
            CF_FILEGROUPDESCRIPTORW: UINT = 0;
            CF_FILECONTENTS: UINT = 0;type
      TForm1 = class(TForm)
        btn1: TBitBtn;
        edt1: TEdit;
        txt1: TMemo;
        procedure Button2Click(Sender: TObject);
        procedure ProcessFileContents(Obj: IDataObject; Index: UINT; FileName: string);
      private
        { Private declarations }
      public
        { Public declarations }
        NextViewerHandle : THandle;
      end;var
      Form1: TForm1;implementation{$R *.dfm}function StringFromClipboardFormat(cf: Word): string;
    var
      sz: array[0..300] of char;
    begin
      {Check if the data is one of the basic clipboard formats}
      case cf of
        CF_DIF         : result := 'CF_DIF';
        CF_DIB         : result := 'CF_DIB';
        CF_TEXT        : result := 'CF_TEXT';
        CF_SYLK        : result := 'CF_SYLK';
        CF_TIFF        : result := 'CF_TIFF';
        CF_RIFF        : result := 'CF_RIFF';
        CF_WAVE        : result := 'CF_WAVE';
        CF_HDROP       : result := 'CF_HDROP';
        CF_BITMAP      : result := 'CF_BITMAP';
        CF_LOCALE      : result := 'CF_LOCALE';
        CF_OEMTEXT     : result := 'CF_OEMTEXT';
        CF_PALETTE     : result := 'CF_PALETTE';
        CF_PENDATA     : result := 'CF_PENDATA';
        CF_UNICODETEXT : result := 'CF_UNICODETEXT';
        CF_ENHMETAFILE : result := 'CF_ENHMETAFILE';
        CF_METAFILEPICT: result := 'CF_METAFILEPICT';    else
        begin
          {Data type not found,so get the description for this data type}
          GetClipboardFormatName(cf, @sz, 200);
          {Add the numeric value of the item?}
          result := sz;
        end;
      end;
    end;procedure TForm1.ProcessFileContents(Obj: IDataObject; Index: UINT; FileName: string);
    var
      Fetc: FORMATETC;
      Medium: STGMEDIUM;
      HR: HRESULT;
    begin
      Fetc.cfFormat := CF_FILECONTENTS;
      Fetc.ptd := nil;
      Fetc.dwAspect := DVASPECT_CONTENT;
      Fetc.lindex := Index;
      Fetc.tymed := TYMED_HGLOBAL or TYMED_ISTREAM or TYMED_ISTORAGE;
      //QueryGetData(
      HR := Obj.GetData(Fetc, Medium);
      txt1.Lines.Add('HR = [' + IntToStr(HR)+'], ');
      if SUCCEEDED(HR) then
      begin
        case Medium.tymed of
          TYMED_HGLOBAL: // use Medium.hGlobal as needed ...
            txt1.Lines.Add('TYMED_HGLOBAL');
          TYMED_ISTREAM:
          begin
            txt1.Lines.Add('TYMED_ISTREAM');
            //HandleFiles(Obj, FEtc, Medium, FileName);   //错误:Undeclared Identifier 'HandleFiles'
          end;
          TYMED_ISTORAGE :
          begin
            txt1.Lines.Add('TYMED_ISTORAGE');
            //DisplayStorage(IStorage(Medium.stg));   //错误:Undeclared Identifier 'DisplayStorage'
          end;
        end;
        ReleaseStgMedium(Medium);
      end else
        txt1.Lines.Add('Failed');
    end;procedure TForm1.Button2Click(Sender: TObject);
    var
      DataObj : IDataObject;
      Fetc: FORMATETC;
      Medium: STGMEDIUM;
      Enum: IEnumFORMATETC;
      Group: Pointer;
      S: string;
      FormatName: array[0..128] of char;
      I: UINT;
      FileNameA: AnsiString;
      FileNameW: WideString;
      HR: HResult;
    begin
      txt1.Clear;
      if (OleGetClipboard(DataObj) <> S_OK) then Exit;
      if DataObj = nil then exit;
      if FAILED(DataObj.EnumFormatEtc(DATADIR_GET, Enum)) then Exit;  while Enum.Next(1, Fetc, nil) = S_OK do
      begin
        S := StringFromClipboardFormat(fetc.cfFormat);
        GetClipboardFormatName(FEtc.cfFormat, FormatName, SizeOf(FormatName));    txt1.Lines.Add('[Clipboard Format: ' + S + ' ]');
        txt1.Lines.Add('[Format: ' + FormatName + ', ' + IntToStr(Fetc.cfFormat) + ' ]');
        txt1.Lines.Add('[Aspect: ' + IntToStr(Fetc.dwAspect) + ' ]');
        txt1.Lines.Add('[Lindex: ' + IntToStr(Fetc.lindex) + ' ]');
        txt1.Lines.Add('[Tymed: ' + IntToStr(Fetc.tymed) + ' ]');    if (S = 'FileGroupDescriptor') or (S = 'FileGroupDescriptorW') or
           (Fetc.cfFormat in [CF_FILEGROUPDESCRIPTORA, CF_FILEGROUPDESCRIPTORW]) then
        begin
          HR := DataObj.GetData(Fetc, Medium);
          txt1.Lines.Add('[ HResult = '+inttostr(HR)+'] ');
          if Failed(HR) then Exit;
          case Medium.tymed of
            TYMED_HGLOBAL :
            begin
              txt1.Lines.Add('[ Using Tymed_HGLOBAL ]');
              Group := GlobalLock(Medium.hGlobal);
              try
                if FEtc.cfFormat = CF_FILEGROUPDESCRIPTORW then
                begin
                  for I := 0 to PFileGroupDescriptorW(Group)^.cItems-1 do
                  begin
                    FileNameW := PFileGroupDescriptorW(Group)^.fgd[I].cFileName;
                    txt1.Lines.Add('filenameW : ' + Filenamew);
                    ProcessFileContents(DataObj, I, FilenameW);
                  end;
                end else
                begin
                  for I := 0 to PFileGroupDescriptorA(Group)^.cItems-1 do
                  begin
                    FileNameA := PFileGroupDescriptorA(Group)^.fgd[I].cFileName;
                    txt1.Lines.Add('filenameA : ' + FileNameA);
                    ProcessFileContents(DataObj, I, FileNameA);
                  end;
                end;
              finally
                GlobalUnlock(Medium.hGlobal);
              end;
            end; //tymed_hglobal
            TYMED_ISTREAM  :
              txt1.Lines.Add('[ Using Tymed_ISTREAM ]');
            TYMED_ISTORAGE :
              txt1.Lines.Add('[ Using Tymed_ISTORAGE ]')
          end;
          ReleaseStgMedium(Medium);
        end;
      end;
    end;end.运行后,选择三封邮件复制,测试结果如下:
    [Clipboard Format: RenPrivateSourceFolder ]
    [Format: RenPrivateSourceFolder, 50308 ]
    [Aspect: 1 ]
    [Lindex: -1 ]
    [Tymed: 4 ]
    [Clipboard Format: RenPrivateMessages ]
    [Format: RenPrivateMessages, 50090 ]
    [Aspect: 1 ]
    [Lindex: -1 ]
    [Tymed: 4 ]
    [Clipboard Format: RenPrivateItem ]
    [Format: RenPrivateItem, 49724 ]
    [Aspect: 1 ]
    [Lindex: -1 ]
    [Tymed: 1 ]
    [Clipboard Format: FileGroupDescriptor ]
    [Format: FileGroupDescriptor, 49426 ]
    [Aspect: 1 ]
    [Lindex: -1 ]
    [Tymed: 1 ]
    [ HResult = 0] 
    [ Using Tymed_HGLOBAL ]
    filenameA : 答复  14年现金流预测--重要邮件.msg
    HR = [-2147221404], 
    Failed
    filenameA : 答复  冠军队聚餐.msg
    HR = [-2147221404], 
    Failed
    filenameA : 答复  建主数据.msg
    HR = [-2147221404], 
    Failed
    [Clipboard Format: FileGroupDescriptorW ]
    [Format: FileGroupDescriptorW, 49427 ]
    [Aspect: 1 ]
    [Lindex: -1 ]
    [Tymed: 1 ]
    [ HResult = 0] 
    [ Using Tymed_HGLOBAL ]
    filenameA : T{

    HR = [-2147221404], 
    Failed
    filenameA : 
    HR = [-2147221404], 
    Failed
    filenameA : 
    HR = [-2147221404], 
    Failed
    [Clipboard Format: FileContents ]
    [Format: FileContents, 49425 ]
    [Aspect: 1 ]
    [Lindex: -1 ]
    [Tymed: 12 ]
    [Clipboard Format: Object Descriptor ]
    [Format: Object Descriptor, 49166 ]
    [Aspect: 1 ]
    [Lindex: -1 ]
    [Tymed: 1 ]
    [Clipboard Format: CF_TEXT ]
    [Format: Object Descriptor, 1 ]
    [Aspect: 1 ]
    [Lindex: -1 ]
    [Tymed: 1 ]
    [Clipboard Format: CF_UNICODETEXT ]
    [Format: Object Descriptor, 13 ]
    [Aspect: 1 ]
    [Lindex: -1 ]
    [Tymed: 1 ]现在能获取到文件名了,那么该如何将文件另存为文件,或者传入Stream以便FTP上传呢?链接中的帖子也没有解决此问题。不知大侠是否可以帮忙看看,谢谢!
      

  4.   

    用GlobalAlloc()分配一内存区域.
    用剪贴板的SetAsHandle()把两者联系起来,然后把剪贴板的数据拷入内存.
    再建一个流导入数据.
      

  5.   

    我觉得可不可以这样做:
    Office里面不是有宏吗,你在outlook里添加自定义按钮,叫‘申请’,然后通过宏完成里的申请动作(插入记录到里的申请表单,把附件上传到指定地方),然后把这个过程做成一个模板,用户打开邮件就自动加载该模板,这样你的整个业务流程是不是会更简洁,我是这么理解的,不知道有没有偏离你所指的意思
      

  6.   

    感谢回复,但是这样做的话不太现实,我的系统已推广到整个中国区上百家工厂,用户数百个,我不可能要求他们都在Office里进行设置。何况,万一碰到用户用的是Foxmail之类怎么办?
    目前系统已能用,只是希望更符合用户习惯,可以Ctrl+V从邮件中复制邮件/附件上传到系统中,而不是另存为文件,再浏览、选择、上传。
      

  7.   

    其实大可不必搞那么多,直接用TClipboard类就可以了,复制邮件时其内容无非两种格式,一个文本(html也是文本),一种是附件(文件),在outlook里复制了又不用做什么判断直接全部复制。
    关于
    “用GlobalAlloc()分配一内存区域.
    用剪贴板的SetAsHandle()把两者联系起来,然后把剪贴板的数据拷入内存.
    再建一个流导入数据.”仔细看
    http://blog.csdn.net/lailai186/article/details/8793012
    http://blog.csdn.net/lailai186/article/details/8793057