【发布时间】:2016-03-02 00:07:07
【问题描述】:
我找到了一个演示应用程序,它能够使用 DwmRegisterThumbnail 获取最小化/隐藏窗口的屏幕截图。它工作完美,但结果图像是在表单本身而不是 TBitmap 中绘制的。
这是代码:
procedure TfrmMain.PreviewWindow(const ASource, ADest: HWND; const ARect: TRect);
var
LResult: HRESULT;
LThumpProp: DWM_THUMBNAIL_PROPERTIES;
begin
if NOT DwmCompositionEnabled then begin
MessageDlg('DWM composition is NOT enabled.', mtWarning, [mbOK], 0);
Exit;
end;
PreviewDisable;
FPreviewEnabled := Succeeded(DwmRegisterThumbnail(ADest, ASource, @FTumbnail));
if FPreviewEnabled then begin
LThumpProp.dwFlags := DWM_TNP_SOURCECLIENTAREAONLY or DWM_TNP_VISIBLE or
DWM_TNP_OPACITY or DWM_TNP_RECTDESTINATION;
LThumpProp.fSourceClientAreaOnly := False;
LThumpProp.fVisible := True;
LThumpProp.opacity := 200;
LThumpProp.rcDestination := ARect;
LResult := DwmUpdateThumbnailProperties(FTumbnail, LThumpProp);
FPreviewEnabled := (LResult = S_OK);
end else
MessageDlg('Cannot link to window ' + IntToStr(ASource), mtError, [mbOK], 0);
end;
并且函数的调用方式如下:
PreviewWindow( TargetWindow.Handle, Self.Handle, LRect);
第二个参数是表单本身的句柄。到目前为止,我尝试使用 GetFormImage,但它没有捕获绘制捕获窗口的区域。我尝试通过以下方式将图像放入 TBitmap,但有两个问题:
procedure TfrmMain.PreviewWindow(const ASource, ADest: HWND; const ARect: TRect);
var
LResult: HRESULT;
LThumpProp: DWM_THUMBNAIL_PROPERTIES;
Bitmap: TBitmap;
Width, Height: integer;
begin
if NOT DwmCompositionEnabled then begin
MessageDlg('DWM composition is NOT enabled.', mtWarning, [mbOK], 0);
Exit;
end; // if NOT DwmCompositionEnabled then begin
Bitmap := TBitmap.Create;
try
Width:=500; //default size....
Height:=500;
Bitmap.SetSize(Width, Height);
PreviewDisable;
//THE FOLLOWING LINE RETURN FALSE WHEN BITMAP.HANDLE IS USED INSTEAD OF ADest
FPreviewEnabled := Succeeded(DwmRegisterThumbnail(Bitmap.Handle, ASource, @FTumbnail));
if FPreviewEnabled then begin
LThumpProp.dwFlags := DWM_TNP_SOURCECLIENTAREAONLY or DWM_TNP_VISIBLE or
DWM_TNP_OPACITY or DWM_TNP_RECTDESTINATION;
LThumpProp.fSourceClientAreaOnly := False;
LThumpProp.fVisible := True;
LThumpProp.opacity := 200;
LThumpProp.rcDestination := ARect;
LResult := DwmUpdateThumbnailProperties(FTumbnail, LThumpProp);
FPreviewEnabled := (LResult = S_OK);
BitBlt(Bitmap.Canvas.Handle, 0, 0, Width, Height, ADest, 0, 0, SRCCOPY);
Bitmap.SaveToFile('d:\test.bmp'); //Test if the image is correct
end else
MessageDlg('Cannot link to window ' + IntToStr(ASource), mtError, [mbOK], 0);
finally
Bitmap.Free;
end;
end;
1.获取正确的尺寸
2.当TBitmap的句柄作为参数时,成功返回false。
可以将图像放入 TBitmap 吗?提前致谢。
已编辑:
我最后一次尝试使用TImage,然后将图像内容保存到文件中。但是会出现白色屏幕截图。
uses
dwmapi;
private
{ Private declarations }
thumb: PHTHUMBNAIL;
function UpdateThumb(aThumb: PHTHUMBNAIL; aDestRect: TRect):boolean;
var
size: PSize;
props: PDWM_THUMBNAIL_PROPERTIES;
begin
result:=true;
if aThumb <> nil then
begin
DwmQueryThumbnailSourceSize(aThumb^, size);
props.dwFlags:=DWM_TNP_VISIBLE and DWM_TNP_RECTDESTINATION and DWM_TNP_OPACITY;
props.fVisible:=true;
props.opacity:=50;
props.fSourceClientAreaOnly:=false;
props.rcDestination:= aDestRect;
if (size.cx < aDestRect.Right - aDestRect.Left) then props.rcDestination.Right:=props.rcDestination.Left+size.cx;
if (size.cy < aDestRect.Bottom - aDestRect.Top) then props.rcDestination.Top:=props.rcDestination.Left+size.cy;
DwmUpdateThumbnailProperties(aThumb^,props^);
end;
end;
procedure TForm1.btn1Click(Sender: TObject);
var
h: Hwnd;
r: TRect;
wwidth, wheight: integer;
i: integer;
begin
h:=FindWindow(nil,'Untitled - Notepad');
if h<>0 then
begin
GetWindowRect(h,r);
wwidth:=r.Right-r.Left;
wheight:=r.Bottom-r.Top;
if thumb <> nil then
begin
DwmUnregisterThumbnail(thumb^);
thumb := nil;
end;
i:=DwmRegisterThumbnail(img1.canvas.Handle,h,thumb);
if i=0 then
UpdateThumb(thumb, Rect(0,0,Img1.Width, Img1.Height));
end;
【问题讨论】:
-
GetFormImage()通过将WM_ERASEBKGND和WM_PAINT消息模拟到 Form 将 Form 绘制到内存中的HDC上,然后将HDC复制到最终的TBitmap.那幅画中不包括缩略图。您不能将HBITMAP提供给DwmRegisterThumbnail(),也不能直接从HWND提供BitBlt()。 -
如果 DWM 实际上将缩略图直接渲染到实际的 HWND 上,而不是简单地将其渲染为 HWND 的合成图像的一部分,当它显示在屏幕上时,我会感到非常惊讶。 DWM 通过在内存中操作位图、将多个源位图合成在一起、混合像素等,最后将生成的图像复制到屏幕显示上来完成其高级视觉效果和性能增强。缩略图可能只是一起渲染以在屏幕上生成 HWND 视觉图像的几个位图之一。
-
要捕获隐藏/最小化窗口的图像,您最好的选择可能是简单地显示/恢复窗口,通过传统方式从屏幕上获取其图像 (
GetDC(0),BitBlt()等),然后在完成时重新隐藏/最小化它。您可以禁用窗口动画以加快恢复/最小化效果,并且可以将窗口的 alpha 不透明度设置为 1,因此它在技术上对操作系统 可见,但用户实际上不会在屏幕上看到它.像这样的小技巧。 -
@Ramy Lebeau,我尝试使用
TImage然后将内容保存到文件,见上文,我更新了我的问题以显示这个。但是会出现一个白色的屏幕截图。那么,根据您的技术知识,我的想法有成功的可能性吗? -
现在您将
TImage的内部HDC而不是HWND传递给DwmRegisterThumbnail()。您了解HWND(窗口)、HDC(设备上下文)、HBITMAP(位图)等之间的区别吗?它们代表不同的事物,它们不可互换。DwmRegisterThumbnail()仅适用于HWNDs,仅此而已。例如,您可以使用GetDC()或GetWindowDC()为HWND获取HDC。但是您不能在需要HWND的地方使用HDC,反之亦然。
标签: delphi bitmap screenshot dwm