如何从剪贴板获取复制的Outlook邮件/附件,保存为文件? 本帖最后由 Dreamia 于 2013-12-08 15:03:07 编辑 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 不符合用户习惯啊。用户更习惯Ctrl+C,Ctrl+V 俺也没做过此类应用,稍微帮你搜了搜,具体得自己查MSDNhttp://www.delphigroups.info/2/5d/414002.htmlshlobj 单元中的 IDataObject 接口提供了QueryGetData方法,通过QueryGetData可以获取到一个FileGroupDescriptor 文件组描述结构体的指针,由此来判断3,如何让窗体本身接受Ctrl+V事件并在事件发生时,进行指定操作?可以对该窗体定义热键ctrl+v,当该热键按下时做处理MSDN中也提供了一个综合各种剪贴板操作的示例Example of a Clipboard ViewerThe 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; } 感谢!这个帖子之前我也有研究过,经过一番借鉴和改进,现在的代码如下: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年现金流预测--重要邮件.msgHR = [-2147221404], FailedfilenameA : 答复 冠军队聚餐.msgHR = [-2147221404], FailedfilenameA : 答复 建主数据.msgHR = [-2147221404], Failed[Clipboard Format: FileGroupDescriptorW ][Format: FileGroupDescriptorW, 49427 ][Aspect: 1 ][Lindex: -1 ][Tymed: 1 ][ HResult = 0] [ Using Tymed_HGLOBAL ]filenameA : T{Y HR = [-2147221404], FailedfilenameA : HR = [-2147221404], FailedfilenameA : 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上传呢?链接中的帖子也没有解决此问题。不知大侠是否可以帮忙看看,谢谢! 用GlobalAlloc()分配一内存区域.用剪贴板的SetAsHandle()把两者联系起来,然后把剪贴板的数据拷入内存.再建一个流导入数据. 我觉得可不可以这样做:Office里面不是有宏吗,你在outlook里添加自定义按钮,叫‘申请’,然后通过宏完成里的申请动作(插入记录到里的申请表单,把附件上传到指定地方),然后把这个过程做成一个模板,用户打开邮件就自动加载该模板,这样你的整个业务流程是不是会更简洁,我是这么理解的,不知道有没有偏离你所指的意思 感谢回复,但是这样做的话不太现实,我的系统已推广到整个中国区上百家工厂,用户数百个,我不可能要求他们都在Office里进行设置。何况,万一碰到用户用的是Foxmail之类怎么办?目前系统已能用,只是希望更符合用户习惯,可以Ctrl+V从邮件中复制邮件/附件上传到系统中,而不是另存为文件,再浏览、选择、上传。 其实大可不必搞那么多,直接用TClipboard类就可以了,复制邮件时其内容无非两种格式,一个文本(html也是文本),一种是附件(文件),在outlook里复制了又不用做什么判断直接全部复制。关于“用GlobalAlloc()分配一内存区域.用剪贴板的SetAsHandle()把两者联系起来,然后把剪贴板的数据拷入内存.再建一个流导入数据.”仔细看http://blog.csdn.net/lailai186/article/details/8793012http://blog.csdn.net/lailai186/article/details/8793057 请教一个关于Toolbar的问题 菜鸟问题:如何通过自己设置的特殊字符来拆分字符串 WideCharToMultiByte的问题 ,高分相送。。在线等待。。。 中国软件业的程序员认为比较黑的公司清单 欢迎加入(2) 这样的客户端如何发布? 哪位现在用delphi的大侠给给我发二个BDE文件吗?在线急等 查询的问题!!!!急 关于DELPHI网络通信SNMP方面(我将给出500分) 自定义函数出错求教 关于socket分段接收问题,望各位大侠指点一二 FastReport如实现打印固定行数,不足补打空白行??? 关于StringGrid 导出数据到EXecl(有大量数据)
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;
}
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{
Y
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上传呢?链接中的帖子也没有解决此问题。不知大侠是否可以帮忙看看,谢谢!
用剪贴板的SetAsHandle()把两者联系起来,然后把剪贴板的数据拷入内存.
再建一个流导入数据.
Office里面不是有宏吗,你在outlook里添加自定义按钮,叫‘申请’,然后通过宏完成里的申请动作(插入记录到里的申请表单,把附件上传到指定地方),然后把这个过程做成一个模板,用户打开邮件就自动加载该模板,这样你的整个业务流程是不是会更简洁,我是这么理解的,不知道有没有偏离你所指的意思
目前系统已能用,只是希望更符合用户习惯,可以Ctrl+V从邮件中复制邮件/附件上传到系统中,而不是另存为文件,再浏览、选择、上传。
关于
“用GlobalAlloc()分配一内存区域.
用剪贴板的SetAsHandle()把两者联系起来,然后把剪贴板的数据拷入内存.
再建一个流导入数据.”仔细看
http://blog.csdn.net/lailai186/article/details/8793012
http://blog.csdn.net/lailai186/article/details/8793057