Fensterinhalt mit GDI+ vergrößert in anderem Fenster darstellen ?

  • Hallo zusammen.
    Der Titel könnte etwas unverständlich sein.
    Im Prinzip soll das Script den Inhalt eines Fensters per GDI+ speichern und vergrößert/verkleinert in einem anderen Fenster darstellen. Ich tue mich bei GDI+ allerdings noch etwas schwer, jedenfalls wird der Fensterinhalt nicht in meine GUI gezeichnet. Ich hänge mal meinen Code an, vielleicht hat ja jemand ne Idee. Ich gehe zumindest davon aus :D ;).

    Spoiler anzeigen


    #include <WindowsConstants.au3>
    #Include <GDIPlus.au3>

    dim $exe_path="notepad.exe",$exe_windowname="Unbenannt"

    consolewrite("waiting for application window"&@CRLF)
    if not WinExists($exe_windowname) then
    Run($exe_path)
    while not WinExists($exe_windowname)
    sleep(100)
    wend
    endif
    consolewrite("window found"&@CRLF)

    $hwnd=WinGetHandle($exe_windowname)
    $gui=GuiCreate("GDI+ Test Parent",320,240,0,0,$WS_SIZEBOX)
    GuiSetState(@SW_SHOW,$gui)

    $gui_size=WinGetPos($gui)
    $app_size=WinGetPos($hwnd)
    consolewrite("app size: "&$app_size[2]&"x"&$app_size[3]&@CRLF)

    consolewrite("gdi init..."&@CRLF)
    if not _GDIPlus_Startup() then consolewrite("couldn' init gdi"&@CRLF)

    $g_gui=_GDIPlus_GraphicsCreateFromHWND($gui)
    if $g_gui==0 then consolewrite("error 1"&@CRLF)

    $g_hwnd=_GDIPlus_GraphicsCreateFromHWND($hwnd)
    if $g_hwnd==0 then consolewrite("error 2"&@CRLF)

    $b_hwnd=_GDIPlus_BitmapCreateFromGraphics($app_size[2],$app_size[3],$g_hwnd)
    if $b_hwnd==0 then
    consolewrite("error 3"&@CRLF)
    else
    consolewrite("image size: "&_GDIPlus_ImageGetWidth($b_hwnd)&"x"&_GDIPlus_ImageGetHeight($b_hwnd)&@CRLF)
    endif

    if not _GDIPlus_GraphicsDrawImageRectRect($g_gui,$b_hwnd,$app_size[0],$app_size[1],$app_size[2],$app_size[3],0,0,$gui_size[2],$gui_size[3]) then consolewrite("error 4"&@CRLF)
    consolewrite("done."&@CRLF&"waiting 3 seconds until script termination..."&@CRLF)

    sleep(3000)

    ProcessClose(WinGetProcess($hwnd))
    consolewrite("clearing gdi+"&@CRLF)
    _WinAPI_DeleteObject($b_hwnd)
    _GDIPlus_GraphicsDispose($g_hwnd)
    _GDIPlus_GraphicsDispose($g_gui)
    _GDIPlus_Shutdown()
    consolewrite("exiting"&@CRLF)

    BTW: Räume ich eigentlich richtig auf am Ende des Codes ?

    EDIT: Code zu Spoiler geändert zwecks Übersichtlichkeit.

    Einmal editiert, zuletzt von Konrad (24. März 2010 um 09:19)

  • Hm. Da bin ich nicht drauf gekommen. Wie dämlich. Naja...habe jedenfalls deinen Code gefunden und angepasst ;).
    Kann der Code auch entsprechend geändert werden, daß er auch mit minimierten und/oder VERDECKTEN Fenstern funktioniert ?

    Spoiler anzeigen


    #include <GUIConstantsEx.au3>
    #include <WindowsConstants.au3>

    #Include <WinAPI.au3>
    #Include <Constants.au3>

    dim $msg,$exe_path="notepad.exe",$exe_windowname="Unbenannt",$refresh=100,$refresh_tmr=-1
    dim $x=-1,$y=-1,$w=320,$h=240

    global $gui,$hwnd,$exe_terminate=true,$dll[2]

    $dll[0] = DllOpen ( "user32.dll")
    $dll[1] = DllOpen ( "gdi32.dll")

    consolewrite("waiting for application window"&@CRLF)
    if not WinExists($exe_windowname) then
    Run($exe_path)
    while not WinExists($exe_windowname)
    sleep(100)
    wend
    endif
    consolewrite("window found"&@CRLF)

    $hwnd=WinGetHandle($exe_windowname)
    $gui=GuiCreate("ZoomApp",$w,$h,$x,$y,$WS_SIZEBOX)
    GuiSetState(@SW_SHOW,$gui)

    $refresh_tmr=TimerInit()
    while WinExists($hwnd)
    $msg=GuiGetMsg()
    if $msg==$GUI_EVENT_CLOSE then _Exit()
    if TimerDiff($refresh_tmr)>=$refresh then
    $state=WinGetState($gui)
    if BitAnd($state,2) then
    consolewrite("clone app in gui"&@CRLF)
    _Stretch()
    else
    consolewrite("gui is hidden. don't clone to save cpu power"&@CRLF)
    endif
    $refresh_tmr=TimerInit()
    endif
    sleep(10)
    wend


    ; ---------- FUNCTIONS -----------------------------------------------------------------------------------------------------------------------------------------

    Func _Exit()
    DLLClose($dll[0])
    DLLClose($dll[1])
    consolewrite("exit function called"&@CRLF)
    if WinExists($hwnd) and $exe_terminate==true then
    consolewrite("terminating application"&@CRLF)
    ProcessClose(WinGetProcess($hwnd))
    endif
    exit
    EndFunc

    Func _Stretch()
    ; get size of app and gui
    $gui_size=WinGetPos($gui)
    $app_size=WinGetPos($hwnd)

    $appHDC = DLLCall("user32.dll","int","GetDC","hwnd",$hwnd)
    $guiHDC = DLLCall("user32.dll","int","GetDC","hwnd",$gui)

    If Not @error Then
    DLLCall("gdi32.dll", "int", "StretchBlt", "int", $guiHDC[0], "int", _
    0, "int", 0, "int", $gui_size[2], "int", $gui_size[3], "int", $appHDC[0], "int", _
    0, "int", 0, "int", $app_size[2] ,"int", $app_size[3], _
    "long", $SRCCOPY)
    DLLCall("user32.dll","int","ReleaseDC","int",$appHDC[0],"hwnd",$hwnd)
    DLLCall("user32.dll","int","ReleaseDC","int",$guiHDC[0],"hwnd",$gui)
    return 1
    EndIf

    ; return 0 when an error occured
    return 0
    EndFunc

    EDIT: Code zu Spoiler geändert zwecks Übersichtlichkeit.

    Einmal editiert, zuletzt von Konrad (24. März 2010 um 09:20)

  • Meinst du so was:

    Spoiler anzeigen
    [autoit]


    ;fast hack by UEZ
    #include <GuiConstantsEx.au3>
    #include <GDIPlus.au3>
    #include <ScreenCapture.au3>

    [/autoit] [autoit][/autoit] [autoit]

    Opt('MustDeclareVars', 1)

    [/autoit] [autoit][/autoit] [autoit]

    _Main()

    [/autoit] [autoit][/autoit] [autoit]

    Func _Main()
    Local $hGUI1, $hGUI2, $hGUI3, $hImage, $hGraphic1, $hGraphic2, $hGraphic3, $sCLSID
    Local $bitmap1, $bitmap2, $bitmap3, $image1, $image2, $image3
    Local $tData, $tParams, $pParams, $pData

    [/autoit] [autoit][/autoit] [autoit]

    ; Capture top left corner of the screen
    _ScreenCapture_Capture (@MyDocumentsDir & "\GDIPlus_Image.jpg", 0, 0, 400, 300)

    [/autoit] [autoit][/autoit] [autoit]

    ; Create a GUI for the original image
    $hGUI1 = GUICreate("Original", 400, 300, 0, 0)
    GUISetState()

    [/autoit] [autoit][/autoit] [autoit]

    ; Create a GUI for the zoomed image
    $hGUI2 = GUICreate("Scaled Up", 800, 600, 0, 350)
    GUISetState()

    [/autoit] [autoit][/autoit] [autoit]

    ; Create a GUI for the scaled down image
    $hGUI3 = GUICreate("Scaled Down", 200, 150, 820, 400)
    GUISetState()

    [/autoit] [autoit][/autoit] [autoit]

    ; Initialize GDI+ library and load image
    _GDIPlus_Startup ()
    $hImage = _GDIPlus_ImageLoadFromFile (@MyDocumentsDir & "\GDIPlus_Image.jpg")

    [/autoit] [autoit][/autoit] [autoit]

    $sCLSID = _GDIPlus_EncodersGetCLSID ("JPG")

    [/autoit] [autoit][/autoit] [autoit]

    ; Draw original image
    $hGraphic1 = _GDIPlus_GraphicsCreateFromHWND ($hGUI1)
    $bitmap1 = _GDIPlus_BitmapCreateFromGraphics(400, 300, $hGraphic1)
    $image1 = _GDIPlus_ImageGetGraphicsContext($bitmap1)
    _GDIPlus_GraphicsDrawImageRect($image1, $hImage, 0, 0, 400, 300)
    _GDIPlus_GraphicsDrawImageRect($hGraphic1, $bitmap1, 0, 0, 400, 300)
    _GDIPlus_ImageSaveToFileEx($bitmap1, @ScriptDir & "\GDIPlus_Image1.jpg", $sCLSID)
    _WinAPI_DeleteObject($bitmap1)
    _GDIPlus_GraphicsDispose($image1)

    [/autoit] [autoit][/autoit] [autoit]

    ; Draw 2x scaled up image and save with lower jpg quality
    $hGraphic2 = _GDIPlus_GraphicsCreateFromHWND ($hGUI2)
    $bitmap2 = _GDIPlus_BitmapCreateFromGraphics(800, 600, $hGraphic2)
    $image2 = _GDIPlus_ImageGetGraphicsContext($bitmap2)
    _GDIPlus_GraphicsDrawImageRectRect ($image2, $hImage, 0, 0, 400, 300, 0, 0, 800, 600)
    _GDIPlus_GraphicsDrawImageRect($hGraphic2, $bitmap2, 0, 0, 800, 600)
    $tParams = _GDIPlus_ParamInit (1)
    $tData = DllStructCreate("int Quality")
    DllStructSetData($tData, "Quality", 10) ;quality 0-100
    $pData = DllStructGetPtr($tData)
    _GDIPlus_ParamAdd($tParams, $GDIP_EPGQUALITY, 1, $GDIP_EPTLONG, $pData)
    $pParams = DllStructGetPtr($tParams)
    _GDIPlus_ImageSaveToFileEx($bitmap2, @ScriptDir & "\GDIPlus_Image2.jpg", $sCLSID, $pParams)
    _WinAPI_DeleteObject($bitmap2)
    _GDIPlus_GraphicsDispose($image2)
    $tData = 0

    [/autoit] [autoit][/autoit] [autoit]

    ; Draw 2x scaled down image
    $hGraphic3 = _GDIPlus_GraphicsCreateFromHWND ($hGUI3)
    $bitmap3 = _GDIPlus_BitmapCreateFromGraphics(200, 150, $hGraphic3)
    $image3 = _GDIPlus_ImageGetGraphicsContext($bitmap3)
    _GDIPlus_GraphicsDrawImageRectRect ($image3, $hImage, 0, 0, 400, 300, 0, 0, 200, 150)
    _GDIPlus_GraphicsDrawImageRect($hGraphic3, $bitmap3, 0, 0, 200, 150)
    _GDIPlus_ImageSaveToFileEx($bitmap3, @ScriptDir & "\GDIPlus_Image3.jpg", $sCLSID)
    _WinAPI_DeleteObject($bitmap3)
    _GDIPlus_GraphicsDispose($image3)

    [/autoit] [autoit][/autoit] [autoit]

    ; Release resources
    _GDIPlus_GraphicsDispose ($hGraphic1)
    _GDIPlus_GraphicsDispose ($hGraphic2)
    _GDIPlus_GraphicsDispose ($hGraphic3)
    _GDIPlus_ImageDispose ($hImage)
    _GDIPlus_Shutdown ()

    [/autoit] [autoit][/autoit] [autoit]

    ; Clean up screen shot file
    FileDelete(@MyDocumentsDir & "\GDIPlus_Image.jpg")

    [/autoit] [autoit][/autoit] [autoit]

    ; Loop until user exits
    Do
    Until GUIGetMsg() = $GUI_EVENT_CLOSE

    [/autoit] [autoit][/autoit] [autoit]

    Exit

    [/autoit] [autoit][/autoit] [autoit]

    EndFunc ;==>_Main

    [/autoit]

    Gruß,
    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

  • Ne, leider nicht. Habe mich auch doof ausgedrückt.

    Mein Programm zeigt ja momentan alle 100ms ein aktualisiertes, vergrößertes Bild von Notepad in einer GUI an. Sobald man aber Notepad minimiert funktioniert das nicht mehr, der Bildinhalt ist einfach weiß. Der Code klappt in der Form also nicht mit versteckten Fenstern. Außerdem ist es glaube ich nicht so toll alle 100ms einen Screenshot zu speichern.

  • *g Nein, ist für kein Spiel ;). Soll ein größeres Projekt werden.

    Hintergrund: Die Software ist später für einen CarPC gedacht. Dafür gibt es diverse Interface-Software (z.B. RideRunner), in der man externe Applikationen einbetten kann, um sie nahtlos ins Interface einzufügen. Das Problem ist allerdings, dass sich manche Programme unter keinen Umständen skalieren wollen lassen, um in den Ausschnitt zu passen. Und selbst, wenn man es schafft das Fenster zu skalieren, so wird immer noch der Inhalt in einer festen Größe gezeichnet.
    Es gibt für einzelne Tools, die im Prinzip das machen, was ich erreichen will: Zu grossen/kleinen Fensterinhalt speichern und in einer skalierbaren GUI neu zeichnen. Das originale Fenster soll dann natürlich NICHT mehr sichtbar sein.

    Leider funktionieren diese Tools dann nur bei einem Programm und haben meistens einen eingeschränkten Funktionsumfang.

    Ich weiß zumindest von einem Programm, dass es mit DLL Injection arbeitet, was sicher der beste Weg ist. Aber das ist ja ein, ich sage mal...UNBELIEBTES Thema in Programmierforen, also versuche ich das Problem anders zu lösen ;).