- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我添加了比原始插件晚3年发布的代码,但它仍然返回错误...
代码很简单,恕我直言......但我仍然很可能错过某些方面......
查看这段代码:
{
nsScreenshot NSIS Plugin
(c) 2003: Leon Zandman (leon@wirwar.com)
Re-compiled by: Linards Liepins (linards.liepins@gmail.com)
Code by: http://www.delphitricks.com/source-code/forms/make_a_desktop_screenshot.html
(e) 2012.
}
library nsScreenshot;
uses
nsis in './nsis.pas',
Windows,
Jpeg,
graphics,
types,
SysUtils;
const
USER32 = 'user32.dll';
type
HWND = type LongWord;
{$EXTERNALSYM HWND}
HDC = type LongWord;
{$EXTERNALSYM HDC}
BOOL = LongBool;
{$EXTERNALSYM BOOL}
{$EXTERNALSYM GetDesktopWindow}
function GetDesktopWindow: HWND; stdcall; external USER32 name 'GetDesktopWindow';
{$EXTERNALSYM GetWindowDC}
function GetWindowDC(hWnd: HWND): HDC; stdcall; external USER32 name 'GetWindowDC';
{$EXTERNALSYM GetWindowRect}
function GetWindowRect(hWnd: HWND; var lpRect: TRect): BOOL; stdcall; external USER32 name 'GetWindowRect';
{$EXTERNALSYM ReleaseDC}
function ReleaseDC(hWnd: HWND; hDC: HDC): Integer; stdcall; external user32 name 'ReleaseDC';
function GetScreenshot(Filename: string; Hwnd: HWND; var Width: integer; var Height: integer): boolean; forward;
function ScreenShot(Bild: TBitMap; hWnd: HWND): boolean; forward;
function Grab_FullScreen(hwndParent: HWND; string_size: integer; variables: PChar; stacktop: pointer):integer; cdecl;
var
buf: array[0..1024] of char;
W,H: integer;
begin
Result := 0;
// set up global variables
Init(hwndParent,string_size,variables,stacktop);
// Get filename to save to
PopString;//(@buf);
// Get a full-screen screenshot
if GetScreenShot(buf,GetDesktopWindow,W,H) then begin
// Everything went just fine...
// Push image dimensions onto stack
PushString(PChar(IntToStr(H)));
PushString(PChar(IntToStr(W)));
// Push result onto stack
PushString(PChar('ok'));
Result := 1;
end else begin
// Something went wrong...
PushString(PChar('error'));
end;
end;
function Grab(hwndParent: HWND; string_size: integer; variables: PChar; stacktop: pointer):integer; cdecl;
var
buf: array[0..1024] of char;
grabWnd: HWND;
Filename: string;
W,H: integer;
begin
Result := 0;
// set up global variables
Init(hwndParent,string_size,variables,stacktop);
try
// Get filename to save to
PopString;//(@buwf);
Filename := buf;
// Get window handle of window to grab
PopString;//(@buf);
grabWnd := StrToInt(buf);
except
PushString(PChar('error'));
exit;
end;
// Get screenshot of parent windows (NSIS)
if GetScreenShot(Filename,grabWnd,W,H) then begin
// Everything went just fine...
// Push image dimensions onto stack
PushString(PChar(IntToStr(H)));
PushString(PChar(IntToStr(W)));
// Push result onto stack
PushString(PChar('ok'));
Result := 1;
end else begin
// Something went wrong...
PushString(PChar('error'));
end;
end;
function GetScreenshot(Filename: string; Hwnd: HWND; var Width: integer; var Height: integer): boolean;
var
bmp: TBitmap;
begin
Result := false;
// Get screenshot
bmp := TBitmap.Create;
try
try
if ScreenShot(bmp,Hwnd) then begin
Width := bmp.Width;
Height := bmp.Height;
bmp.SaveToFile(Filename);
Result := true;
end;
except
// Catch exception and do nothing (function return value remains 'false')
end;
finally
bmp.Free;
end;
end;
function ScreenShot(Bild: TBitMap; hWnd: HWND): boolean;
var
c: TCanvas;
r, t: TRect;
h: THandle;
begin
Result := false;
c := TCanvas.Create;
c.Handle := GetWindowDC(GetDesktopWindow);
h := hWnd;
if h <> 0 then begin
GetWindowRect(h, t);
try
r := Rect(0, 0, t.Right - t.Left, t.Bottom - t.Top);
Bild.Width := t.Right - t.Left;
Bild.Height := t.Bottom - t.Top;
Bild.Canvas.CopyRect(r, c, t);
finally
ReleaseDC(0, c.Handle);
c.Free;
end;
Result := true;
end;
end;
function GetScreenToFile(FileName: string; Quality: Word; Percent: Word): boolean;
var
Bmp: TBitmap;
Jpg: TJpegImage;
begin
Bmp := TBitmap.Create;
Jpg := TJpegImage.Create;
try
Bmp.Width := GetDeviceCaps(GetDc(0), 8) * Percent div 100;
Bmp.Height := GetDeviceCaps(GetDc(0), 10) * Percent div 100;
SetStretchBltMode(Bmp.Canvas.Handle, HALFTONE);
StretchBlt(Bmp.Canvas.Handle, 0, 0, Bmp.Width, Bmp.Height, GetDc(0), 0, 0, GetDeviceCaps(GetDc(0), 8), GetDeviceCaps(GetDc(0), 10), SRCCOPY);
Jpg.Assign(Bmp);
Jpg.CompressionQuality := Quality;
Jpg.SaveToFile(FileName);
finally
Jpg.free;
Bmp.free;
end;
end;
function ScreenToFile(hwndParent: HWND; string_size: integer; variables: PChar; stacktop: pointer):integer; cdecl;
var
buf: array[0..1024] of char;
grabWnd: HWND;
Filename: string;
W,H: integer;
begin
Result := 0;
Init(hwndParent,string_size,variables,stacktop);
try
PopString;
Filename := buf;
PopString;
grabWnd := StrToInt(buf);
except
PushString(PChar('error'));
exit;
end;
if GetScreenToFile(Filename,W,H) then
begin
PushString(PChar('ok'));
Result := 1;
end else
begin
PushString(PChar('error'));
end;
end;
//ScreenToFile('SHOT.JPG', 50, 70);
exports Grab_FullScreen,
Grab,
ScreenToFile;
begin
end.
搜索ScreenToFile
。
感谢您的任何意见。该插件对于安装程序文档生成自动化至关重要。
最佳答案
从您自己的回答帖子中可以看出您正在使用 ANSI 版本的 NSIS。由于您在 Delphi XE 中编译的库代码中使用了 string
、Char
和 PChar
映射到 Unicode 字符串,因此您可以在 NSIS 设置应用程序和您的库之间传递错误的数据。
我检查了您稍微修改过的插件核心单元 NSIS.pas
并且存在一些问题,导致您的插件无法正常工作。然而,正如我看到这个单元时,我首先想到的是将独立的过程和函数包装到一个类中。这就是我所做的。
因为您目前只使用了 your code
中原始核心单元的 3 个函数。我已经简化了仅使用这些类的类(以及一个额外的用于显示消息框的类)。这是修改后的插件核心单元的代码。我不是数据操作专家,所以也许下面的代码可以简化,但它至少可以在我测试过的 Delphi XE2 和 Delphi 2009 中运行。这是代码:
unit NSIS;
interface
uses
Windows, CommCtrl, SysUtils;
type
PParamStack = ^TParamStack;
TParamStack = record
Next: PParamStack;
Value: PAnsiChar;
end;
TNullsoftInstaller = class
private
FParent: HWND;
FParamSize: Integer;
FParameters: PAnsiChar;
FStackTop: ^PParamStack;
public
procedure Initialize(Parent: HWND; ParamSize: Integer; Parameters: PAnsiChar;
StackTop: Pointer);
procedure PushString(const Value: string = '');
function PopString: string;
function MessageDialog(const Text, Caption: string; Buttons: UINT): Integer;
end;
var
NullsoftInstaller: TNullsoftInstaller;
implementation
procedure TNullsoftInstaller.Initialize(Parent: HWND; ParamSize: Integer;
Parameters: PAnsiChar; StackTop: Pointer);
begin
FParent := Parent;
FParamSize := ParamSize;
FParameters := Parameters;
FStackTop := StackTop;
end;
procedure TNullsoftInstaller.PushString(const Value: string = '');
var
CurrParam: PParamStack;
begin
if Assigned(FStackTop) then
begin
CurrParam := PParamStack(GlobalAlloc(GPTR, SizeOf(TParamStack) + FParamSize));
StrLCopy(@CurrParam.Value, PAnsiChar(AnsiString(Value)), FParamSize);
CurrParam.Next := FStackTop^;
FStackTop^ := CurrParam;
end;
end;
function TNullsoftInstaller.PopString: string;
var
CurrParam: PParamStack;
begin
Result := '';
if Assigned(FStackTop) then
begin
CurrParam := FStackTop^;
Result := String(PAnsiChar(@CurrParam.Value));
FStackTop^ := CurrParam.Next;
GlobalFree(HGLOBAL(CurrParam));
end;
end;
function TNullsoftInstaller.MessageDialog(const Text, Caption: string;
Buttons: UINT): Integer;
begin
Result := MessageBox(FParent, PChar(Text), PChar(Caption), Buttons);
end;
initialization
NullsoftInstaller := TNullsoftInstaller.Create;
finalization
if Assigned(NullsoftInstaller) then
NullsoftInstaller.Free;
end.
正如您所看到的,声明了 NullsoftInstaller
全局变量,它允许您使用我包装了您之前使用过的函数的类。通过初始化和终结部分简化了此变量中对象实例的使用,在加载库时创建此对象实例并将其分配给此变量,并在释放库时释放该对象实例。
因此,您在代码中唯一需要做的就是使用这个 NullsoftInstaller
全局变量,如下所示:
uses
NSIS;
function ScreenToFile(Parent: HWND; ParamSize: Integer; Parameters: PAnsiChar;
StackTop: Pointer): Integer; cdecl;
var
InputString: string;
begin
Result := 0;
// this is not necessary, if you keep the NullsoftInstaller object instance
// alive (and there's even no reason to free it, since this will be done in
// the finalization section when the library is unloaded), so the following
// statement has no meaning when you won't free the NullsoftInstaller
if not Assigned(NullsoftInstaller) then
NullsoftInstaller := TNullsoftInstaller.Create;
// this has the same meaning as the Init procedure in the original core unit
NullsoftInstaller.Initialize(Parent, ParamSize, Parameters, StackTop);
// this is the same as in the original, except that returns a native string
InputString := NullsoftInstaller.PopString;
NullsoftInstaller.MessageDialog(InputString, 'PopString Result', 0);
// and finally the PushString method, this is also the same as original and
// as well as the PopString supports native string for your Delphi version
NullsoftInstaller.PushString('ok');
end;
这是我尝试的屏幕截图程序,代码中的TakeScreenshot
。它需要一个额外的参数 DropShadow
,当启用 Aero 合成时,该参数应该截取包括窗口阴影的屏幕截图。然而,除了将假窗口放置在捕获的窗口后面之外,我找不到一种以不同的方式执行此操作的方法。它有一个很大的弱点:有时会发生捕获完成后假窗口未完全显示的情况,因此它会截取捕获窗口周围的当前桌面的屏幕截图,而不是后面的白色假窗口(尚未显示)。因此,将 DropShadow
设置为 True 现在还处于实验阶段。
当 DropShadow
为 False(没有投影的屏幕截图)时,它可以正常工作。我的猜测是,由于上述 Unicode Delphi 与 ANSI NSIS 问题,您传递了错误的参数。
library nsScreenshot;
uses
Windows, SysUtils, Types, Graphics, DwmApi, Forms, JPEG, NSIS;
procedure CalcCloseCrop(Bitmap: TBitmap; const BackColor: TColor;
out CropRect: TRect);
var
X: Integer;
Y: Integer;
Color: TColor;
Pixel: PRGBTriple;
RowClean: Boolean;
LastClean: Boolean;
begin
LastClean := False;
CropRect := Rect(Bitmap.Width, Bitmap.Height, 0, 0);
for Y := 0 to Bitmap.Height-1 do
begin
RowClean := True;
Pixel := Bitmap.ScanLine[Y];
for X := 0 to Bitmap.Width - 1 do
begin
Color := RGB(Pixel.rgbtRed, Pixel.rgbtGreen, Pixel.rgbtBlue);
if Color <> BackColor then
begin
RowClean := False;
if X < CropRect.Left then
CropRect.Left := X;
if X + 1 > CropRect.Right then
CropRect.Right := X + 1;
end;
Inc(Pixel);
end;
if not RowClean then
begin
if not LastClean then
begin
LastClean := True;
CropRect.Top := Y;
end;
if Y + 1 > CropRect.Bottom then
CropRect.Bottom := Y + 1;
end;
end;
with CropRect do
begin
if (Right < Left) or (Right = Left) or (Bottom < Top) or
(Bottom = Top) then
begin
if Left = Bitmap.Width then
Left := 0;
if Top = Bitmap.Height then
Top := 0;
if Right = 0 then
Right := Bitmap.Width;
if Bottom = 0 then
Bottom := Bitmap.Height;
end;
end;
end;
procedure TakeScreenshot(WindowHandle: HWND; const FileName: string;
DropShadow: Boolean);
var
R: TRect;
Form: TForm;
Bitmap: TBitmap;
Target: TBitmap;
DeviceContext: HDC;
DesktopHandle: HWND;
ExtendedFrame: Boolean;
const
CAPTUREBLT = $40000000;
begin
ExtendedFrame := False;
if DwmCompositionEnabled then
begin
DwmGetWindowAttribute(WindowHandle, DWMWA_EXTENDED_FRAME_BOUNDS, @R,
SizeOf(TRect));
if DropShadow then
begin
ExtendedFrame := True;
R.Left := R.Left - 30;
R.Top := R.Top - 30;
R.Right := R.Right + 30;
R.Bottom := R.Bottom + 30;
end;
end
else
GetWindowRect(WindowHandle, R);
SetForegroundWindow(WindowHandle);
Bitmap := TBitmap.Create;
try
Bitmap.PixelFormat := pf24bit;
Bitmap.SetSize(R.Right - R.Left, R.Bottom - R.Top);
if ExtendedFrame then
begin
DesktopHandle := GetDesktopWindow;
DeviceContext := GetDC(GetDesktopWindow);
Form := TForm.Create(nil);
try
Form.Color := clWhite;
Form.BorderStyle := bsNone;
Form.AlphaBlend := True;
Form.AlphaBlendValue := 0;
ShowWindow(Form.Handle, SW_SHOWNOACTIVATE);
SetWindowPos(Form.Handle, WindowHandle, R.Left, R.Top,
R.Right - R.Left, R.Bottom - R.Top, SWP_NOACTIVATE);
Form.AlphaBlendValue := 255;
BitBlt(Bitmap.Canvas.Handle, 0, 0, R.Right - R.Left, R.Bottom - R.Top,
DeviceContext, R.Left, R.Top, SRCCOPY or CAPTUREBLT);
finally
Form.Free;
ReleaseDC(DesktopHandle, DeviceContext);
end;
Target := TBitmap.Create;
try
CalcCloseCrop(Bitmap, clWhite, R);
Target.SetSize(R.Right - R.Left, R.Bottom - R.Top);
Target.Canvas.CopyRect(Rect(0, 0, R.Right - R.Left, R.Bottom - R.Top),
Bitmap.Canvas, R);
Target.SaveToFile(FileName);
finally
Target.Free;
end;
end
else
begin
DeviceContext := GetWindowDC(WindowHandle);
try
BitBlt(Bitmap.Canvas.Handle, 0, 0, R.Right - R.Left, R.Bottom - R.Top,
DeviceContext, 0, 0, SRCCOPY or CAPTUREBLT);
finally
ReleaseDC(WindowHandle, DeviceContext);
end;
Bitmap.SaveToFile(FileName);
end;
finally
Bitmap.Free;
end;
end;
function ScreenToFile(Parent: HWND; ParamSize: Integer; Params: PAnsiChar;
StackTop: Pointer): Integer; cdecl;
var
I: Integer;
FileName: string;
DropShadow: Boolean;
Parameters: array[0..1] of string;
begin
Result := 0;
if not Assigned(NullsoftInstaller) then
NullsoftInstaller := TNullsoftInstaller.Create;
NullsoftInstaller.Initialize(Parent, ParamSize, Params, StackTop);
for I := 0 to High(Parameters) do
Parameters[I] := NullsoftInstaller.PopString;
FileName := Parameters[1];
if not DirectoryExists(ExtractFilePath(FileName)) or
not TryStrToBool(Parameters[0], DropShadow) then
begin
NullsoftInstaller.PushString('error');
NullsoftInstaller.PushString('Invalid parameters!');
Exit;
end;
try
TakeScreenshot(Parent, FileName, DropShadow);
NullsoftInstaller.PushString('ok');
Result := 1;
except
on E: Exception do
begin
NullsoftInstaller.PushString('error');
NullsoftInstaller.PushString(E.Message);
NullsoftInstaller.MessageDialog(E.Message, 'Error', 0);
end;
end;
end;
exports
ScreenToFile;
begin
end.
关于delphi - NSIS 插件 "nsScreenshot"在 Windows NT 6.x 中无法工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11259775/
所以我没有做很多 Win32 调用,但最近我不得不使用 GetFileTime()和 SetFileTime()功能。现在虽然我的程序没有正式支持 Win98 和更低版本,但人们仍然在那里使用它,我尽
我正在做一个应用程序虚拟化项目。所以我在 NT 级别挂接应用程序并将注册表调用定向到我的虚拟注册表。在运行任何应用程序时,如果我转到"file"->“打开”。我几乎没有像下面这样的注册表调用: ZwO
代码如下: 登陆时记录cookies页面代码 <!--#include file="md5.asp"--> //32位md5加密文件,一定得调用,该文
代码如下: <%@LANGUAGE="VBSCRIPT" CODEPAGE="65001"%> <!--#include v
我想深入研究 ntdll!NtQueueApcThread,看看在执行系统调用指令后会发生什么。根据文档(Intel® 64 and IA-32 Architectures Software Deve
显然,EASEUS Partition Master程序可以显示图形之前 Windows GUI 启动(即,它在启动时运行 CheckDisk 的同时运行)。 什么我已经知道 : 这可能需要没有很好记
我正在查看 Windows API 的事件跟踪,根据文档和我运行的一些测试,似乎如果已经有内核记录器在运行,则 API 会发送 ERROR_ALREADY_EXISTS 调用 StartTrace 时
nt.stat_result 是什么类型的对象? nt.stat_result(st_mode=33206, st_ino=0L, st_dev=0, st_nlink=0, st_uid=0, st
我开发了中间件,为我们组织内多个平台上的多个客户端应用程序提供 RPC 功能。中间件是用 C# 编写的,并作为 Windows NT 服务运行。它处理诸如对网络共享的文件访问、数据库访问等事情。中间件
我正在尝试替换一些遗留的 DefineDosDevice 用户空间代码(由于提升的和正常的 session 由不同的 DosDevice 存储表示,因此在具有管理员用户的 Vista 上不起作用,因此
我目前正在尝试调试系统死锁,但我很难理解这一点。 Child-SP RetAddr : Args to Child
我想将设备路径转换为文件路径。 我想通过进程id获取进程名,所以我用的是这段代码 PsLookupProcessByProcessId(processId,&pEProcess); ObOpenObj
我已经为 Windows XP 开发了一个驱动程序,它能够监控进程的执行。 回调函数使用标准 WDK API (PsSetCreateProcessNotifyRoutine) 接收通知。 驱动程序然
我正在为我的笔记本电脑编写一个自定义触摸板驱动程序,因为它在 Windows 下的支持非常糟糕。我已经弄清楚了协议(protocol),我准备继续实现它,但我对如何去做有点困惑。它是一个多点触控触摸板
我需要知道如何从用户输入的文件中提取目录信息,以下面的代码为例: ECHO Drag and drop your .txt file here, after that press Enter: SET
我正在使用脚本创建 SQL Server 复制。当我尝试执行 作业失败。无法确定作业 L3BPT2M-Atlas-14 的所有者 (STAR\moorer7) 是否具有服务器访问权限(原因:无法获取有
你遇到过这种问题吗? 我试过: telnet localhost 3306 连接失败。 我可以在任务管理器中看到mysqld-nt.exe(我使用的是windows平台)。 所以我重启了服务器,就ok
我有一个名为 a 的数组,我想在数组 a 的每个 nt-h 元素之后插入一个元素。例如,我想将字符串 XXX 放在数组 a 的每个 3 元素之后,结果得到一个新数组 b 如下例所示: let a =
我的问题是:如果这个文件(非常重要)很小(不到一个簇,只有几个字节),怎么可能得到文件磁盘偏移量。 目前我使用这个 Windows API 函数: DeviceIOControl(FileHandle
在 Windows 本地网络上,我有一个 MySql 数据库、几个客户端应用程序(仅查询数据库)和一个定期填充数据库的 Windows NT 服务。我正在寻找存储数据库凭据的最佳方式,以便所有应用程序
我是一名优秀的程序员,十分优秀!