FileInstall,i_view32.exe,i_view32.exe,0 FileInstall,s.gif,s.gif,0 FileInstall,DeskMan.ahk,DeskMan_v0.3.ahk,0 #SingleInstance ,Force ; configuration SetBatchLines ,-1 SetWinDelay ,0 CoordMode ,Mouse,Screen CoordMode ,ToolTip,Screen countps = 0 Main: ; this is only for reading, there is no "Main:" beeing called ;) Gosub, Configuration ; Read from configfile Gosub, GetTaskbarPos ; the taskbar Gosub, GetThumbSizes ; calc the thumbnail dims Gosub, GetWorkPos ; the area of "normal" windows Gosub, GetDockPos ; the deskman-dock Gosub, InitDockGui ; paint dock with picture placeholders Gosub, TRAYMENU ; init trayicon Gosub, WinBottom ; move deskman away (needed when inside taskbar ? Gosub, RefreshDock ; Get Fresh Thumbnails ;Gosub, DEBUG Return Configuration: file_iview = %A_ScriptDir%\i_view32.exe file_320mph = %A_ScriptDir%\..\320mph\320mph.ahk file_spacer = %A_ScriptDir%\s.gif FileCreateDir , %Temp%\DeskMan appTitle = DeskMan - Dock appName = DeskMan ; perhaps this can be read automatically ? PaperSizeMode = "Off" wincorrect_y = 1 repaintcounter =0 Gosub ,READINI Return ; define some Hot-Keys (win + arrow , or alt-gr + arrow (1 hand only!) <^>!Up:: #Up:: HalfUp: ResizeWin( work_x, work_y, work_w, ceil( work_h / 2 ) ) Return <^>!Down:: #Down:: HalfDown: ResizeWin( work_x, ceil( work_h / 2 ), work_w, ceil( work_h / 2) ) Return <^>!Left:: #Left:: HalfLeft: ResizeWin( work_x, work_y, ceil( work_w / 2), work_h ) Return <^>!Right:: #Right:: HalfRight: ResizeWin( work_x + ceil(work_w / 2) , work_y , ceil(work_w/2), work_h ) Return <^>!Enter:: #Enter:: MaximizeWindow: if PaperSizeMode <> "off" { ; fullscreen ResizeWin( 0 , 0 , A_ScreenWidth , A_ScreenHeight ) } else { ; without taskbar ResizeWin( work_x ,work_y , work_w, work_h ) } Return <^>!-:: TogglePaperSize: if PaperSizeMode = "off" { WinHide ahk_class Shell_TrayWnd WinHide ahk_id %deskman_id% WinHide,Program Manager SetTimer, RepaintDock , off Gosub, TogglePaperSizeOn SetTimer, RepaintDock , off } else if PaperSizeMode = "on" { WinHide ahk_class Shell_TrayWnd WinHide ahk_id %deskman_id% WinHide,Program Manager SetTimer, RepaintDock , off Gosub, TogglePaperSizeFull SetTimer, RepaintDock , off } else ;if PaperSizeMode = "full" { WinShow ahk_class Shell_TrayWnd WinShow ahk_id %deskman_id% WinHide,Program Manager SetTimer, RepaintDock , off Gosub, TogglePaperSizeOff forcerepaint = 1 Gosub, RepaintDock } Return PaperSize: ResizeWin( work_x + work_w / 8 ,work_y , work_w - work_w / 4, work_h ) Return <^>!#:: RunWait,%file_320mph% Return #1:: TileLast2Y:: Gosub, HalfUp Gosub, LastWindow Gosub, HalfDown Gosub, NextWindow forcerepaint=1 Return #2:: TileLast2X:: Gosub, HalfLeft Gosub, LastWindow Gosub, HalfRight Gosub, NextWindow forcerepaint=1 Return #3:: RestoreLast2:: Gosub, MaximizeWindow Gosub, LastWindow Gosub, MaximizeWindow Gosub, NextWindow forcerepaint=1 Return #4:: TogglePaperSizeOn: PaperSizeMode="on" WinGet, paperactive_id, ID, A WinSet, Style, -0xC00000, A WinGetActiveStats, title, w, h, x, y if ( w > minwidth ) Gosub, PaperSize SetTimer, RepaintDock , off ; loop until current_id is in front (max is all processes) WinGet, ids, list,,, Program Manager loop, %ids% { win_id :=ids%a_index% if ( win_id <> paperactive_id ) { if ( winIsDocked%win_id% = 1 ) { WinMinimize, ahk_id %win_id% winisminimized%win_id% = %win_id% } } } WinActivate, %paperactive_id% WinShow, %paperactive_id% ;SetTimer, RepaintDock , %repainttimer% Return #5:: TogglePaperSizeFull: PaperSizeMode="full" WinGet, paperactive_id, ID, A WinSet, Style, -0xC00000, A WinGetActiveStats, title, w, h, x, y if ( w > minwidth ) Gosub, MaximizeWindow SetTimer, RepaintDock , off ; loop until current_id is in front (max is all processes) WinGet, ids, list,,, Program Manager loop, %ids% { win_id :=ids%a_index% if ( win_id <> paperactive_id ) { if ( winIsDocked%win_id% = 1 ) { WinMinimize, ahk_id %win_id% winisminimized%win_id% = %win_id% } } } WinActivate, %paperactive_id% WinShow, %paperactive_id% ;SetTimer, RepaintDock , %repainttimer% Return #6:: TogglePaperSizeOff: PaperSizeMode="off" WinGet, paperactive_id, ID, A WinSet, Style, +0xC00000, A Gosub, WinBottom ; move window away SetTimer, RepaintDock , off ; loop until current_id is in front (max is all processes) WinGet, ids, list,,, Program Manager loop, %ids% { win_id :=ids%a_index% if ( win_id <> paperactive_id ) { if ( winisminimized%win_id% = win_id ) { WinRestore, ahk_id %win_id% Gosub, WinBottom ; move window away winisminimized%win_id% = } } } WinActivate, %paperactive_id% WinShow, %paperactive_id% WinGetActiveStats, title, w, h, x, y if ( w > minwidth ) Gosub, MaximizeWindow ;SetTimer, RepaintDock , %repainttimer% Return !F11:: Send, {F11} Gosub, MaximizeWindow Return <^>!PgUp:: #PgUp:: NextWindow: Send, !+{esc} Return <^>!PgDn:: #PgDn:: LastWindow: WinBottom: Send, !{esc} Return InitDockGui: ; add some picture-placeholder (dock-positions) y=0 x=0 Loop, %maxthumbs% { Gui, Add, Pic , gRestoreWin x%x% y%y% vPicB%a_index% ; add dock-slots to gui y+= 12 Gui, Add, Pic , gRestoreWin x%x% y%y% vPic%a_index% ; add dock-slots to gui if ( taskbar_pos = "left" or taskbar_pos ="right" ) y += %thumb_h% ; move pointer for next pos else x += %thumb_w% ; move pointer for next pos } Gui, -Caption ; window-style / chrome Gui, +ToolWindow Gui, +AlwaysOnTop +LastFound +Owner ; +Owner prevents a taskbar button from appearing. Gui, Show, x%dock_x% y%dock_y% w%dock_w% h%dock_h% , %appTitle% ; display window/Toolbar /* if ( forcedocktransparent = "1" ) { Gui, Color, 00CCCC Gui, +Lastfound ; Make the GUI window the last found window. WinSet, TransColor, 00CCCC ;forcedocktransparent=0 ; only needed once } */ WinGet, deskman_id, ID, %appTitle% ; fetch deskman_id for fast checks Gosub, DockToFront ;SetTimer, DockToFront, %repainttimer% Return Dock2TaskBar: ; --- DOES NOT WORK !!! --- or at least very buggy, when sizes are not exactly correct ! ; Active window to be docked to the taskbar, NEEDS hw_tray value hw_tray := DllCall( "FindWindowEx", "uint",0, "uint",0, "str","Shell_TrayWnd", "uint",0 ) WinActivate, ahk_id deskman_id Process Exist ; PID -> ErrorLevel WinGet hw_gui, ID, ahk_pid %ErrorLevel% DllCall( "SetParent", "uint", hw_gui, "uint", hw_tray ) Return GetTaskbarPos: ; get dimensions and position of taskbar (specialcase autohide ?) WinGetPos, taskbar_x, taskbar_y, taskbar_w, taskbar_h, ahk_class Shell_TrayWnd ; find out if its on top/left/bottom/right with its x,y ; x0,y0 ( w < h ) means its on top if ( taskbar_x < 10 and taskbar_w < taskbar_h ) taskbar_pos = left ; x0,y0 ( w >= h ) means its on left if ( taskbar_x < 10 and taskbar_w >= taskbar_h ) taskbar_pos = top ; x+,y0 means its on right if ( taskbar_x > 10 ) taskbar_pos = right ; x0,y+ means its on bottom if ( taskbar_y > 10 ) taskbar_pos = bottom Return GetThumbSizes: ; calculate size of a thumbnail thumb_w := ceil( A_ScreenWidth / maxthumbs ) ; width of dock (also thumbnail-width) thumb_h := ceil( A_ScreenHeight / maxthumbs ) ; height of thumbnails Return GetWorkPos: ; default without taskbar if ( insidetaskbar = "1" ) { dock2_w = 0 dock2_h = 0 } else { dock2_w := thumb_w dock2_h := thumb_h } if taskbar_pos = left { work_x := dock2_w + taskbar_w + work_border work_y := work_border - 1 work_w := A_ScreenWidth - taskbar_w - dock2_w -work_border -work_border work_h := A_ScreenHeight - work_border +1 } if taskbar_pos = top { work_x := work_border work_y := dock2_h + taskbar_h + dock_border + work_border - 1 work_w := A_ScreenWidth - work_border -work_border work_h := A_ScreenHeight - taskbar_h - dock_h -work_border -workborder +1 } if taskbar_pos = bottom { work_x := work_border work_y := work_border -1 work_w := A_ScreenWidth -work_border -work_border work_h := A_ScreenHeight - taskbar_h - dock2_h -work_border -work_border +1 } if taskbar_pos = right { work_x := work_border work_y := work_border -1 work_w := A_ScreenWidth - taskbar_w - dock2_w -work_border -work_border work_h := A_ScreenHeight - work_border -work_border +1 } ; irfanview needs integer and not float so lets precalc it here and dont mess with casting later work_h_half := ceil( work_h / 2 ) work_w_half := ceil( work_w / 2 ) ; windows smaller than half get part-shot and not full window minwidth := work_w_half Return GetDockPos: if ( insidetaskbar = 1 ) { if taskbar_pos = right { dock_x := work_x + work_w + work_border + dock_border + 2 dock_y := insidetaskbar_y0 dock_w := thumb_w dock_h := A_ScreenHeight - insidetaskbar_y0 - insidetaskbar_yf } if taskbar_pos = left { dock_x := taskbar_w - dock_border dock_y := insidetaskbar_y0 dock_w := thumb_w dock_h := A_ScreenHeight - insidetaskbar_y0 - insidetaskbar_yf } if taskbar_pos = top { dock_x := insidetaskbar_x0 dock_y := taskbar_h - dock_border dock_w := A_ScreenWidth - insidetaskbar_x0 - insidetaskbar_xf dock_h := thumb_h } if taskbar_pos = bottom { dock_x := insidetaskbar_x0 dock_y := work_y + work_h +work_border + dock_border dock_w := A_ScreenWidth - insidetaskbar_x0 - insidetaskbar_xf dock_h := thumb_h } } else { if taskbar_pos = right { dock_x := work_x + work_w + work_border + dock_border + 2 dock_y := 0 dock_w := thumb_w dock_h := A_ScreenHeight } if taskbar_pos = left { dock_x := taskbar_w - dock_border dock_y := 0 dock_w := thumb_w dock_h := A_ScreenHeight } if taskbar_pos = top { dock_x := 0 dock_y := taskbar_h - dock_border dock_w := A_ScreenWidth dock_h := thumb_h } if taskbar_pos = bottom { dock_x := 0 dock_y := work_y + work_h + work_border + dock_border dock_w := A_ScreenWidth dock_h := thumb_h } } Return ResizeWin( XPos, YPos, XSize, YSize ) { WinGet, active_id, ID, A ; fetch active foreground-window if ( active_id = deskman_id ) return ; correct some pixels in positioning to look "just right" ;YPos := YPos - wincorrect_y ;YSize := YSize + wincorrect_y WinMove, ahk_id %active_id%, , %XPos% , %YPos% , %XSize% , %YSize% ; invalidate window so it gets refreshed next time WinIsDocked%active_id% = ;Gosub, DockToFront } DockToFront: ; force DeskMan to Front Gui, +AlwaysOnTop +LastFound +Owner ; +Owner prevents a taskbar button from appearing. Return f9:: RefreshDockMax: maximizeall = 1 Gosub, RefreshDock Return f12:: RefreshDock: Gosub, DockToFront SetTimer, RepaintDock , Off ; clear old timers ; remove thumbnails FileDelete, %Temp%\DeskMan\thumb_*.bmp ; keep active window! WinGet, current_id, ID, A ; start with active Gosub, CaptureThumbActive winIsDocked%capture_id% = 1 capture_id =x ; clear ; loop until current_id is in front (max is all processes) WinGet, ids, list,,, Program Manager loop, %ids% { if ( capture_id <> current_id ) { Gosub, WinBottom if maximizeall = 1 { WinGetActiveStats, title, w, h, x, y if ( w > minwidth ) ResizeWin( work_x ,work_y , work_w, work_h ) } Gosub, CaptureThumbActive winIsDocked%capture_id% = 1 } } forcerepaint = 1 maximizeall = 0 Gosub, RepaintDock return RepaintDock: ; remove closed thumbs but dont do much (as this is done in a loop!) SetTimer, RepaintDock , off ; clear old timers if ( forcedocktofront = "1" ) { Gosub, DockToFront } ; try to add foreground-window to dock if not in there ( changes are good we hit it shortly after start-new) WinGet, active_id, ID, A WinGetTitle, title, ahk_id %active_id% ;tooltip, %repaintcounter% if repaintcounter > 10 { forcerepaint = 1 winIsDocked%active_id% = } ; detect and add new windows if ( winIsDocked%active_id% = "" or winIsDockedTitle%active_id% <> title) { winIsDockedTitle%active_id% := title ; store title and repaint if this changes Gosub, CaptureThumbActive winIsDocked%capture_id% = 1 GuiControl,1:,Pic1, *w%thumb_w% *h%thumb_h% %Temp%\DeskMan\thumb_%capture_id%.bmp } ; test if display has changed ! dockedNewCount = 0 ; start with empty dock Loop, %maxthumbs% { dockIdNew%a_index% = ;clear } ; stack minimized windows into dock ;this way all "non-dead" minimized windows get stacked into dock WinGet, ids, list,,, Program Manager Loop, %ids% { StringTrimRight, id, ids%a_index%, 0 ; find the id of this window if winIsDocked%id% ; is window with this id in dock already ? { dockedNewCount += 1 ; how many slots are used already ? dockIdNew%dockedNewCount% = %id% ; remeber id for this position } } ; fill with file_spacer if empty loop, %maxthumbs% { val1 := DockId%a_index% val2 := DockIdNew%a_index% if ( val1 <> val2 ) { forcerepaint = 1 Gosub, DockToFront } } if forcerepaint <> { dockedCount = 0 ; start with empty dock Loop, %maxthumbs% { dockId%a_index% = ;clear } ; stack minimized windows into dock ;this way all "non-dead" minimized windows get stacked into dock WinGet, ids, list,,, Program Manager Loop, %ids% { StringTrimRight, id, ids%a_index%, 0 ; find the id of this window if winIsDocked%id% ; is window with this id in dock already ? { dockedCount += 1 ; how many slots are used already ? dockId%dockedCount% = %id% ; remeber id for this position GuiControl,1:,Pic%dockedCount% , *w%thumb_w% *h%thumb_h% %Temp%\DeskMan\thumb_%id%.bmp GuiControl,1:,PicB%dockedCount%, *w100 *h12 %Temp%\DeskMan\thumbB_%id%.bmp } } ; fill with file_spacer if empty loop, %maxthumbs% { if DockId%a_index% = { GuiControl,1:,Pic%a_index%, *w%thumb_w% *h%thumb_h% %file_spacer% } } repaintcounter =0 Gosub, TryResizeDock Gosub, DockToFront } ; end forcerepaint forcerepaint = ; try not to draw in next round (but its multithreaded!) somebody can click restore while repaint, if ( forceautorefresh = "1") { repaintcounter := repaintcounter +1 } SetTimer, RepaintDock , %repainttimer% Return TryResizeDock: if ( forcedocktransparent = "1") { newheight := dockedNewCount * ( thumb_h + 12 ) if ( newheight > dock_h ) newheight := dock_h newwidth := dockedNewCount * thumb_w if ( newwidth > dock_w ) newwidth := dock_w if ( taskbar_pos ="left" or taskbar_pos="right" ) WinMove , ahk_id %deskman_id% ,, %dock_x%, %dock_y%, %dock_w% , %newheight% else WinMove , ahk_id %deskman_id% ,, %dock_x%, %dock_y%, %newwidth% , %dock_h% } Return CaptureThumbActive: WinGet , captureactive_id, ID, A winGetTitle, title , ahk_id %captureactive_id% WinGetClass, class , ahk_id %captureactive_id% ;get Class-name capture_id = if ( title = "" or captureactive_id = deskman_id ) ; skip DeskMan Window (recursion!) return ; skip some programs not good with deskman if class in TPickSessionDlg,TForm,TFormMain,TBaseLoadErrorDlg,Shell_TrayWnd,DV2ControlHost,ZORRO,Progman,tooltips_class32,AutoHotkeyGUI,TForm4,AutoHotkeyGUI return Gosub, CaptureThumb return CaptureThumb: capture_id := captureactive_id wingetpos, x, y, width, height, ahk_id %capture_id% ; read width from capture-window if ( width < minwidth ) { ; get picture cropped so we see more detail RunWait,%file_iview% /silent /capture=1 /crop=(0`,0`,%work_w_half%`,%work_h_half%) /resample=(%thumb_w%`,%thumb_h%) /convert=%Temp%\DeskMan\thumb_%capture_id%.bmp } else { ; get thumb of active window RunWait,%file_iview% /silent /jpgq=100 /capture=1 /resample=(%thumb_w%`,%thumb_h%) /convert=%Temp%\DeskMan\thumb_%capture_id%.bmp } ; always capture icon and title RunWait,%file_iview% /silent /capture=1 /crop=(0`,0`,200`,24) /resample=(100`,12) /convert=%Temp%\DeskMan\thumbB_%capture_id%.bmp return RestoreWin: StringReplace, pos , A_GuiControl, Pic SetTimer, RepaintDock , off Gosub, WinBottom ; undo the click on deskman ; find active window, which is on top of stack, DeskMan is active because of click ; get some lookups forcerepaint = 1 dockIdpos := dockId%pos% id := dockId%pos% if ( winIsDocked%id% <> "" ) { ; activate restored id WinActivate, ahk_id %id% WinGetTitle, title, ahk_id %id% wingetpos, x, y, width, height, ahk_id %id% ; only maximize and move big windows, as small ones eg. dialogboxes dont like maximize if ( width > minwidth ) { ResizeWin( %work_x%, %work_y%, %work_w%, %work_h% ) } winIsDocked%id% = ; force repaint in next interval } Gosub, RepaintDock Return ^f8:: ReloadScript: Reload ; Sleep 200 ; If successful, the reload will close this instance during the Sleep, so the line below will never be reached. MsgBox, 4,, The script could not be reloaded. Would you like to open it for editing? IfMsgBox, Yes, Edit Return DEBUG: ;tooltip, %dock_x% %dock_y% %dock_w% %dock_h% ;tooltip, %maxthumbs% %thumb_w% %thumb_h% ;tooltip, %taskbar_x% %taskbar_y% %taskbar_w% %taskbar_h% %taskbar_pos% tooltip, %work_x% %work_y% %work_w% %work_h% Return TRAYMENU: ;Menu,Tray,NoStandard ;Menu,Tray,DeleteAll Menu,Tray,Add,&Settings,SETTINGS Menu,Tray,Add,DeskMan,ABOUT Menu,Tray,Add Menu,Tray,Add,&About,ABOUT Menu,Tray,Add,E&xit,EXIT Menu,Tray,Default,DeskMan Return ABOUT: about= (LTrim DeskMan `nControl all your Windows, similar to Apple-Dock but different ;) `n`nThis program uses IrFanView by Irfan Skiljan. `nHolomind @2006 (based on) MultiMonMan Skrommel @2006 www.donationcoders.com/skrommel ) MsgBox,0,DeskMan,%about% Return SETTINGS: Gosub,READINI RunWait,%appName%.ini Gosub,READINI Return READINI: IfNotExist,%appName%.ini { ini= (LTrim `;[Settings] `;maxthumbs = 14 ; how many thumbs to show ( screenheight / maxthumbs = thumbheight )? `;work_border = 4 ; looks nicer `;dock_border = 0 ; make a gap between dock and your window. `;repainttimer = 1000 ; msecs `;forcedocktofront=0 ; force at every repaint desman to always on top `;forcedocktransparent=0 ; force at every repaint desman to always on top `;insidetaskbar = 0 ; `;insidetaskbar_x0 = 70 ; when needed move this much (eg. startbutton) `;insidetaskbar_y0 = 30 ; when needed move that much (eg. startbutton) `;insidetaskbar_xf = 200 ; when needed keep free on right (eg. trayicons+clock) `;insidetaskbar_yf = 200 ; when needed keep free on bottom (eg. trayicons+clock) [Settings] maxthumbs=14 work_border=4 dock_border=0 repainttimer=1000 forcedocktofront=0 forcedocktransparent=0 insidetaskbar=0 insidetaskbar_x0=70 insidetaskbar_y0=30 insidetaskbar_xf=200 insidetaskbar_yf=200 ) FileAppend,%ini%,%appName%.ini ini= } IniRead,forcedocktofront ,%appName%.ini,Settings,forcedocktofront IniRead,forcedocktransparent ,%appName%.ini,Settings,forcedocktransparent IniRead,maxthumbs ,%appName%.ini,Settings,maxthumbs IniRead,work_border ,%appName%.ini,Settings,work_border IniRead,dock_border ,%appName%.ini,Settings,dock_border IniRead,repainttimer ,%appName%.ini,Settings,repainttimer IniRead,insidetaskbar ,%appName%.ini,Settings,insidetaskbar IniRead,insidetaskbar_x0 ,%appName%.ini,Settings,insidetaskbar_x0 IniRead,insidetaskbar_y0 ,%appName%.ini,Settings,insidetaskbar_y0 IniRead,insidetaskbar_xf ,%appName%.ini,Settings,insidetaskbar_xf IniRead,insidetaskbar_yf ,%appName%.ini,Settings,insidetaskbar_yf Return ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; /* BinReadWrite.ahk Routines to read and write binary data from/to files. Based on original functions written by Laszlo http://www.autohotkey.com/forum/viewtopic.php?t=4604 TODO: Perhaps set a lastError variable to explicit the errors. // by Philippe Lhoste http://Phi.Lho.free.fr // File/Project history: 1.03.000 -- 2006/02/15 (PL) -- Moved Bin2Hex & Hex2Bin to DllCallStruct, apply code rules. 1.02.000 -- 2006/01/24 (PL) -- Slight change of the API: all functions return -1 if error. Integrated Laszlo suggestions on improving Bin2Hex and Hex2Bin. 1.01.000 -- 2006/01/23 (PL) -- Declaration of the local variables, to get access to global WinAPI constants, and for consistency. 1.00.000 -- 2006/01/19 (PL) -- Rewrote the functions to separate opening and closing, allowing efficient multiple operations. */ ; WinAPI constants INVALID_HANDLE_VALUE = -1 INVALID_FILE_SIZE = 0xFFFFFFFF FILE_BEGIN = 0 FILE_CURRENT = 1 FILE_END = 2 /* // Open the file for reading. // Return the file handle to provide in further read operations and in the final close operation, // or INVALID_HANDLE_VALUE if an error was found. */ OpenFileForRead(_filename) { local handle handle := DllCall("CreateFile" , "Str", _filename ; lpFileName , "UInt", 0x80000000 ; dwDesiredAccess (GENERIC_READ) , "UInt", 3 ; dwShareMode (FILE_SHARE_READ|FILE_SHARE_WRITE) , "UInt", 0 ; lpSecurityAttributes , "UInt", 3 ; dwCreationDisposition (OPEN_EXISTING) , "UInt", 0 ; dwFlagsAndAttributes , "UInt", 0) ; hTemplateFile If (handle = INVALID_HANDLE_VALUE or handle = 0) { ErrorLevel = -1 } IfNotEqual ErrorLevel, 0, Return INVALID_HANDLE_VALUE ; Couldn't open the file Return handle } /* // Open the file for writing. // Return the file handle to provide in further write operations and in the final close operation, // or INVALID_HANDLE_VALUE if an error was found. */ OpenFileForWrite(_filename) { local handle handle := DllCall("CreateFile" , "Str", _filename ; lpFileName , "UInt", 0x40000000 ; dwDesiredAccess (GENERIC_WRITE) , "UInt", 3 ; dwShareMode (FILE_SHARE_READ|FILE_SHARE_WRITE) , "UInt", 0 ; lpSecurityAttributes , "UInt", 4 ; dwCreationDisposition (OPEN_ALWAYS: create if not exists) , "UInt", 0 ; dwFlagsAndAttributes , "UInt", 0) ; hTemplateFile If (handle = INVALID_HANDLE_VALUE or handle = 0) { ErrorLevel = -1 } IfNotEqual ErrorLevel, 0, Return INVALID_HANDLE_VALUE ; Couldn't open the file Return handle } /* // Close the file. */ CloseFile(_handle) { local result result := DllCall("CloseHandle" , "UInt", _handle) If (result = 0) { ErrorLevel = -1 } } /* // Get the size of the opened file, in bytes. // Limited to 4GB, so it is more limited that AHK's FileGetSize. // It is here for consistency, and because it accepts a file handle instead of a path. // // Return the size in bytes, -1 if there was an error. */ GetFileSize(_handle) { local fileSize fileSize := DllCall("GetFileSize" , "UInt", _handle , "UInt", 0) If (fileSize = INVALID_FILE_SIZE) { ErrorLevel = -1 } IfNotEqual ErrorLevel, 0, Return -1 Return fileSize } /* // Move the file pointer in the file to the given offset relative to moveMethod. // // moveMethod can be FILE_BEGIN, FILE_CURRENT or FILE_END. // If moveMethod is -1, nothing is done (default, for operations at current position). // To get the current position, call this function with just FILE_CURRENT (null offset). // offset can be positive (toward end of the file) or negative (toward start of the file). // // Return -1 if there was an error, the new file pointer position if OK. // Note: Currently it doesn't work for files larger than 2GB... */ MoveInFile(_handle, _moveMethod=-1, _offset=0) { local result result = %INVALID_FILE_SIZE% if (_moveMethod != -1) { result := DllCall("SetFilePointer" , "UInt", _handle ; hFile , "Int", _offset ; lDistanceToMove , "UInt", 0 ; lpDistanceToMoveHigh , "UInt", _moveMethod) ; dwMoveMethod if (result = -1) ; INVALID_SET_FILE_POINTER { ErrorLevel = -1 } IfNotEqual ErrorLevel, 0, Return -1 ; Couldn't make the move } Return result } /* // Write in a file opened for writing. // // Move to position given by moveMethod and offset // (by default stand at current position) and // write byteNb bytes from data (all data if byteNb = 0; // data contains binary bytes that can be a string or // raw bytes generated from hexa data with the Hex2Bin routine). // // moveMethod, defaulting to -1 (no move, write at current position), // can also be FILE_BEGIN, FILE_CURRENT or FILE_END. // offset can be positive (toward end of file) or negative (toward beginning of file). // // Return the number of bytes written (-1 if there was an error). */ WriteInFile(_handle, ByRef @data, _byteNb=0, _moveMethod=-1, _offset=0) { local dataSize, result, written _offset := MoveInFile(_handle, _moveMethod, _offset) IfNotEqual ErrorLevel, 0, Return -1 ; Couldn't make the move dataSize := VarSetCapacity(@data) ; Get the capacity (>= used length!) If (_byteNb < 1 or _byteNb > dataSize) { byteNb := dataSize } result := DllCall("WriteFile" , "UInt", _handle ; hFile , "Str", @data ; lpBuffer , "UInt", _byteNb ; nNumberOfBytesToWrite , "UInt *", written ; lpNumberOfBytesWritten , "UInt", 0) ; lpOverlapped if (result = 0 or written < _byteNb) { ErrorLevel = -2 } IfNotEqual ErrorLevel, 0, Return -1 ; Couldn't write in the file Return written } /* // Read from a file opened for reading. // // Move to position given by moveMethod and offset // (by default stand at current position) and // read byteNb bytes in data (the whole file if byteNb = 0; // data contains binary bytes that can be a string or // raw bytes that can be converted to hex digits with the Bin2Hex routine). // // moveMethod, defaulting to -1 (no move, read at current position), // can also be FILE_BEGIN, FILE_CURRENT or FILE_END. // offset can be positive (toward end of file) or negative (toward beginning of file). // // Return the number of bytes read (-1 if there was an error), which can be less // than requested if end-of-file is meet. */ ReadFromFile(_handle, ByRef @data, _byteNb=0, _moveMethod=-1, _offset=0) { local fileSize, granted, result, read _offset := MoveInFile(_handle, _moveMethod, _offset) IfNotEqual ErrorLevel, 0, Return -1 ; Couldn't make the move if (_byteNb = 0) { ; Read whole file (or less if file pointer isn't at start) fileSize := GetFileSize(_handle) IfNotEqual ErrorLevel, 0, Return -1 ; Couldn't get the file size _byteNb := fileSize } granted := VarSetCapacity(@data, _byteNb, 0) if (granted < _byteNb) { ; Cannot allocate enough memory ErrorLevel = Mem=%granted% Return -1 } result := DllCall("ReadFile" , "UInt", _handle ; hFile , "Str", @data ; lpBuffer , "UInt", _byteNb ; nNumberOfBytesToRead , "UInt *", read ; lpNumberOfBytesRead , "UInt", 0) ; lpOverlapped if (result = 0) { ErrorLevel = -2 } ;~ MsgBox fileSize: %fileSize% - offset: %_offset% - byteNb: %_byteNb% - granted: %granted% - read: %read% IfNotEqual ErrorLevel, 0, Return -1 ; Couldn't read the file ; Note that we can have read less data than requested, ; eg. if end of file has been meet Return read } /* // Convert raw bytes stored in a variable to a string of hexa digit pairs. // Convert either byteNb bytes or, if null, the whole content of the variable. // // Return the number of converted bytes, or -1 if error (memory allocation) */ Bin2Hex(ByRef @hex, ByRef @bin, _byteNb=0) { local intFormat, dataSize, dataAddress, granted, x ; Save original integer format intFormat = %A_FormatInteger% ; For converting bytes to hex SetFormat Integer, Hex ; Get size of data dataSize := VarSetCapacity(@bin) If (_byteNb < 1 or _byteNb > dataSize) { _byteNb := dataSize } dataAddress := &@bin ; Make enough room (faster) granted := VarSetCapacity(@hex, _byteNb * 2) if (granted < _byteNb * 2) { ; Cannot allocate enough memory ErrorLevel = Mem=%granted% Return -1 } Loop %_byteNb% { ; Get byte in hexa x := *dataAddress + 0x100 StringRight x, x, 2 ; 2 hex digits StringUpper x, x @hex = %@hex%%x% dataAddress++ ; Next byte } ; Restore original integer format SetFormat Integer, %intFormat% Return _byteNb } /* // Convert a string of hexa digit pairs to raw bytes stored in a variable. // Convert either byteNb bytes or, if null, the whole content of the variable. // // Return the number of converted bytes, or -1 if error (memory allocation) */ Hex2Bin(ByRef @bin, _hex, _byteNb=0) { local dataSize, granted, dataAddress, x ; Get size of data x := StrLen(_hex) dataSize := Ceil(x / 2) if (x = 0 or dataSize * 2 != x) { ; Invalid string, empty or odd number of digits ErrorLevel = Param Return -1 } If (_byteNb < 1 or _byteNb > dataSize) { _byteNb := dataSize } ; Make enough room granted := VarSetCapacity(@bin, _byteNb, 0) if (granted < _byteNb) { ; Cannot allocate enough memory ErrorLevel = Mem=%granted% Return -1 } dataAddress := &@bin Loop Parse, _hex { if (A_Index & 1) ; Odd { x = %A_LoopField% ; Odd digit } else { ; Concatenate previous x and even digit, converted to hex x := "0x" . x . A_LoopField ; Store integer in memory DllCall("RtlFillMemory" , "UInt", dataAddress , "UInt", 1 , "UChar", x) dataAddress++ } } Return _byteNb } ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; GuiClose: EXIT: ExitApp