Archiv verlassen und diese Seite im Standarddesign anzeigen : Screenshot
Volkmar Rigo
17.02.2000, 20:38
ich möchte ein programm erstellen, das alle x sekunden ein screenshot vom desktop macht. im moment verwede ich folgende funktion, die aber zu langsam ist. hat jemand optimierungsvorschläge:<P>
bmp.PixelFormat:=pf8bit;<br>
bmp.Width := Screen.DeskTopWidth;<br>
bmp.Height := Screen.DeskTopHeight;<br>
dc := GetDc(0); If (dc = 0) then exit;<br>
If (GetDeviceCaps(dc, RASTERCAPS) And RC_PALETTE = RC_PALETTE) Then<br>
Begin<br>
GetMem(lpPal, sizeof(TLOGPALETTE) + (255 * sizeof(TPALETTEENTRY)));<br>
FillChar(lpPal^, sizeof(TLOGPALETTE) + (255 * sizeof(TPALETTEENTRY)), #0);<br>
lpPal^.palVersion := $300;<br>
lpPal^.palNumEntries := GetSystemPaletteEntries(dc, 0, 256, lpPal^.palPalEntry); <br>
If (lpPal^.PalNumEntries <> 0) Then bmp.Palette := CreatePalette(lpPal^);<br>
FreeMem(lpPal, sizeof(TLOGPALETTE) + (255 * sizeof(TPALETTEENTRY)));<br>
End;<br>
BitBlt(bmp.Canvas.Handle, 0, 0, Screen.DeskTopWidth, Screen.DeskTopHeight, Dc, Screen.DeskTopLeft, Screen.DeskTopTop, SRCCOPY);<br>
ReleaseDc(0, dc);<br>
Andreas Kosch
18.02.2000, 06:50
Hallo,
heutzutage kann man die Sonderfälle 16 bzw. 256 Farben ignorieren, daher würde ich auf die langsamen Palettenfunktionen verzichten. Das folgende Beispiel druckt das über das Fensterhandle definierte Fenster aus:
<pre>
procedure E_Snapshot(const Text: PChar; hWindow: Integer);
const
cRAND = 250;
var
hWin : HWND;
aWinRect : TRect;
iW, iH : Integer;
aScreenBitmap : TBitmap;
aDC : THandle;
hBM : HBitmap;
iInfoSize : DWORD;
iImageSize : DWORD;
pInfo : PBitmapInfo;
pImage : Pointer;
iDIBWidth : Integer;
iDIBHeight : Integer;
iScale : Integer;
iDestWidth : Integer;
iDestHeight : Integer;
iDPI : Integer;
sInfo : String;
begin
try
if Assigned(Text) then
sInfo := Text
else
sInfo := '(ohne Titel)';
hWin := hWindow;
GetWindowRect(hWin, aWinRect);
iW := aWinRect.Right - aWinRect.Left;
iH := aWinRect.Bottom - aWinRect.Top;
aDC := GetWindowDC(hWin);
aScreenBitmap := TBitmap.Create;
try
aScreenBitmap.Width := iW;
aScreenBitmap.Height := iH;
BitBlt(aScreenBitmap.Canvas.Handle, 0, 0, iW, iH, aDC, 0, 0, SRCCOPY);
ReleaseDC(hWin, aDC);
Printer.Orientation := poLandscape;
Printer.BeginDoc;
with Printer, Canvas do
begin
hBM := aScreenBitmap.Handle;
GetDIBSizes(hBM, iInfoSize, iImageSize);
pInfo := AllocMem(iInfoSize);
try
pImage := AllocMem(iImageSize);
try
GetDIB(hBM, 0, pInfo^, pImage^);
with pInfo^.bmiHeader do
begin
iDIBWidth := biWidth;
iDIBHeight := biHeight;
end;
iDPI := GetDeviceCaps(Canvas.Handle, LOGPIXELSX);
// Druckerauflösung berücksichtigen (300dpi=2; 600dpi=4)
iScale := (iDPI div 300) * 2;
// Größe des Druckbereiches berechnen
iDestWidth := iW * iScale;
iDestHeight := iH * iScale;
{$IFDEF TestOutput}
sInfo := Format('Originalfenster: %d-%d; iScale: %d; iDestWidth: %d; ' +
'iDestHeight: %d; Screen: %d-%d; Page: %d-%d = %d DPI',
[iW, iH, iScale, iDestWidth, iDestHeight,
Screen.Width, Screen.Height,
PageWidth, PageHeight, iDPI]);
{$ENDIF}
Canvas.TextOut(cRAND, 100, sInfo);
StretchDIBits(Canvas.Handle, cRAND, cRAND,
iDestWidth + cRAND, iDestHeight + cRAND,
0, 0, iDIBWidth, iDIBHeight, pImage, pInfo^,
DIB_RGB_COLORS, SRCCOPY);
finally
FreeMem(pImage, iImageSize);
end;
finally
FreeMem(pInfo, iInfoSize);
end;
end;
Printer.EndDoc;
finally
aScreenBitmap.Free;
end;
except
MessageBeep($FFFFFFFF);
end
end;
</pre>
Volkmar Rigo
20.02.2000, 19:26
leider reicht das weglassen der palettenfunction nicht. ich möchte nämlich einen server erstellen, der die aktuelle bildschirmansicht einem client auf einem anderen rechner zur verfügung stellt (ala pc anywhere). deshalb darf der server die arbeitsgeschwindigkeit der rechners nicht merklich beeinflussen... es muß gehen, denn es gibt ja schon programme, die sowas können
Andreas Kosch
21.02.2000, 13:09
Hallo Volkmar,
die "Programme, die das können" gehen jedoch nach einem völlig anderen Prinzip vor. Anstelle den Bildschirm als riesige Grafik zu übertragen (sehr grosse Datenmengen -> hohe Netzlast), klinken sich diese Tools in die <b>GDI</b>-Funktionen von Windows ein und speichern nur die aufgerufenen API-Funktionen mit ihren jeweiligen Parametern als Meta-Daten (sehr kleine Datenmenge -> kleine Netzbelastung). Je nach Win32-Version sind dazu unterschiedliche Techniken üblich, ab Windows 2000 hat Microsoft diesen Modus standardisiert, indem nur noch eine einzige Schnittstelle dafür zuständig ist. Der andere Rechner (der Empfänger) muss diese zwischengespeicherten GDI-Aufruf dann nur noch abspielen und erhält so die exakt gleiche Bildschirmdarstellung. Da der Empfänger auch den <b>ViewPort</b> definieren kann, kann bei der Wiedergabe der zu zeichnende Bereich auch in ein beliebig grossen Fenster verkleinert werden.
Volkmar Rigo
22.02.2000, 16:37
ich habe bei tests festgestellt, daß die übertragung bei mir nicht das problem ist (da lokales netzwerk und komprimiertes bild). ist es kompliziert, sich an die gdi-funktionen zu hängen
Andreas Kosch
23.02.2000, 13:25
Hallo,
gute Frage - ich habe mir das nicht näher angeschaut. Über das Win32-SDK-Setup kann man sich Unmengen von Beispielprojekten für Visual Studio (C++) installieren lassen, wenn ich mich richtig erinnere, sollte auch dafür ein Beispiel vorhanden sein. Und in einem Microsoft-Dokument zu Windows 2000 aus dem MSDN wurde die neue API-Funktion beschrieben, so das man nach dieser Funktion alle Beispielprojekte durchsuchen lassen kann (wenn man einige GByte auf seiner Festplatte frei hat)
vBulletin® v3.8.1, Copyright ©2000-2010, Jelsoft Enterprises Ltd.