AHKv2: Diálogos para seleccionar Icono, Fuente, Color y Más! [27/04/2018]

Esta sección es para compartir scripts, librerías y herramientas.

Moderator: Flipeador

User avatar
Flipeador
Posts: 1204
Joined: 15 Nov 2014, 21:31
Location: Argentina
Contact:

AHKv2: Diálogos para seleccionar Icono, Fuente, Color y Más! [27/04/2018]

28 Nov 2015, 05:46

Notas:
  • En todos los diálogos se incluye un pequeño ejemplo.
  • Estaré actualizando las funciones y agregando nuevas...
Requisitos:
  • Algunas funciones requieren la clase ImageButton.
  • Todas las funciones requieren la versión 2 de AutoHotkey.




Muestra un diálogo para pedirle al usuario que seleccione un icono
Image

Code: Select all

/*
Muestra un diálogo para pedirle al usuario que seleccione un icono.
Parámetros:
    Owner: El identificador de la ventana propietaria de este diálogo. Este valor puede ser cero.
    FileName: La ruta a un archivo que contenga iconos.
    Icon: El índice del icono en el archivo. El valor por defecto es 1.
Return: Si tuvo éxito devuelve un objeto con las claves FileName e Icon, caso contrario devuelve 0.
*/
ChooseIcon(Owner := 0, FileName := "", Icon := 1)
{
    VarSetCapacity(PATH, 32767 * 2, 0)
    StrPut(FileName, &PATH, StrLen(FileName) + 1, "UTF-16")

    If (DllCall("Shell32.dll\PickIconDlg", "Ptr", Owner, "Ptr", &PATH, "UInt", 32767, "IntP", --Icon))
    {
        OutputVar       := {}
        If (!InStr(OutputVar.FileName := StrGet(&PATH, "UTF-16"), ":"))
            OutputVar.FileName := StrReplace(OutputVar.FileName, "`%SystemRoot`%", A_WinDir,, 1)
        OutputVar.Icon  := Icon + 1
    }

    Return (IsObject(OutputVar) ? OutputVar : FALSE)
}





Muestra un diálogo para pedirle al usuario que seleccione una imágen o un icono
Image

Code: Select all

#Include ..\Gdi\ImageButton.ahk

/*
Muestra un diálogo para pedirle al usuario que seleccione una imágen o un icono.
Parámetros:
    Owner: El identificador de la ventana propietaria de este diálogo. Este valor puede ser cero.
    FileName: La ruta a una imágen o a un archivo que contenga iconos. Si el archivo no existe, se establece en shell32.dll.
    Icon: El índice del icono en el archivo. El valor por defecto es 1.
    Width: El ancho por defecto. Si este valor es una cadena vacía se deshabilita.
    Height: El alto por defecto. Si este valor es una cadena vacía se deshabilita.
    Quality: La calidad por defecto. Si este valor es una cadena vacía se deshabilita.
Return: Si tuvo éxito devuelve un objeto con las claves FileName, Icon, Widh, Height y Quality, caso contrario devuelve 0.
*/
ChooseImage(Owner := 0, FileName := "", Icon := 1, Width := "", Height := "", Quality := "") ;WIN_V+
{
    If (!FileExist(FileName) || DirExist(FileName)) ;Check if FileName is a valid File
        FileName := A_WinDir . "\System32\shell32.dll" ;If not, set to shell32.dll

    Title           := "Seleccionar imágen" ;Dlg Window Title
    ButtonStyle     := [[0, 0x7E8DB6, "Black", 0x242424, 2, 0x282828, 0x242424, 1], [5, 0x8392B8, 0x98A5C5, 0x242424, 2, 0x282828, 0x242424, 1], [5, 0x8392B8, 0xA9B5CF, 0x242424, 2, 0x282828, 0x242424, 1], [0, 0xCCCCCC, "Black", 0x4A4A4A, 2, 0x282828, 0xA7B7C9, 1], [0, 0x7E8DB6, "Black", 0x242424, 2, 0x282828, 0x404040, 2], [5, 0x8392B8, 0x98A5C5, 0x242424, 2, 0x282828, 0x242424, 1]]

    ;Create GUI
    g               := GuiCreate("-ToolWindow" . (Owner ? " +Owner" . Owner : ""), Title)
    g.BackColor     := 0x282828 ;Background color: Dark

    g.SetFont("s9 Italic q5", "Arial Black")
    oFind           := g.AddButton("x337 y4 w58 h25", "• • •") ;Find Button
        ImageButton.Create(oFind.hWnd, ButtonStyle*)

    g.SetFont("s11", "Tahoma")
    oCancel         := g.AddButton("x296 y357 w99 h29", "Cancelar")
        ImageButton.Create(oCancel.hWnd, ButtonStyle*)
    oAccept         := g.AddButton("x177 y357 w99 h29 Default", "Aceptar")
        ImageButton.Create(oAccept.hWnd, ButtonStyle*)

    g.SetFont("s8", "Segoe UI")
    oLoad           := g.AddText("x5 y356 w165 h16 cGray")
    oInfo           := g.AddText("x5 y373 w165 h16 cGray")

    g.SetFont("Normal q5 s11")
    oFile           := g.AddEdit("x5 y4 w330 h25 c0x8694B9 BackGround0x282828 -E0x200 Border ReadOnly", A_Space . FileName)

    oList           := g.AddListView("x5 y32 w391 h253 BackGround0x282828 Icon +0x00880C LV0x010840", "")
        DllCall("User32.dll\SendMessageW", "Ptr", oList.hWnd, "UInt", 0x1035, "Ptr", 0, "Int", (34 & 0xFFFF) | (22 << 16)) ;X, Y

    g.AddText("x5 y288 w391 h64 c0x8694B9 BackGroundTrans Border")

    g.AddText("x10 y294 w56 h23 c0x8694B9 BackGroundTrans", "Ancho:")
    oWidth          := g.AddEdit("x77 y294 w63 h22 cGray BackGround0x282828 -E0x200 Border ReadOnly", A_Space . Width)
    oWidthU         := g.AddButton("x142 y294 w20 h11" . (Width==""?" Disabled":""), "˄")        , ImageButton.Create(oWidthU.hWnd, ButtonStyle*)
    oWidthD         := g.AddButton("x142 y305 w20 h11" . (Width==""?" Disabled":""), "˅")        , ImageButton.Create(oWidthD.hWnd, ButtonStyle*)

    g.AddText("x10 y323 w56 h23 c0x8694B9 BackGroundTrans", "Alto:")
    oHeight         := g.AddEdit("x77 y323 w63 h22 cGray BackGround0x282828 -E0x200 Border ReadOnly", A_Space . Height)
    oHeightU        := g.AddButton("x142 y323 w20 h11" . (Height==""?" Disabled":""), "˄")        , ImageButton.Create(oHeightU.hWnd, ButtonStyle*)
    oHeightD        := g.AddButton("x142 y334 w20 h11" . (Height==""?" Disabled":""), "˅")        , ImageButton.Create(oHeightD.hWnd, ButtonStyle*)

    g.AddText("x230 y294 w56 h23 c0x8694B9 BackGroundTrans", "Calidad:")
    oQuality        := g.AddEdit("x306 y294 w63 h22 cGray BackGround0x282828 -E0x200 Border ReadOnly", A_Space . Quality)
    oQualityU       := g.AddButton("x371 y294 w20 h11" . (Quality==""?" Disabled":""), "˄")        , ImageButton.Create(oQualityU.hWnd, ButtonStyle*)
    oQualityD       := g.AddButton("x371 y305 w20 h11" . (Quality==""?" Disabled":""), "˅")        , ImageButton.Create(oQualityD.hWnd, ButtonStyle*)

    ;Some initiation data
    oTBar           := ComObjCreate("{56FDF344-FD6D-11d0-958A-006097C9A090}", "{EA1AFB91-9E28-4B86-90E9-9E9F8A5EEFAF}")
    hTBar           := Owner ? Owner : g.hWnd

    Data            := {oList: oList, oInfo: oInfo, oLoad: oLoad, oTBar: oTBar, Title: Title, g:g, oFile: oFile, oWidth: oWidth, oHeight: oHeight, oQuality: oQuality
                        , hTBar: hTBar, hIcon: 0
                        , Error: TRUE, FileName: FileName, Icon: Icon, Width: Width, Height: Height, Quality: Quality}

    ;Show and load
    g.Show("w399 h392")
    ChooseImage_Load(Data)

    ;Events
    oWidthU.OnEvent("Click", Func("ChooseImage_UpDown").Bind(Data, "Width", "Up", -1, SysGet(78))) ;Data, What?, Up or down?, Min, Max
    oWidthD.OnEvent("Click", Func("ChooseImage_UpDown").Bind(Data, "Width", "Down", -1, SysGet(78)))

    oHeightU.OnEvent("Click", Func("ChooseImage_UpDown").Bind(Data, "Height", "Up", -1, SysGet(79)))
    oHeightD.OnEvent("Click", Func("ChooseImage_UpDown").Bind(Data, "Height", "Down", -1, SysGet(79)))

    oQualityU.OnEvent("Click", Func("ChooseImage_UpDown").Bind(Data, "Quality", "Up", 1, 100))
    oQualityD.OnEvent("Click", Func("ChooseImage_UpDown").Bind(Data, "Quality", "Down", 1, 100))
    
    oFind.OnEvent("Click", Func("ChooseImage_Find").Bind(Data))
    oList.OnEvent("ItemSelect", Func("ChooseImage_ItemSelect").Bind(Data))
    oCancel.OnEvent("Click", Func("ChooseImage_Close").Bind(Data, TRUE)) ;Data, Error?
    oAccept.OnEvent("Click", Func("ChooseImage_Close").Bind(Data, FALSE))
    g.OnEvent("Close", Func("ChooseImage_Close").Bind(Data, TRUE))
    g.OnEvent("Escape", Func("ChooseImage_Close").Bind(Data, TRUE))

    ;Wait...
    WinWaitClose("ahk_id " . g.hWnd)

    ;Finish and return
    ObjRelease(oTBar)
    If (Data.hIcon)
        DllCall("User32.dll\DestroyIcon", "Ptr", Data.hIcon)
    Return (Data.Error ? FALSE : Data)
}

ChooseImage_Close(Data, Error)
{
    If (!Error && (Data.FileName == "" || Data.Icon == 0))
    {
        MsgBox("El archivo seleccionado no contiene íconos o es inválido.", Data.Title, "IconX Owner" . Data.g.hWnd)
        Return
    }
    
    Data.Error     := Error
    Data.g.Destroy()
}

ChooseImage_UpDown(Data, What, Action, Min, Max)
{
    Value                 := SubStr(Data["o" . What].Text, 2)
    Data[What]            := Action == "Up" ? (Value >= Max ? Max : Value + 1) : (Value <= Min ? Min : Value - 1)
    Data["o" . What].Text := A_Space . Data[What]
}

ChooseImage_Find(Data)
{
    Data.g.Opt("+OwnDialogs")

    If (Data.FileName == "")
        FileName    := FileSelect(3,,, "Imágenes (*.exe;*.dll;*.cpl;*.icl;*.scr;*.ocx;*.ico;*.bmp;*.ani;*.cur;*.jpg;*.tif;*.tiff;*.png;*.gif;*.jpeg)")
    Else
        FileName    := FileSelect(3, Data.FileName,, "Imágenes (*.exe;*.dll;*.cpl;*.icl;*.scr;*.ocx;*.ico;*.bmp;*.ani;*.cur;*.jpg;*.tif;*.tiff;*.png;*.gif;*.jpeg)")
    
    If (!ErrorLevel && FileName != Data.FileName)
    {
        Data.oFile.Text := A_Space . (Data.FileName := FileName)
        Data.Icon       := 1
        ChooseImage_Load(Data)
    }
}

ChooseImage_ItemSelect(Data)
{
    If (!(RowNumber := Data.oList.GetNext()))
        Data.oList.Modify(Data.Icon, "Select Focus Vis")
    Else
        Data.Icon     := RowNumber
    
    If (Data.hIcon)
        DllCall("User32.dll\DestroyIcon", "Ptr", Data.hIcon)

    Data.hIcon := DllCall("Shell32.dll\ExtractIconW", "Ptr", 0, "Str", Data.FileName, "Int", Data.Icon - 1)
    DllCall("User32.dll\SendMessage", "Ptr", Data.g.hWnd, "UInt", 0x0080, "Int", 0, "Ptr", Data.hIcon)
    DllCall("User32.dll\SendMessage", "Ptr", Data.g.hWnd, "UInt", 0x0080, "Int", 1, "Ptr", Data.hIcon)
}

ChooseImage_Load(Data)
{
    Data.oList.Opt("-Redraw")
    Data.oList.Delete()
    
    If (Data.FileName != "")
    {
        Count       := DllCall("Shell32.dll\ExtractIconW", "Ptr", 0, "Str", Data.FileName, "Int", -1)
        ImageList   := IL_Create(Count ? Count : 1, 1, 1)
        IL_Destroy(Data.oList.SetImageList(ImageList))
        
        If (Count)
        {
            Percentage := 0
            Icons      := 0

            Loop (Count)
            {
                Percentage += 100.0 / Count

                ;Ensure that it is an icon
                If (!DllCall("User32.dll\DestroyIcon", "Ptr", DllCall("Shell32.dll\ExtractIconW", "Ptr", 0, "Str", Data.FileName, "Int", A_Index - 1)))
                    Continue

                If (!(Icon := IL_Add(ImageList, Data.FileName, A_Index)))
                    Continue

                If (!Data.oList.Add("Icon" . Icon))
                    Continue

                ;Update info every 4 iterations (for performance)
                ++Icons
                If (Mod(A_Index, 4) == 0)
                {
                    Data.oLoad.Text  := "Cargado:`t" . Round(Percentage, 2) . " `%." ;Load percentage (with two decimals)
                    Data.oInfo.Text  := "Iconos:`t" . Icons . " de " . Count . "." ;Current number of icons
                }

                DllCall(NumGet(NumGet(Data.oTBar)+9*A_PtrSize), "Ptr", Data.oTBar, "Ptr", Data.hTBar, "Int64", Round(Percentage * 10), "Int64", 1000)
            }

            DllCall(NumGet(NumGet(Data.oTBar)+9*A_PtrSize), "Ptr", Data.oTBar, "Ptr", Data.hTBar, "Int64", 0, "Int64", 1000)
            Data.oList.Modify(Data.Icon := (Data.Icon > Data.oList.GetCount() ? Data.oList.GetCount() : Data.Icon), "Focus Select Vis")
        }
        
        Else If (IL_Add(ImageList, Data.FileName))
            R := Data.oList.Add("Icon" . (Data.Icon := 1) . " Focus Select Vis")

        Else
            R := 0, Data.Icon := 0
    }
    
    Data.oLoad.Text   := "Cargado:`t100 `%."
    Data.oInfo.Text   := "Iconos:`t" . Data.oList.GetCount() . " de " . (Count ? Count : (R ? 1 : 0)) . "."
    Data.g.Title      := "(" . Data.oList.GetCount() . ") " . Data.Title
    Data.oList.Opt("+Redraw")
    ChooseImage_ItemSelect(Data)
}





Muestra el díalogo "Abrir con..."
Image

Code: Select all

/*
Muestra el díalogo "Abrir con...".
Parámetros:
    Owner: El identificador de la ventana propietaria de este diálogo. Este valor puede ser cero.
    FileName: La ruta a el archivo sobre el cual preguntar al usuario con que programa se debe abrir.
Return: Si tuvo éxito devuelve 1, caso contrario devuelve 0.
*/
OpenWith(Owner, FileName)
{
    If (!FileExist(FileName) || DirExist(FileName))
        Return (FALSE)

    VarSetCapacity(OPENASINFO, 2 * A_PtrSize + 4)
    NumPut(&FileName, OPENASINFO, 0, "Ptr")
    NumPut(0x00000004 | 0x00000001, OPENASINFO, 2 * A_PtrSize, "UInt")

    Return (DllCall("Shell32.dll\SHOpenWithDialog", "Ptr", Owner, "Ptr", &OPENASINFO) == 0)
} ;https://msdn.microsoft.com/en-us/library/windows/desktop/bb762234(v=vs.85).aspx





Muestra el diálogo "Ejecutar"
Image

Code: Select all

/*
Muestra el diálogo "Ejecutar".
Parámetros:
    Owner: El identificador de la ventana propietaria de este diálogo. Este valor puede ser cero.
    WorkingDir: El directorio de trabajo. Si este parámetro es una cadena vacía o el directorio no existe se utiliza el directorio de trabajo actual.
    Title: El título de la ventana. Si este parámetro es una cadena vacía se utiliza el título por defecto 'Ejecutar'.
    Description: La descripción. Si este parámetro es una cadena vacía se utiliza la descripción por defecto.
    hIcon: El identificador a un icono. Si este parámetro es 0 se utiliza el icono por defecto.
*/
RunFileDlg(Owner := 0, WorkingDir := "", Title := "", Description := "", hIcon := 0)
{
    If (!DirExist(WorkingDir))
        WorkingDir := A_WorkingDir

    DllCall("Kernel32.dll\GetModuleHandleExW", "UInt", 0, "Str", "shell32.dll", "PtrP", hModule)
    RunFileDlg := DllCall("Kernel32.dll\GetProcAddress", "Ptr", hModule, "UInt", 61, "Ptr")
    DllCall(RunFileDlg, "Ptr", Owner, "Ptr", hIcon, "Str", WorkingDir, Title?"Str":"Ptr", Title?Title:0, Description?"Str":"Ptr", Description?Description:0, "UInt", 0)
} ;https://www.winehq.org/pipermail/wine-patches/2004-June/011280.html | https://www.codeproject.com/articles/2734/using-the-windows-runfile-dialog-the-documented-an





Muestra el diálogo donde aparece la version de Windows
Image

Code: Select all

/*
Muestra el diálogo donde aparece la version de Windows.
Parámetros:
    Owner: El identificador de la ventana propietaria de este diálogo. Este valor puede ser cero.
    Title: El título de la ventana. Si Title contiene "#" el texto se divide en dos partes, la primera se asigna al título y la otra a la primera línea del diálogo.
    Text: El texto a mostrar en el diálogo despues de la información de versión y copyright.
*/
ShellAbout(Owner := 0, Title := "", Text := "", Icon := 0)
{
    DllCall("Shell32.dll\ShellAbout", "Ptr", Owner, "Str", Title, "Str", Text, "Ptr", Icon)
} ;https://msdn.microsoft.com/en-us/library/windows/desktop/bb762152(v=vs.85).aspx





Muestra un diálogo y espera a que el usuario haga clic en un botón. Generalmente utilizado para informar al usuario o para pedir confirmación antes de realizar una determinada acción
GitHub: https://github.com/flipeador/AutoHotkey ... Dialog.ahk
Image

Code: Select all

/*
    Muestra un diálogo de tareas. Generalmente utilizado para informar al usuario y/o para pedir confirmación antes de realizar una determinada acción.
    Parámetros:
        Owner   : El identificador de la ventana padre de este diálogo. Este valor puede ser cero.
                  Un Array con el identificador de la ventana padre y/o el icono principal a mostrar en el diálogo. [Owner, MainIcon|IconFile|*HICON, MainIconIndex].
                  MainIcon puede ser cualquiera de los siguientes valores:
                     0xFFFE (TD_ERROR_ICON)       = Aparece un ícono de señal de stop o error en el cuadro de diálogo de tarea.
                     0xFFFF (TD_WARNING_ICON)     = Aparece un icono de signo de exclamación en el cuadro de diálogo de tarea.
                     0xFFFD (TD_INFORMATION_ICON) = Un ícono que consiste en una letra minúscula i en un círculo aparece en el cuadro de diálogo de tarea.
                     0xFFFC (TD_SHIELD_ICON)      = Aparece un icono de escudo en el cuadro de diálogo de tarea.
                  IconFile: La ruta a un archivo icono o que contenga iconos, MainIconIndex especifica el índice del icono (por defecto es 1).
                  *HICON  : Especifica un asterisco seguido del identificador de un icono. El icono no es eliminado.
        Title   : La cadena que se utilizará para el título del diálogo. Si es una cadena vacía, se utilizará el nombre del archivo ejecutable.
                  Un Array con el título y el "subtítulo". [Title, Subtitle].
        Content : La cadena que se visualizará como contenido principál en el diálogo para instruir al usuario qué hacer o presentar información.
                  Un Array con el texto principal e información adicional. [Content, ExpandedInformation, ExpandedControlText, CollapsedControlText, ExpandedByDefault?].
                  ExpandedControlText : La cadena que se utilizará para etiquetar el botón para contraer la información adicional.
                  CollapsedControlText: La cadena que se utilizará para etiquetar el botón para expandir la información adicional.
                  ExpandedByDefault   : Determina si la información adicinal se muestra expandida inicialmente. Por defecto es 0 (FALSE).
        Buttons : Especifica los botones comunes del diálogo, debe especificar una cadena con una o más de las palabras OK/YES/NO/CANCEL/RETRY/CLOSE, puede añadir como prefijo una "d" para establecerlo como por defecto.
                  Un Array que especifica los distintos tipos de botones a mostrar en el diálogo. [CommonButtons, CommandLinkButtons, RadioButtons, CheckBox].
                  CommandLinkButtons: Especifica un Array con la definición de los Botones o Enlaces de Comando que se mostrarán en el diálogo. La cadena-etiqueta que inicie con "`r" será el botón por defecto.
                  RadioButtons      : Especifica un Array con la definición de los RadioButtons que se mostrarán en el diálogo. La cadena-etiqueta que inicie con "`r" será el botón marcado al inicio.
                  CheckBox          : La cadena que se utilizará para etiquetar la casilla de verificación (checkbox).
        Footer  : La cadena que se utilizará en el área del pie de página (parte inferior) del diálogo.
                  Un Array con el texto en el área de pie de página y el icono a mostrar junto a él. [FooterText, FooterIcon|IconFile|*HICON, FooterIconIndex]. Se aplica la misma lógica que en el parámetro «Owner».
        Callback: Puntero a una función de devolución de llamada definida por la aplicación; o puede especificar el nombre de una función, en cuyo caso se utilizará CallbackCreate+CallbackFree.
                  Un Array con la función de devolución de llamada y los datos de referencia definidos por la aplicación. [FuncPtr|FuncName, DataPtr|Data].
        Options : Especifica un entero que controla ciertos comportamiendos del diálogo, debe sumar los valores para combinar.
            0x0001 (TDF_ENABLE_HYPERLINKS)         = Habilita el procesamiento de hipervínculos para las cadenas especificadas en Content, ExpandedInformation y FooterText. <A HREF="executablestring">Hyperlink Text</A>.
            0x0008 (TDF_ALLOW_DIALOG_CANCELLATION) = Indica que el diálogo se debe poder cerrar usando Alt-F4, Escape y el botón de cerrar de la barra de título, incluso si no se especifica ningún botón de cancelar en CommonButtons o CommandLinkButtons.
            0x0020 (TDF_USE_COMMAND_LINKS_NO_ICON) = Indica que los botones CommandLink se deben mostrar como enlaces de comando (sin un glifo) en lugar de botones pulsadores. Al utilizar enlaces de comando, todos los caracteres hasta el primer carácter de nueva línea se tratarán como el texto principal del enlace de comando, y el resto se tratará como la nota del enlace de comando.
            0x0100 (TDF_VERIFICATION_FLAG_CHECKED) = Indica que la casilla de verificación (CheckBox) en el cuadro de diálogo está marcada cuando se muestra inicialmente el cuadro de diálogo.
            0x0200 (TDF_SHOW_PROGRESS_BAR)         = Indica que se debe mostrar una barra de progreso.
            0x0400 (TDF_SHOW_MARQUEE_PROGRESS_BAR) = Indica que se debe mostrar una barra de progreso "a marcas" (Marquee Progress Bar).
            0x0800 (TDF_CALLBACK_TIMER)            = Indica que se debe invocar la devolución de llamada del diálogo de tareas aproximadamente cada 200 milisegundos.
            0x2000 (TDF_RTL_LAYOUT)                = Indica que el texto se muestra leyendo de derecha a izquierda.
            0x8000 (TDF_CAN_BE_MINIMIZED)          = Indica que el diálogo de tareas puede ser minimizado.
            0x01000000 (TDF_SIZE_TO_CONTENT)       = Indica que el ancho del diálogo de tareas está determinado por el ancho de su área de contenido. Este indicador se ignora si el ancho no está configurado en 0.
    Return:
        Si hubo un error devuelve el código de error (entero), si tuvo éxito devuelve un objeto con las siguientes claves.
            Button  : La cadena con el nombre del botón común precionado o el índice del botón CommandLink donde el primer botón añadido tendra el identificador 1, el segundo el identificador 2 y así suscesivamente.
            Radio   : El identificador del botón radio marcado. El primer botón radio añadido tendrá el identificador 1, el segundo el identificador 2 y así suscesivamente.
            CheckBox: Determina el estado del botón de verificación (checkbox). Si es 1, el CheckBox estaba marcado.
    Observaciones:
        Puede ejecutar la ayuda presionando la tecla F1.
        Ver ejemplo al final
*/
TaskDialog(Owner, Title, Content := "", Buttons := "", Footer := "", Callback := "", Options := 0)
{
    ; TASKDIALOGCONFIG structure
    ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb787473(v=vs.85).aspx
    Local Size  := A_PtrSize == 4 ? 96 : 160    ; cbSize
        , Flags := 0    ; dwFlags
    VarSetCapacity(TASKDIALOGCONFIG, Size, 0)    ; TASKDIALOGCONFIG structure
    NumPut(Size, &TASKDIALOGCONFIG, "UInt")    ; cbSize

    ; establecemos la ventana padre
    Local Owner2 := IsObject(Owner) && ObjLength(Owner) > 0 ? Owner[1] : 0
    NumPut(Owner2, &TASKDIALOGCONFIG + 4, "Ptr")    ; hwndParent

    ; establecemos el icono principal
    Local MainIcon      := (IsObject(Owner) && ObjLength(Owner) > 1 ? Owner[2] : "")
    Local MainIconIndex := (IsObject(Owner) && ObjLength(Owner) > 2 ? Owner[3] :  1)
    Local MainIconType  := MainIcon == "" ? "" : (SubStr(MainIcon, 1, 1) == "*" && SubStr(MainIcon, 2) is "Integer" ? 0 : MainIcon is "Integer" ? 1 : 2)
    NumPut(TaskDialog_SetIcon(MainIcon, MainIconIndex, MainIconType, Flags, 0x0002), &TASKDIALOGCONFIG + (A_PtrSize == 4 ? 24 : 36), "Ptr")    ; hMainIcon | pszMainIcon | TDF_USE_HICON_MAIN = 0x0002

    ; establecemos el título
    Local Title2 := (IsObject(Title) && ObjLength(Title) > 0 ? Title[1] : Title) . ""
    NumPut(Title2 == "" ? 0 : &Title2, &TASKDIALOGCONFIG + (A_PtrSize == 4 ? 20 : 28))    ; pszWindowTitle

    ; establecemos el subtítulo
    Local SubTitle := IsObject(Title) && ObjLength(Title) > 1 ? Title[2] . "" : ""
    NumPut(SubTitle == "" ? 0 : &SubTitle, &TASKDIALOGCONFIG + (A_PtrSize = 4 ? 28 : 44))    ; pszMainInstruction

    ; establecemos el texto principal
    Local Content2 := (IsObject(Content) && ObjLength(Content) > 0 ? Content[1] : Content) . ""
    NumPut(Content2 == "" ? 0 : &Content2, &TASKDIALOGCONFIG + (A_PtrSize == 4 ? 32 : 52))    ; pszContent

    ; establecemos la información adicional, la etiqueta del botón que la expande y la contrae, y el estado inicial (expandido o contraido)
    Local ExpandedInformation := IsObject(Content) && ObjLength(Content) > 1 ? Content[2] . "" : ""
    NumPut(ExpandedInformation == "" ? 0 : &ExpandedInformation, &TASKDIALOGCONFIG + (A_PtrSize == 4 ? 64 : 100))    ; pszExpandedInformation
    Local ExpandedControlText := IsObject(Content) && ObjLength(Content) > 2 ? Content[3] . "" : ""
    NumPut(ExpandedControlText == "" ? 0 : &ExpandedControlText, &TASKDIALOGCONFIG + (A_PtrSize == 4 ? 68 : 108))    ; pszExpandedControlText
    Local CollapsedControlText := IsObject(Content) && ObjLength(Content) > 3 ? Content[4] . "" : ""
    NumPut(CollapsedControlText == "" ? 0 : &CollapsedControlText, &TASKDIALOGCONFIG + (A_PtrSize == 4 ? 72 : 116))    ; pszCollapsedControlText
    Flags |= IsObject(Content) && ObjLength(Content) > 4 && Content[5] ? 0x0080 : 0x0000    ; TDF_EXPANDED_BY_DEFAULT = 0x0080

    ; establecemos los botones comunes
    Local DefaultButton := 0    ; almacena el botón común por defecto (si se especificó); o cero
        , CommonButtons := IsObject(Buttons) && ObjLength(Buttons) > 0 ? TaskDialog_CommonButtons(Buttons[1], &TASKDIALOGCONFIG, DefaultButton) : 0
    NumPut(CommonButtons, &TASKDIALOGCONFIG + (A_PtrSize == 4 ? 16 : 24), "UInt")

    ; establecemos los controles de enlace de comando (command link buttons)
    Local TASKDIALOG_BUTTON := "", CLButton := ""
    If (CLButton := TASKDIALOG_BUTTON(TASKDIALOG_BUTTON, IsObject(Buttons) && ObjLength(Buttons) > 1 ? Buttons[2] : 0, DefaultButton))
        NumPut(CLButton.Count, &TASKDIALOGCONFIG + (A_PtrSize == 4 ? 36 : 60), "UInt")    ; cButtons
      , NumPut(&TASKDIALOG_BUTTON, &TASKDIALOGCONFIG + (A_PtrSize == 4 ? 40 : 64))    ; pButtons
      , NumPut(CLButton.Default, &TASKDIALOGCONFIG + (A_PtrSize == 4 ? 44 : 72), "Int")    ; nDefaultButton
      , Flags |= 0x0010    ; TDF_USE_COMMAND_LINKS

    ; establecemos los controles Radio Buttons
    Local TASKDIALOG_RBUTTON := "", RButton := ""
    If (RButton := TASKDIALOG_BUTTON(TASKDIALOG_RBUTTON, IsObject(Buttons) && ObjLength(Buttons) > 2 ? Buttons[3] : 0))
        NumPut(RButton.Count, &TASKDIALOGCONFIG + (A_PtrSize == 4 ? 48 : 76), "UInt")    ; cButtons
      , NumPut(&TASKDIALOG_RBUTTON, &TASKDIALOGCONFIG + (A_PtrSize == 4 ? 52 : 80))    ; pButtons
      , NumPut(RButton.Default, &TASKDIALOGCONFIG + (A_PtrSize == 4 ? 56 : 88), "Int")    ; nDefaultRadioButton
      , Flags |= RButton.Default ? 0 : 0x4000    ; TDF_NO_DEFAULT_RADIO_BUTTON = 0x4000

    ; establecemos la etiqueta del control de verificación (checkbox)
    Local VerificationText := (IsObject(Buttons) && ObjLength(Buttons) > 3 ? Buttons[4] . "" : "")
    NumPut(VerificationText == "" ? 0 : &VerificationText, &TASKDIALOGCONFIG + (A_PtrSize == 4 ? 60 : 92))    ; pszVerificationText

    ; establecemos el texto en el área del pie de página
    Local FooterText := (IsObject(Footer) && ObjLength(Footer) > 0 ? Footer[1] : Footer) . ""
    NumPut(FooterText == "" ? 0 : &FooterText, &TASKDIALOGCONFIG + (A_PtrSize == 4 ? 80 : 132))    ; pszFooter

    ; establecemos el icono en el área de pie de página
    Local FooterIcon      := (IsObject(Footer) && ObjLength(Footer) > 1 ? Footer[2] : "")
    Local FooterIconIndex := (IsObject(Footer) && ObjLength(Footer) > 2 ? Footer[3] :  1)
    Local FooterIconType  := FooterIcon == "" ? "" : (SubStr(FooterIcon, 1, 1) == "*" && SubStr(FooterIcon, 2) is "Integer" ? 0 : FooterIcon is "Integer" ? 1 : 2)
    NumPut(TaskDialog_SetIcon(FooterIcon, FooterIconIndex, FooterIconType, Flags, 0x0004), &TASKDIALOGCONFIG + (A_PtrSize == 4 ? 76 : 124), "Ptr")    ; hFooterIcon | pszFooterIcon | TDF_USE_HICON_FOOTER = 0x0004

    ; establecemos la función de devolución de llamada y los datos de referencia
    Local Callback2    := IsObject(Callback) && ObjLength(Callback) > 0 ? Callback[1] : Callback
    Local FuncPtr      := Callback2 is "Integer" ? 0 : CallbackCreate(Callback2 == "" ? "TaskDialog_CallbackProc" : Callback2)
    Local CallbackData := IsObject(Callback) && ObjLength(Callback) > 1 ? (Callback[2] is "Integer" ? Callback[2] : &Callback[2]) : 0
    NumPut(FuncPtr ? FuncPtr : (Callback2 == "" ? 0 : Callback2), &TASKDIALOGCONFIG + (A_PtrSize == 4 ? 84 : 140))
    NumPut(CallbackData, &TASKDIALOGCONFIG + (A_PtrSize == 4 ? 88 : 148))

    ; establecemos los Flags (banderas)
    NumPut(Flags | Options, &TASKDIALOGCONFIG + (A_PtrSize == 4 ? 12 : 20), "UInt")

    ; llamamos a la función WINAPI::TaskDialogIndirect para mostrar el diálogo
    Local R := 0, Button := 0, Radio := 0, Checkbox := 0
    R := DllCall("Comctl32.dll\TaskDialogIndirect", "UPtr", &TASKDIALOGCONFIG, "IntP", Button, "IntP", Radio, "IntP", Checkbox, "UInt")

    ; destruimos los iconos si se utilizó la función incorporada LoadPicture()
    If (MainIconType == 2)
        DllCall("User32.dll\DestroyIcon", "Ptr", NumGet(&TASKDIALOGCONFIG + (A_PtrSize == 4 ? 24 :  36), "Ptr"))    ; hMainIcon
    If (FooterIconType == 2)
        DllCall("User32.dll\DestroyIcon", "Ptr", NumGet(&TASKDIALOGCONFIG + (A_PtrSize == 4 ? 76 : 124), "Ptr"))    ; hFooterIcon

    ; liberamos la memoria utilizada al llamar a CallbackCreate
    If (FuncPtr)
        CallbackFree(FuncPtr)    ; Return: 0 = OK | FuncPtr = ERROR

    ; devolvemos el resultado
    Buttons := {1: "OK", 6: "YES", 7: "NO", 2: "CANCEL", 4: "RETRY", 8: "CLOSE"}
    Return R ? R : {Button: ObjHasKey(Buttons, Button) ? Buttons[Button] : Button?Button-100:0, Radio: Radio?Radio-100:0, CheckBox: Checkbox}
}





/*
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    :::: FUNCIONES PARA USO INTERNO DE LA FUNCIÓN TaskDialog. IGNORAR!
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*/
TASKDIALOG_BUTTON(ByRef TASKDIALOG_BUTTON, Buttons, Default := 0)
{
    If (!IsObject(Buttons) || ObjLength(Buttons) == 0)
        Return 0

    Local Offset  := -A_PtrSize
    VarSetCapacity(TASKDIALOG_BUTTON, (4 + A_PtrSize) * ObjLength(Buttons))
    Loop (ObjLength(Buttons))
    {
        If (SubStr(Buttons[A_Index], 1, 1) == "`r")
            Default := 100 + A_Index, Buttons[A_Index] := SubStr(Buttons[A_Index], 2)
        NumPut(100 + A_Index, &TASKDIALOG_BUTTON + (Offset += A_PtrSize), "Int")    ; nButtonID
        NumPut(ObjGetAddress(Buttons, A_Index), &TASKDIALOG_BUTTON + (Offset += 4))    ; pszButtonText
    }

    Return {Count: ObjLength(Buttons), Default: Default}
} ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb787475(v=vs.85).aspx

TaskDialog_CommonButtons(Value, TASKDIALOGCONFIG, ByRef DefaultButton)
{
    If (Value is "Number")    ; permite utilizar un entero para determinar los botones normales mostrados en el diálogo; en lugar de una cadena con el nombre de los botones
        Return Value
    ;                                 IDOK          |         IDYES          |         IDNO            |        IDCANCEL         |          IDRETRY         |         IDCLOSE
    NumPut(DefaultButton := InStr(Value, "dOK") ? 1 : InStr(Value, "dY") ? 6 : InStr(Value, "dNO") ? 7 : InStr(Value, "dCA") ? 2 : InStr(Value, "dRE") ? 4 : InStr(Value, "dCL") ? 8 : 0
            , TASKDIALOGCONFIG + (A_PtrSize == 4 ? 44 : 72), "Int")    ; nDefaultButton
    ;          TDCBF_OK_BUTTON      |    TDCBF_YES_BUTTON     |     TDCBF_NO_BUTTON      |    TDCBF_CANCEL_BUTTON   |    TDCBF_RETRY_BUTTON     |    TDCBF_CLOSE_BUTTON
    Return (InStr(Value, "OK")?1:0) | (InStr(Value, "Y")?2:0) | (InStr(Value, "NO")?4:0) | (InStr(Value, "CA")?8:0) | (InStr(Value, "RE")?16:0) | (InStr(Value, "CL")?32:0)
}

TaskDialog_SetIcon(Icon, IconIndex, ByRef IconType, ByRef Flags, Flag)
{
    Flags |= IconType == "" || IconType == 1 ? 0 : Flag    ; TDF_USE_HICON_MAIN = 0x0002 | TDF_USE_HICON_FOOTER = 0x0004

    If (IconType == "")    ; sin icono
        Return 0
    If (IconType == 0)    ; *HICON
        Return SubStr(Icon, 2)
    If (IconType == 1)
        Return Icon    ; iconos predefinidos (error, advertencia, información, escudo, ..)

    Local HICON := LoadPicture(Icon, "Icon" . IconIndex, ImageType)
    If (!HICON || ImageType != 1)    ; si fallo al cargar el icono o si el archivo no es un icono
    {
        If (HICON)
            DllCall(ImageType ? "User32.dll\DestroyCursor" : "Gdi32.dll\DeleteObject", "Ptr", HICON)
        IconType := ""    ; sin icono
        Return 0
    }

    Return HICON    ; HICON = LoadPicture()
}

TaskDialog_CallbackProc(Hwnd, Notification, wParam, lParam, RefData)
{
    If (Notification == 3)    ; TDN_HYPERLINK_CLICKED
        Run(StrGet(lParam, "UTF-16"))

    Return 0
}





/*
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    :::: EJEMPLO
    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*/
/*
; establecemos las parámetros y opciones del diálogo
Owner        := 0
MainIcon     := 0xFFFC    ; TD_SHIELD_ICON
Title        := "Título del diálogo"
Subtitle     := "# Mi Subtitulo =D"    ; MainInstruction
Content      := "Contenido principal del diálogo! | Presiona F1 para ver la ayuda!`nVisita <A HREF="https://autohotkey.com">AutoHotkey</A>" 
ExpInfo      := "Mostrando la información adicional"    ; ExpandedInformation
Buttons      := "dOK YES NO CANCEL RETRY CLOSE"    ; dOK = Default OK
CLButtons    := ["Command Link #1", "Command Link #2`nInformación adicional :)"]
RButtons     := ["Radio Button #1", "`rRadio Button #2"]    ; `r = Default
CButton      := "Casilla de verificación (checkbox)"    ; CheckBox Control
FooterText   := "Texto en el área de pie de página"
FooterIcon   := A_ComSpec    ; LoadPicture() + DestroyIcon()
Callback     := "TaskDialog_CallbackProc2"
CallbackData := {Help: "Hola, soy una ayuda =D", Bye: "Bye Bye!"}
Options      := 0x0001 | 0x0008 | 0x0100 | 0x0200 | 0x0400 | 0x0800 | 0x8000
; mostramos el diálogo y almacenamos el valor devuelto en la variable "R"
R := TaskDialog([Owner,MainIcon], [Title,Subtitle], [Content,ExpInfo], [Buttons,CLButtons,RButtons,CButton], [FooterText,FooterIcon], [Callback,CallbackData], Options)
MsgBox(!IsObject(R) ? "ERROR #" . R : "Button: " . R.Button . "`nRadio: " . R.Radio . "`nCheckBox: " . R.CheckBox)
ExitApp
; Función de devolución de llamada del diálogo
; Hwnd: El identificador de la ventana de diálogo de tarea.
; Notification: Código de notificación, ver referencia.
; wParam / lParam: Especifica información adicional, depende del valor de Notification.
; RefData: Puntero a datos específicos de la aplicación.
; Referencia: https://msdn.microsoft.com/en-us/library/windows/desktop/bb760542(v=vs.85).aspx
TaskDialog_CallbackProc2(Hwnd, Notification, wParam, lParam, RefData)
{
    Local CallbackData := Object(RefData)
    If (Notification == 2)    ; TDN_BUTTON_CLICKED
        MsgBox("Button Clicked: " . wParam,, "Owner" . Hwnd)
    Else If (Notification == 3)    ; TDN_HYPERLINK_CLICKED
        Run(StrGet(lParam, "UTF-16"))
    Else If (Notification == 5)    ; TDN_DESTROYED
        MsgBox(CallbackData.Bye)
    Else If (DllCall("User32.dll\IsWindowVisible", "Ptr", Hwnd) && Notification == 6)    ; TDN_RADIO_BUTTON_CLICKED
        MsgBox("RadioButton #" . wParam,, "Owner" . Hwnd)
    Else If (Notification == 7)    ; TDN_DIALOG_CONSTRUCTED
        Return 0
    Else If (Notification == 8)    ; TDN_VERIFICATION_CLICKED
        MsgBox("CheckBox: " . wParam,, "Owner" . Hwnd)
    Else If (Notification == 9)    ; TDN_HELP (F1)
        MsgBox(CallbackData.Help,, "Owner" . Hwnd)
    Else If (Notification == 10)    ; TDN_EXPANDO_BUTTON_CLICKED
        ToolTip(wParam ? "Mostrando la info adicional" : "Ocultando la info adicional"), SetTimer("ToolTip", -1000)
    return 0 ;CONSTANTS: https://searchcode.com/codesearch/view/77005279/
}*/





Muestra un diálogo para pedirle al usuario que seleccione un color RGB
Image

Code: Select all

/*
Muestra un diálogo para pedirle al usuario que seleccione un color RGB.
Parámetros:
    Owner: El identificador de la ventana propietaria de este diálogo. Este valor puede ser cero.
    Color: El color RGB seleccionado por defecto al crear el diálogo. si se deja en -1, automáticamente se lee el último color seleccionado por el usuario.
    Palette: Un 'array' con los 16 colores que acepta la paleta de colores mostrada por el diálogo. Si este valor es 0, lee la paleta de colores guardada por el usuario.
Return:
    La función devuelve -1 si el usuario canceló el diálogo. En caso contrario devuelve el color RGB (0x000000).
Observaciones:
    El color seleccionado y la paleta de colores es automáticamente guardada en un archivo cuando el usuario acepta el diálogo.
*/
ChooseColor(Owner := 0, Color := -1, Palette := 0)
{
    CfgFile             := A_AppData . "\AutoHotkey\Temp\ChooseColor.ini"
    Flags               := 0x00000001 | 0x00000100
    Color               := Color == -1 ? IniRead(CfgFile, "Default", "Color", 0) : ((Color & 255) << 16) | (((Color >> 8) & 255) << 8) | (Color >> 16)
    Palette             := IsObject(Palette) ? Palette : []

    If (!FileExist(CfgFile))
    {
        DirCreate(SubStr(CfgFile, 1, -16))
        FileOpen(CfgFile, "w", "CP0")
    }
    
    ;https://msdn.microsoft.com/en-us/library/windows/desktop/dd183449(v=vs.85).aspx
    VarSetCapacity(CUSTOM, 16 * A_PtrSize)
    Loop (16)
    {
        If (Palette[A_Index] == "" || Palette[A_Index] == -1)
            NumPut(IniRead(CfgFile, "Palette", A_Index, 0), CUSTOM, (A_Index - 1) * 4, "UInt")
        Else
            NumPut(((Palette[A_Index] & 255) << 16) | (((Palette[A_Index] >> 8) & 255) << 8) | (Palette[A_Index] >> 16), CUSTOM, (A_Index - 1) * 4, "UInt")
    }
    
    ;https://msdn.microsoft.com/en-us/library/windows/desktop/ms646830(v=vs.85).aspx
    NumPut(VarSetCapacity(CHOOSECOLOR, 9 * A_PtrSize, 0), CHOOSECOLOR, 0, "UInt")
    NumPut(Owner, CHOOSECOLOR, A_PtrSize, "Ptr")
    NumPut(Color, CHOOSECOLOR, 3 * A_PtrSize, "Ptr")
    NumPut(&CUSTOM, CHOOSECOLOR, 4 * A_PtrSize, "Ptr")
    NumPut(Flags, CHOOSECOLOR, 5 * A_PtrSize, "UInt")

    ;https://msdn.microsoft.com/en-us/library/windows/desktop/ms646912(v=vs.85).aspx
    R                   := DllCall("ComDlg32.dll\ChooseColorW", "Ptr", &CHOOSECOLOR)

    If (R != FALSE)
    {
        IniWrite(Color := NumGet(CHOOSECOLOR, 3 * A_PtrSize, "UInt"), CfgFile, "Default", "Color")
        
        Loop (16)
            IniWrite(NumGet(CUSTOM, (A_Index - 1) * 4, "UInt"), CfgFile, "Palette", A_Index)
    }

    Return (R == FALSE ? -1 : Format("0x{:06X}", (Color & 255) << 16 | (Color & 65280) | (Color >> 16)))
}





Muestra un diálogo para pedirle al usuario que selecciona fuente y color
Image

Code: Select all

/*
Muestra un diálogo para pedirle al usuario que selecciona fuente y color.
Parámetros:
    Owner: El identificador de la ventana propietaria de este diálogo. Este valor puede ser cero.
    FontName: El nombre de la fuente seleccionada por defecto.
    Options: Opciones para este diálogo. Este parámetro debe ser una cadena con una o más de las siguientes palabras:
        sN                                   = Número entero que reprecenta el tamaño del texto.
        Bold / Italic / Underline / strike   = El estilo del texto. Negrita, cursiva, subrayado, tachado; respectivamente.
        wN                                   = El peso del texto. 400 es normal. 600 es semi-negrita. 700 es negrita.
        cN                                   = El color RGB del texto.
        csN                                  = El conjunto de caracteres.
    Flags: Otras opciones. Espesificar uno o más de los siguientes valores:
        0x00000200 = Muestra el botón Aplicar.
        0x00000004 = Muestra el botón Ayuda.
        0x00040000 = Muestra únicamente las fuentes de tipo 'TrueType'.
        0x00004000 = Muestra las fuentes 'fixed-pitch'.
        0x02000000 = Muestra las fuentes marcadas como ocultas en el panel de control.
        0x01000000 = El diálogo no muestra fuentes orientadas de forma vertical.
        0x00000100 = Habilita el subrayado, tachado y seleccion de color. Este es el valor por defecto.
        0x00010000 = La fuente debe existir. Este es el valor por defecto.
*/
ChooseFont(Owner := 0, FontName := "Arial", Options := "", Flags := 0x10100)
{
    hDC         := DllCall("Gdi32.dll\CreateDCW", "Str", "DISPLAY", "Ptr", 0, "Ptr", 0, "Ptr", 0, "Ptr")
    LogPixelsY  := DllCall("Gdi32.dll\GetDeviceCaps", "Ptr", hDC, "Int", 90)
    DllCall("Gdi32.dll\DeleteDC", "Ptr", hDC)

    Size        := RegExMatch(Options, "i)s([\-\d\.]+)(p*)", t)     ? Round((t.1 * LogPixelsY) / 72)    : Round((10 * LogPixelsY) / 72)
    Weight      := RegExMatch(Options, "i)w([\-\d\.]+)(p*)", t)     ? t.1                               : (InStr(Options, "Bold") ? 700 : 400)
    CharSet     := RegExMatch(Options, "i)cs([\-\d\.]+)(p*)", t)    ? t.1                               : 1
    Color       := RegExMatch(Options, "i)c([\-\d\.xa-f]+)(p*)", t) ? t.1+0                             : 0x000000
    Flags       |= 0x00000041

    VarSetCapacity(LOGFONT, 92, 0)
    NumPut(Size, LOGFONT, 0, "Int")
    NumPut(Weight, LOGFONT, 16, "Int")
    NumPut(!!InStr(Options, "Italic"), LOGFONT, 20, "UChar")
    NumPut(!!InStr(Options, "Underline"), LOGFONT, 21, "UChar")
    NumPut(!!InStr(Options, "Strike"), LOGFONT, 22, "UChar")
    NumPut(CharSet, LOGFONT, 23, "UChar")
    StrPut(FontName, &LOGFONT + 28, StrLen(FontName) + 1, "UTF-16")

    NumPut(VarSetCapacity(CHOOSEFONT, A_PtrSize = 8 ? 104 : 60, 0), CHOOSEFONT, 0, "UInt")
    NumPut(Owner, CHOOSEFONT, A_PtrSize, "Ptr")
    NumPut(&LOGFONT, CHOOSEFONT, 3*A_PtrSize, "Ptr")
    NumPut(Flags, CHOOSEFONT, 4*A_PtrSize + 4, "UInt")
    NumPut(((Color & 255) << 16) | (((Color >> 8) & 255) << 8) | (Color >> 16), CHOOSEFONT, 4*A_PtrSize + 2*4, "UInt")

    If (DllCall("comdlg32.dll\ChooseFontW", "Ptr", &CHOOSEFONT))
    {
        Font            := {}
        Font.Color      := Format("0x{:06X}", ((BGR:=NumGet(CHOOSEFONT, 4*A_PtrSize + 2*4, "UInt")) & 255) << 16 | (BGR & 65280) | (BGR >> 16))
        Font.Size       := NumGet(CHOOSEFONT, A_PtrSize=8?32:16, "Int") // 10
        Loop Parse, "Height.Width.Escapement.Orientation.Weight.Italic", "."
            Font[A_LoopField]   := NumGet(LOGFONT, (A_Index - 1) * 4, A_Index == 6 ? "UChar" : "Int")
        Loop Parse, "Underline.Strike.CharSet.OutPrecision.ClipPrecision.Quality.PitchAndFamily", "."
            Font[A_LoopField]   := NumGet(LOGFONT, 20 + A_Index, "UChar")
        Font.FontName   := StrGet(&LOGFONT + 28)
        Font.Bold       := Font.Weight == 700
    }

    Return (IsObject(Font) ? Font : FALSE)
}





Muestra un diálogo para guardar un archivo
GitHub: https://github.com/flipeador/AutoHotkey ... veFile.ahk
Image

Code: Select all

/*
    Muestra un diálogo para guardar uno archivo.
    Parámetros:
        Owner / Title:
            El identificador de la ventana propietaria de este diálogo. Este valor puede ser cero.
            Un Array con el identificador de la ventana propietaria y el título. Si el título es una cadena vacía se establece al por defecto "Guardar como".
        FileName:
            La ruta al archivo o directorio seleccioado por defecto. Si especifica un directorio, éste debe terminar con una barra invertida.
        Filter:
            Especifica un filtro de archivos. Debe especificar un objeto, cada clave representa la descripción y el valor los tipos de archivos.
            Para especificar el filtro seleccionado por defecto, agrege el caracter "`n" al valor de la clave.
        CustomPlaces:
            Especifica un Array con los directorios personalizados que se mostrarán en el panel izquierdo. Los directorios inexistentes serán omitidos.
            Para especificar la hubicación en la lista, especifique un Array con el directorio y la hubicación de este (0 = Inferior, 1 = Superior).
            Generalmente se suelte utilizar con la opción FOS_HIDEPINNEDPLACES.
        Options:
            Determina el comportamiento del diálogo. Este parámetro debe ser uno o más de los siguientes valores.
                0x00000002  (FOS_OVERWRITEPROMPT) = Ppreguntar antes de sobrescribir un archivo existente con el mismo nombre.
                0x00000004  (FOS_STRICTFILETYPES) = Solo permite al usuario elegir un archivo que tenga una de las extensiones de nombre de archivo especificadas a través del filtro.
                0x00040000 (FOS_HIDEPINNEDPLACES) = Ocultar elementos que se muestran de forma predeterminada en el panel de navegación de la vista.
                0x10000000  (FOS_FORCESHOWHIDDEN) = Incluye elementos ocultos y del sistema.
                0x02000000  (FOS_DONTADDTORECENT) = No agregue el elemento que se abre o guarda en la lista de documentos recientes (function SHAddToRecentDocs).
            Puede consultar todos los valores disponibles en https://msdn.microsoft.com/en-us/library/windows/desktop/dn457282(v=vs.85).aspx.
            Los valores por defecto son FOS_OVERWRITEPROMPT y FOS_STRICTFILETYPES.
    Return:
        Devuelve 0 si el usuario canceló el diálogo, en caso contrario devuelve la ruta del archivo seleccionado.
    Ejemplo:
        MsgBox SaveFile( [0, "Título del diálogo - Guardar como.."]
                       , A_ComSpec
                       , {Música: "*.mp3", Imágenes: "`n*.jpg;*.png", Videos: "*.avi;*.mp4;*.mkv;*.wmp", Documentos: "*.txt"}
                       , [A_WinDir,A_Desktop,A_Temp,A_Startup,A_ProgramFiles]
                       , 0x00000002 | 0x00000004 | 0x10000000 | 0x02000000 )
*/
SaveFile(Owner, FileName := "", Filter := "", CustomPlaces := "", Options := 0x6)
{
    ; IFileSaveDialog interface
    ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb775688(v=vs.85).aspx
    local IFileSaveDialog := ComObjCreate("{C0B4E2F3-BA21-4773-8DBA-335EC946EB8B}", "{84BCCD23-5FDE-4CDB-AEA4-AF64B83D78AB}")
        ,           Title := IsObject(Owner) ? Owner[2] . "" : ""
        ,           Flags := Options     ; FILEOPENDIALOGOPTIONS enumeration (https://msdn.microsoft.com/en-us/library/windows/desktop/dn457282(v=vs.85).aspx)
        ,      IShellItem := PIDL := 0   ; PIDL recibe la dirección de memoria a la estructura ITEMIDLIST que debe ser liberada con la función CoTaskMemFree
        ,             Obj := {}, foo := bar := ""
        ,       Directory := FileName
    Owner := IsObject(Owner) ? Owner[1] : (WinExist("ahk_id" . Owner) ? Owner : 0)
    Filter := IsObject(Filter) ? Filter : {"All files": "*.*"}


    if ( FileName != "" )
    {
        if ( InStr(FileName, "\") )
        {
            if !( FileName ~= "\\$" )    ; si «FileName» termina con "\" se trata de una carpeta
            {
                local File := ""
                SplitPath(FileName, File, Directory)
                ; IFileDialog::SetFileName
                ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb775974(v=vs.85).aspx
                DllCall(NumGet(NumGet(IFileSaveDialog)+15*A_PtrSize), "UPtr", IFileSaveDialog, "UPtr", &File)
            }
            
            while ( InStr(Directory,"\") && !DirExist(Directory) )                   ; si el directorio no existe buscamos directorios superiores
                Directory := SubStr(Directory, 1, InStr(Directory, "\",, -1) - 1)    ; recupera el directorio superior
            if ( DirExist(Directory) )
            {
                DllCall("Shell32.dll\SHParseDisplayName", "UPtr", &Directory, "Ptr", 0, "UPtrP", PIDL, "UInt", 0, "UInt", 0)
                DllCall("Shell32.dll\SHCreateShellItem", "Ptr", 0, "Ptr", 0, "UPtr", PIDL, "UPtrP", IShellItem)
                ObjRawSet(Obj, IShellItem, PIDL)
                ; IFileDialog::SetFolder method
                ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb761828(v=vs.85).aspx
                DllCall(NumGet(NumGet(IFileSaveDialog)+12*A_PtrSize), "Ptr", IFileSaveDialog, "UPtr", IShellItem)
            }
        }
        else    ; si «FileName» es únicamente el nombre de un archivo
            DllCall(NumGet(NumGet(IFileSaveDialog)+15*A_PtrSize), "UPtr", IFileSaveDialog, "UPtr", &FileName)
    }


    ; COMDLG_FILTERSPEC structure
    ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb773221(v=vs.85).aspx
    local Description := "", FileTypes := "", FileTypeIndex := 1
    ObjSetCapacity(Obj, "COMDLG_FILTERSPEC", 2*Filter.Count() * A_PtrSize)
    for Description, FileTypes in Filter
    {
        FileTypeIndex := InStr(FileTypes,"`n") ? A_Index : FileTypeIndex
        ObjRawSet(Obj, "#" . A_Index, Trim(Description)), ObjRawSet(Obj, "@" . A_Index, Trim(StrReplace(FileTypes,"`n")))
        NumPut(ObjGetAddress(Obj,"#" . A_Index), ObjGetAddress(Obj,"COMDLG_FILTERSPEC") + A_PtrSize * 2*(A_Index-1))        ; COMDLG_FILTERSPEC.pszName
        NumPut(ObjGetAddress(Obj,"@" . A_Index), ObjGetAddress(Obj,"COMDLG_FILTERSPEC") + A_PtrSize * (2*(A_Index-1)+1))    ; COMDLG_FILTERSPEC.pszSpec
    }

    ; IFileDialog::SetFileTypes method
    ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb775980(v=vs.85).aspx
    DllCall(NumGet(NumGet(IFileSaveDialog)+4*A_PtrSize), "UPtr", IFileSaveDialog, "UInt", Filter.Count(), "UPtr", ObjGetAddress(Obj,"COMDLG_FILTERSPEC"))

    ; IFileDialog::SetFileTypeIndex method
    ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb775978(v=vs.85).aspx
    DllCall(NumGet(NumGet(IFileSaveDialog)+5*A_PtrSize), "UPtr", IFileSaveDialog, "UInt", FileTypeIndex)


    if ( IsObject(CustomPlaces := IsObject(CustomPlaces) || CustomPlaces == "" ? CustomPlaces : [CustomPlaces]) )
    {
        local Directory := ""
        for foo, Directory in CustomPlaces    ; foo = index
        {
            foo := IsObject(Directory) ? Directory[2] : 0    ; FDAP enumeration (https://msdn.microsoft.com/en-us/library/windows/desktop/bb762502(v=vs.85).aspx)
            if ( DirExist(Directory := IsObject(Directory) ? Directory[1] : Directory) )
            {
                DllCall("Shell32.dll\SHParseDisplayName", "UPtr", &Directory, "Ptr", 0, "UPtrP", PIDL, "UInt", 0, "UInt", 0)
                DllCall("Shell32.dll\SHCreateShellItem", "Ptr", 0, "Ptr", 0, "UPtr", PIDL, "UPtrP", IShellItem)
                ObjRawSet(Obj, IShellItem, PIDL)
                ; IFileDialog::AddPlace method
                ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb775946(v=vs.85).aspx
                DllCall(NumGet(NumGet(IFileSaveDialog)+21*A_PtrSize), "UPtr", IFileSaveDialog, "UPtr", IShellItem, "UInt", foo)
            }
        }
    }


    ; IFileDialog::SetTitle method
    ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb761834(v=vs.85).aspx
    DllCall(NumGet(NumGet(IFileSaveDialog)+17*A_PtrSize), "UPtr", IFileSaveDialog, "UPtr", Title == "" ? 0 : &Title)

    ; IFileDialog::SetOptions method
    ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb761832(v=vs.85).aspx
    DllCall(NumGet(NumGet(IFileSaveDialog)+9*A_PtrSize), "UPtr", IFileSaveDialog, "UInt", Flags)


    ; IModalWindow::Show method
    ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb761688(v=vs.85).aspx
    local Result := FALSE
    if ( !DllCall(NumGet(NumGet(IFileSaveDialog)+3*A_PtrSize), "UPtr", IFileSaveDialog, "Ptr", Owner, "UInt") )
    {
        ; IFileDialog::GetResult method
        ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb775964(v=vs.85).aspx
        if ( !DllCall(NumGet(NumGet(IFileSaveDialog)+20*A_PtrSize), "UPtr", IFileSaveDialog, "UPtrP", IShellItem) )
        {
            DllCall("Shell32.dll\SHGetIDListFromObject", "UPtr", 0*VarSetCapacity(Result,32767*2, 0)+IShellItem, "UPtrP", PIDL)
            DllCall("Shell32.dll\SHGetPathFromIDListEx", "UPtr", PIDL, "Str", Result, "UInt", 32767, "UInt", 0)
            ObjRawSet(Obj, IShellItem, PIDL)
        }
    }


    for foo, bar in Obj    ; foo = IShellItem interface (ptr)  |  bar = PIDL structure (ptr)
        if ( foo is "integer" )    ; IShellItem?
            ObjRelease(foo), DllCall("Ole32.dll\CoTaskMemFree", "UPtr", bar)
    ObjRelease(IFileSaveDialog)

    return Result
}





Muestra un diálogo para seleccionar un archivo
GitHub: https://github.com/flipeador/AutoHotkey ... seFile.ahk
Image

Code: Select all

/*
    Muestra un diálogo para seleccionar un archivo.
    Parámetros:
        Owner / Title:
            El identificador de la ventana propietaria de este diálogo. Este valor puede ser cero.
            Un Array con el identificador de la ventana propietaria y el título. Si el título es una cadena vacía se establece al por defecto "Abrir".
        FileName:
            La ruta al archivo o directorio seleccioado por defecto. Si especifica un directorio, éste debe terminar con una barra invertida.
        Filter:
            Especifica un filtro de archivos. Debe especificar un objeto, cada clave representa la descripción y el valor los tipos de archivos.
            Para especificar el filtro seleccionado por defecto, agrege el caracter "`n" al valor de la clave.
        CustomPlaces:
            Especifica un Array con los directorios personalizados que se mostrarán en el panel izquierdo. Los directorios inexistentes serán omitidos.
            Para especificar la hubicación en la lista, especifique un Array con el directorio y la hubicación de este (0 = Inferior, 1 = Superior).
            Generalmente se suelte utilizar con la opción FOS_HIDEPINNEDPLACES.
        Options:
            Determina el comportamiento del diálogo. Este parámetro debe ser uno o más de los siguientes valores.
                0x00000200 (FOS_ALLOWMULTISELECT) = Permite seleccionar más de un archivo.
                0x00001000    (FOS_FILEMUSTEXIST) = El archivo devuelto debe existir. Este es el valor por defecto.
                0x00040000 (FOS_HIDEPINNEDPLACES) = Ocultar elementos que se muestran de forma predeterminada en el panel de navegación de la vista.
                0x02000000  (FOS_DONTADDTORECENT) = No agregue el elemento que se abre o guarda en la lista de documentos recientes (function SHAddToRecentDocs).
                0x10000000  (FOS_FORCESHOWHIDDEN) = Incluye elementos ocultos y del sistema.
            Puede consultar todos los valores disponibles en https://msdn.microsoft.com/en-us/library/windows/desktop/dn457282(v=vs.85).aspx.
    Return:
        Devuelve 0 si el usuario canceló el diálogo, caso contrario devuelve la ruta del archivo seleccionado.
        Si especificó la opción FOS_ALLOWMULTISELECT y la función tuvo éxito, devuelve un Array con la ruta de los archivos seleccionados.
    Ejemplo:
        Result := ChooseFile( [0, "Título del diálogo - Seleccionar archivo.."]
                            , A_ComSpec
                            , {Todos: "`n*.*", Música: "*.mp3", Imágenes: "*.jpg;*.png", Videos: "*.avi;*.mp4;*.mkv;*.wmp", Documentos: "*.txt"}
                            , [A_WinDir,A_Desktop,A_Temp,A_Startup,A_ProgramFiles]
                            , 0x10000000 | 0x02000000 | 0x00000200 | 0x00001000 )
        If ((List := "") == "" && Result != FALSE)
            For Each, File in Result
                List .= File . "`n"
        MsgBox List
*/
ChooseFile(Owner, FileName := "", Filter := "", CustomPlaces := "", Options := 0x1000)
{
    ; IFileOpenDialog interface
    ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb775834(v=vs.85).aspx
    local IFileOpenDialog := ComObjCreate("{DC1C5A9C-E88A-4DDE-A5A1-60F82A20AEF7}", "{D57C7288-D4AD-4768-BE02-9D969532D960}")
        ,           Title := IsObject(Owner) ? Owner[2] . "" : ""
        ,           Flags := Options     ; FILEOPENDIALOGOPTIONS enumeration (https://msdn.microsoft.com/en-us/library/windows/desktop/dn457282(v=vs.85).aspx)
        ,      IShellItem := PIDL := 0   ; PIDL recibe la dirección de memoria a la estructura ITEMIDLIST que debe ser liberada con la función CoTaskMemFree
        ,             Obj := {COMDLG_FILTERSPEC: ""}, foo := bar := ""
        ,       Directory := FileName
    Owner := IsObject(Owner) ? Owner[1] : (WinExist("ahk_id" . Owner) ? Owner : 0)
    Filter := IsObject(Filter) ? Filter : {"All files": "*.*"}


    if ( FileName != "" )
    {
        if ( InStr(FileName, "\") )
        {
            if !( FileName ~= "\\$" )    ; si «FileName» termina con "\" se trata de una carpeta
            {
                local File := ""
                SplitPath(FileName, File, Directory)
                ; IFileDialog::SetFileName
                ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb775974(v=vs.85).aspx
                DllCall(NumGet(NumGet(IFileOpenDialog)+15*A_PtrSize), "UPtr", IFileOpenDialog, "UPtr", &File)
            }
            
            while ( InStr(Directory,"\") && !DirExist(Directory) )                   ; si el directorio no existe buscamos directorios superiores
                Directory := SubStr(Directory, 1, InStr(Directory, "\",, -1) - 1)    ; recupera el directorio superior
            if ( DirExist(Directory) )
            {
                DllCall("Shell32.dll\SHParseDisplayName", "UPtr", &Directory, "Ptr", 0, "UPtrP", PIDL, "UInt", 0, "UInt", 0)
                DllCall("Shell32.dll\SHCreateShellItem", "Ptr", 0, "Ptr", 0, "UPtr", PIDL, "UPtrP", IShellItem)
                ObjRawSet(Obj, IShellItem, PIDL)
                ; IFileDialog::SetFolder method
                ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb761828(v=vs.85).aspx
                DllCall(NumGet(NumGet(IFileOpenDialog)+12*A_PtrSize), "Ptr", IFileOpenDialog, "UPtr", IShellItem)
            }
        }
        else    ; si «FileName» es únicamente el nombre de un archivo
            DllCall(NumGet(NumGet(IFileOpenDialog)+15*A_PtrSize), "UPtr", IFileOpenDialog, "UPtr", &FileName)
    }
    

    ; COMDLG_FILTERSPEC structure
    ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb773221(v=vs.85).aspx
    local Description := "", FileTypes := "", FileTypeIndex := 1
    ObjSetCapacity(Obj, "COMDLG_FILTERSPEC", 2*Filter.Count() * A_PtrSize)
    for Description, FileTypes in Filter
    {
        FileTypeIndex := InStr(FileTypes,"`n") ? A_Index : FileTypeIndex
        ObjRawSet(Obj, "#" . A_Index, Trim(Description)), ObjRawSet(Obj, "@" . A_Index, Trim(StrReplace(FileTypes,"`n")))
        NumPut(ObjGetAddress(Obj,"#" . A_Index), ObjGetAddress(Obj,"COMDLG_FILTERSPEC") + A_PtrSize * 2*(A_Index-1))        ; COMDLG_FILTERSPEC.pszName
        NumPut(ObjGetAddress(Obj,"@" . A_Index), ObjGetAddress(Obj,"COMDLG_FILTERSPEC") + A_PtrSize * (2*(A_Index-1)+1))    ; COMDLG_FILTERSPEC.pszSpec
    }

    ; IFileDialog::SetFileTypes method
    ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb775980(v=vs.85).aspx
    DllCall(NumGet(NumGet(IFileOpenDialog)+4*A_PtrSize), "UPtr", IFileOpenDialog, "UInt", Filter.Count(), "UPtr", ObjGetAddress(Obj,"COMDLG_FILTERSPEC"))

    ; IFileDialog::SetFileTypeIndex method
    ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb775978(v=vs.85).aspx
    DllCall(NumGet(NumGet(IFileOpenDialog)+5*A_PtrSize), "UPtr", IFileOpenDialog, "UInt", FileTypeIndex)

    
    if ( IsObject(CustomPlaces := IsObject(CustomPlaces) || CustomPlaces == "" ? CustomPlaces : [CustomPlaces]) )
    {
        local Directory := ""
        for foo, Directory in CustomPlaces    ; foo = index
        {
            foo := IsObject(Directory) ? Directory[2] : 0    ; FDAP enumeration (https://msdn.microsoft.com/en-us/library/windows/desktop/bb762502(v=vs.85).aspx)
            if ( DirExist(Directory := IsObject(Directory) ? Directory[1] : Directory) )
            {
                DllCall("Shell32.dll\SHParseDisplayName", "UPtr", &Directory, "Ptr", 0, "UPtrP", PIDL, "UInt", 0, "UInt", 0)
                DllCall("Shell32.dll\SHCreateShellItem", "Ptr", 0, "Ptr", 0, "UPtr", PIDL, "UPtrP", IShellItem)
                ObjRawSet(Obj, IShellItem, PIDL)
                ; IFileDialog::AddPlace method
                ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb775946(v=vs.85).aspx
                DllCall(NumGet(NumGet(IFileOpenDialog)+21*A_PtrSize), "UPtr", IFileOpenDialog, "UPtr", IShellItem, "UInt", foo)
            }
        }
    }


    ; IFileDialog::SetTitle method
    ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb761834(v=vs.85).aspx
    DllCall(NumGet(NumGet(IFileOpenDialog)+17*A_PtrSize), "UPtr", IFileOpenDialog, "UPtr", Title == "" ? 0 : &Title)

    ; IFileDialog::SetOptions method
    ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb761832(v=vs.85).aspx
    DllCall(NumGet(NumGet(IFileOpenDialog)+9*A_PtrSize), "UPtr", IFileOpenDialog, "UInt", Flags)


    ; IModalWindow::Show method
    ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb761688(v=vs.85).aspx
    local Result := []
    if ( !DllCall(NumGet(NumGet(IFileOpenDialog)+3*A_PtrSize), "UPtr", IFileOpenDialog, "Ptr", Owner, "UInt") )
    {
        ; IFileOpenDialog::GetResults method
        ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb775831(v=vs.85).aspx
        local IShellItemArray := 0    ; IShellItemArray interface (https://msdn.microsoft.com/en-us/library/windows/desktop/bb761106(v=vs.85).aspx)
        DllCall(NumGet(NumGet(IFileOpenDialog)+27*A_PtrSize), "UPtr", IFileOpenDialog, "UPtrP", IShellItemArray)

        ; IShellItemArray::GetCount method
        ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb761098(v=vs.85).aspx
        local Count := 0    ; pdwNumItems
        DllCall(NumGet(NumGet(IShellItemArray)+7*A_PtrSize), "UPtr", IShellItemArray, "UIntP", Count, "UInt")

        local Buffer := ""
        loop ( 0*VarSetCapacity(Buffer, 32767 * 2) + Count )
        {
            ; IShellItemArray::GetItemAt method
            ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb761100(v=vs.85).aspx
            DllCall(NumGet(NumGet(IShellItemArray)+8*A_PtrSize), "UPtr", IShellItemArray, "UInt", A_Index-1, "UPtrP", IShellItem)
            DllCall("Shell32.dll\SHGetIDListFromObject", "UPtr", IShellItem, "UPtrP", PIDL)
            DllCall("Shell32.dll\SHGetPathFromIDListEx", "UPtr", PIDL, "Str", Buffer, "UInt", 32767, "UInt", 0)
            ObjRawSet(Obj, IShellItem, PIDL), ObjPush(Result, Buffer)
        }

        ObjRelease(IShellItemArray)
    }


    for foo, bar in Obj    ; foo = IShellItem interface (ptr)  |  bar = PIDL structure (ptr)
        if ( foo is "integer" )    ; IShellItem?
            ObjRelease(foo), DllCall("Ole32.dll\CoTaskMemFree", "UPtr", bar)
    ObjRelease(IFileOpenDialog)

    return ObjLength(Result) ? (Options & 0x200 ? Result : Result[1]) : FALSE
}





Muestra un diálogo para seleccionar una carpeta
GitHub: https://github.com/flipeador/AutoHotkey ... Folder.ahk
Image

Code: Select all

/*
    Muestra un diálogo para seleccionar una carpeta.
    Parámetros:
        Owner / Title:
            El identificador de la ventana propietaria de este diálogo. Este valor puede ser cero.
            Un Array con el identificador de la ventana propietaria y el título. Si el título es una cadena vacía se establece al por defecto "Seleccionar carpeta".
        StartingFolder:
            La ruta al directorio seleccioado por defecto. Si el directorio no existe, busca en directorios superiores.
        CustomPlaces:
            Especifica un Array con los directorios personalizados que se mostrarán en el panel izquierdo. Los directorios inexistentes serán omitidos.
            Para especificar la hubicación en la lista, especifique un Array con el directorio y la hubicación de este (0 = Inferior, 1 = Superior).
            Generalmente se suelte utilizar con la opción FOS_HIDEPINNEDPLACES.
        Options:
            Determina el comportamiento del diálogo. Este parámetro debe ser uno o más de los siguientes valores.
            0x00000200 (FOS_ALLOWMULTISELECT) = Permite seleccionar más de un directorio.
            0x00040000 (FOS_HIDEPINNEDPLACES) = Ocultar elementos que se muestran de forma predeterminada en el panel de navegación de la vista.
            0x02000000  (FOS_DONTADDTORECENT) = No agregua el elemento que se abre o guarda en la lista de documentos recientes (función SHAddToRecentDocs).
            0x10000000  (FOS_FORCESHOWHIDDEN) = Incluye elementos ocultos y del sistema.
            Puede consultar todos los valores disponibles en https://msdn.microsoft.com/en-us/library/windows/desktop/dn457282(v=vs.85).aspx.
    Return:
        Devuelve 0 si el usuario canceló el diálogo, caso contrario devuelve la ruta del directorio seleccionado. El directorio nunca termina con "\".
        Si especificó la opción FOS_ALLOWMULTISELECT y la función tuvo éxito, devuelve un Array con la ruta de los directorios seleccionados.
    Ejemplo:
        Result := ChooseFolder( [0, "Título del diálogo - Seleccionar carpeta.."]
                              , A_WinDir . "\System32\Non-existent folder\Carpeta inexistente"
                              , [A_WinDir,A_Desktop,A_Temp,A_Startup,A_ProgramFiles]
                              , 0x10000000 | 0x02000000 | 0x00000200 )
        List := ""
        For Each, Directory in Result
            List .= Directory . "`n"
        MsgBox List
*/
ChooseFolder(Owner, StartingFolder := "", CustomPlaces := "", Options := 0)
{
    ; IFileOpenDialog interface
    ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb775834(v=vs.85).aspx
    local IFileOpenDialog := ComObjCreate("{DC1C5A9C-E88A-4DDE-A5A1-60F82A20AEF7}", "{D57C7288-D4AD-4768-BE02-9D969532D960}")
        ,           Title := IsObject(Owner) ? Owner[2] . "" : ""
        ,           Flags := 0x20 | Options    ; FILEOPENDIALOGOPTIONS enumeration (https://msdn.microsoft.com/en-us/library/windows/desktop/dn457282(v=vs.85).aspx)
        ,      IShellItem := PIDL := 0         ; PIDL recibe la dirección de memoria a la estructura ITEMIDLIST que debe ser liberada con la función CoTaskMemFree
        ,             Obj := {}, foo := bar := ""
    Owner := IsObject(Owner) ? Owner[1] : (WinExist("ahk_id" . Owner) ? Owner : 0)
    CustomPlaces := IsObject(CustomPlaces) || CustomPlaces == "" ? CustomPlaces : [CustomPlaces]


    while (InStr(StartingFolder, "\") && !DirExist(StartingFolder))    ; si el directorio no existe buscamos directorios superiores
        StartingFolder := SubStr(StartingFolder, 1, InStr(StartingFolder, "\",, -1) - 1)
    if ( DirExist(StartingFolder) )
    {
        DllCall("Shell32.dll\SHParseDisplayName", "UPtr", &StartingFolder, "Ptr", 0, "UPtrP", PIDL, "UInt", 0, "UInt", 0)
        DllCall("Shell32.dll\SHCreateShellItem", "Ptr", 0, "Ptr", 0, "UPtr", PIDL, "UPtrP", IShellItem)
        ObjRawSet(Obj, IShellItem, PIDL)    ; guardamos la interfaz «IShellItem» y la estructura «PIDL» para liberarlas al final
        ; IFileDialog::SetFolder method
        ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb761828(v=vs.85).aspx
        DllCall(NumGet(NumGet(IFileOpenDialog)+12*A_PtrSize), "Ptr", IFileOpenDialog, "UPtr", IShellItem)
    }


    if ( IsObject(CustomPlaces) )
    {
        local Directory := ""
        For foo, Directory in CustomPlaces    ; foo = index
        {
            foo := IsObject(Directory) ? Directory[2] : 0    ; FDAP enumeration (https://msdn.microsoft.com/en-us/library/windows/desktop/bb762502(v=vs.85).aspx)
            if ( DirExist(Directory := IsObject(Directory) ? Directory[1] : Directory) )
            {
                DllCall("Shell32.dll\SHParseDisplayName", "UPtr", &Directory, "Ptr", 0, "UPtrP", PIDL, "UInt", 0, "UInt", 0)
                DllCall("Shell32.dll\SHCreateShellItem", "Ptr", 0, "Ptr", 0, "UPtr", PIDL, "UPtrP", IShellItem)
                ObjRawSet(Obj, IShellItem, PIDL)
                ; IFileDialog::AddPlace method
                ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb775946(v=vs.85).aspx
                DllCall(NumGet(NumGet(IFileOpenDialog)+21*A_PtrSize), "UPtr", IFileOpenDialog, "UPtr", IShellItem, "UInt", foo)
            }
        }
    }


    ; IFileDialog::SetTitle method
    ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb761834(v=vs.85).aspx
    DllCall(NumGet(NumGet(IFileOpenDialog)+17*A_PtrSize), "UPtr", IFileOpenDialog, "UPtr", Title == "" ? 0 : &Title)

    ; IFileDialog::SetOptions method
    ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb761832(v=vs.85).aspx
    DllCall(NumGet(NumGet(IFileOpenDialog)+9*A_PtrSize), "UPtr", IFileOpenDialog, "UInt", Flags)


    ; IModalWindow::Show method
    ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb761688(v=vs.85).aspx
    local Result := []
    if ( !DllCall(NumGet(NumGet(IFileOpenDialog)+3*A_PtrSize), "UPtr", IFileOpenDialog, "Ptr", Owner, "UInt") )
    {
        ; IFileOpenDialog::GetResults method
        ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb775831(v=vs.85).aspx
        local IShellItemArray := 0    ; IShellItemArray interface (https://msdn.microsoft.com/en-us/library/windows/desktop/bb761106(v=vs.85).aspx)
        DllCall(NumGet(NumGet(IFileOpenDialog)+27*A_PtrSize), "UPtr", IFileOpenDialog, "UPtrP", IShellItemArray)

        ; IShellItemArray::GetCount method
        ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb761098(v=vs.85).aspx
        local Count := 0    ; pdwNumItems
        DllCall(NumGet(NumGet(IShellItemArray)+7*A_PtrSize), "UPtr", IShellItemArray, "UIntP", Count)

        local Buffer := ""
        loop ( 0*VarSetCapacity(Buffer,32767 * 2) + Count )
        {
            ; IShellItemArray::GetItemAt method
            ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb761100(v=vs.85).aspx
            DllCall(NumGet(NumGet(IShellItemArray)+8*A_PtrSize), "UPtr", IShellItemArray, "UInt", A_Index-1, "UPtrP", IShellItem)
            DllCall("Shell32.dll\SHGetIDListFromObject", "UPtr", IShellItem, "UPtrP", PIDL)
            DllCall("Shell32.dll\SHGetPathFromIDListEx", "UPtr", PIDL, "Str", Buffer, "UInt", 32767, "UInt", 0)
            ObjRawSet(Obj, IShellItem, PIDL), ObjPush(Result, RTrim(Buffer, "\"))
        }

        ObjRelease(IShellItemArray)
    }


    for foo, bar in Obj    ; foo = IShellItem interface (ptr)  |  bar = PIDL structure (ptr)
        ObjRelease(foo), DllCall("Ole32.dll\CoTaskMemFree", "UPtr", bar)
    ObjRelease(IFileOpenDialog)

    return ObjLength(Result) ? ( Options & 0x200 ? Result : Result[1] ) : FALSE
}





Muestra un diálogo para pedirle al usuario que ingrese una cadena
Image

Code: Select all

#Include ..\Gdi\ImageButton.ahk

/*
Muestra un diálogo para pedirle al usuario que ingrese una cadena.
Parámetros:
    Owner: El identificador de la ventana propietaria de este diálogo. Este valor puede ser cero.
    Title: El título de la ventana.
    Prompt: El Texto que suele ser un mensaje al usuario indicando que tipo de "cosa" se espera que introduzca. Este es un control 'Link'.
    Default: El texto que aparecerá por defecto. Este es un control 'Edit'.
    Options: Opciones para este diálogo. Este parámetro debe ser una cadena con una o más de las siguientes palabras:
        xN / yN / wN / hN    = Las coordenadas y dimenciones de la ventana. Si no se especifica, se calcula automáticamente.
        NoPrompt             = Reemplaza el control 'Link' de Prompt y el control Edit de 'Default' por un control Edit multi-línea.
        Number               = Limita el texto que el usuario puede introducir a solo números.
        Password             = Utiliza el modo contraseña.
        ReadOnly             = Establece el control Edit a solo-lectura.
Return: Si tuvo éxito y el usuario aceptó el diálogo devuelve el texto introducido por el usuario, caso contrario devuelve una cadena vacía.
ErrorLevel: Si el usuario aceptó el diálogo se establece en 0, caso contrario se establece en 1. Si hubo un error se establece en 2.
*/
InputBox(Owner := 0, Title := "", Prompt := "", Default := "", Options := "")
{
    X               := RegExMatch(Options, "i)X([\-\d\.]+)(p*)", t) ? " x" . t.1  : ""
    Y               := RegExMatch(Options, "i)Y([\-\d\.]+)(p*)", t) ? " y" . t.1  : ""
    W               := RegExMatch(Options, "i)W([\-\d\.]+)(p*)", t) ? t.1         : SysGet(78) // 100 * 40 ;W: 40%
    H               := RegExMatch(Options, "i)H([\-\d\.]+)(p*)", t) ? t.1         : SysGet(79) // 100 * 37 ;H: 37%
    Number          := InStr(Options, "Number")                     ? " Number"   : ""
    Password        := InStr(Options, "Password")                   ? " Password" : ""
    ReadOnly        := InStr(Options, "ReadOnly")                   ? " ReadOnly" : ""
    ButtonStyle     := [[0, 0x7E8DB6, "Black", 0x242424, 2, 0x282828, 0x242424, 1], [5, 0x8392B8, 0x98A5C5, 0x242424, 2, 0x282828, 0x242424, 1], [5, 0x8392B8, 0xA9B5CF, 0x242424, 2, 0x282828, 0x242424, 1], [0, 0xCCCCCC, "Black", 0x4A4A4A, 2, 0x282828, 0xA7B7C9, 1], [0, 0x7E8DB6, "Black", 0x242424, 2, 0x282828, 0x404040, 2], [5, 0x8392B8, 0x98A5C5, 0x242424, 2, 0x282828, 0x242424, 1]]

    If (Owner)
    {
        WinGetPos(nX, nY, nW, nH, "ahk_id" . Owner)
        If (ErrorLevel)
        {
            ErrorLevel := 2
            Return ("")
        }

        nX += 5, nY += 1

        If (X == "")
            X := " x" . (nX+W > SysGet(78) ? SysGet(78) - W : nX)
        If (Y == "")
            Y := " y" . (nY+H > SysGet(79) ? SysGet(79) - H : nY)
    }

    ;Create GUI
    g               := GuiCreate("-ToolWindow" . (Owner ? " +Owner" . Owner : ""), Title)
    g.BackColor     := 0x282828 ;Background color: Dark

    g.SetFont("s10 Italic q5", "Segoe UI")

    if (InStr(Options, "NoPrompt"))
        oEdit       := g.AddEdit("x5 y5 w" . (W-10) . " h" . (H-40) . " WantTab T8 -Wrap c0x8694B9 Background0x282828 Multi HScroll -E0x200 Border" . ReadOnly)
    Else
    {
        oInfo       := g.AddText("x5 y5 w" . (W-10) . " h" . H-65 . " c0x8694B9 BackgroundTrans", Prompt)
        oEdit       := g.AddEdit("x5 y" . (H-60) . " w" . (W-10) . " h25 WantTab T8 c0x8694B9 Background0x282828 -Multi -E0x200 Border" . ReadOnly . Number . Password, Default)
        DllCall("User32.dll\SendMessageW", "Ptr", oEdit.hWnd, "UInt", 0x1501, "Int", TRUE, "Str", Default) ;EM_SETCUEBANNER
    }

    oCancel         := g.AddButton("x" . (W-105) . " y" . (H-30) . " w100 h25", "Cancelar")
    ImageButton.Create(oCancel.hWnd, ButtonStyle*)

    oAccept         := g.AddButton("x" . (W-210) . " y" . (H-30) . " w100 h25 Default", "Aceptar")
    ImageButton.Create(oAccept.hWnd, ButtonStyle*)

    ;Show GUI
    g.Show(x . y . " w" . W . " h" . H)

    ;Set Events
    Data            := {Text: "", Error: TRUE, g: g, oEdit: oEdit}
    g.OnEvent("Close", Func("InputBox_Close").Bind(Data, TRUE))
    g.OnEvent("Escape", Func("InputBox_Close").Bind(Data, TRUE))
    oCancel.OnEvent("Click", Func("InputBox_Close").Bind(Data, TRUE))
    oAccept.OnEvent("Click", Func("InputBox_Close").Bind(Data, FALSE))

    ;Wait... and return
    WinWaitClose("ahk_id " . g.hWnd)
    ErrorLevel      := Data.Error
    Return (ErrorLevel ? "" : Data.Text)
}

InputBox_Close(Data, Error)
{
    If (!(Data.Error := Error))
        Data.Text := Data.oEdit.Text
    Data.g.Destroy()
}





Crea una ventana de mensaje cerca del icono de la bandeja o área de notificación
GitHub: https://github.com/flipeador/AutoHotkey ... yTipEx.ahk
Image

Image

Code: Select all

#Include ImageButton.ahk

/*
    Crea una ventana de mensaje cerca del icono de la bandeja o área de notificación.
    Parámetros:
        Title  : El título a mostrar en el diálogo.
        Message: El mensaje para el usuario.
        Icon   : El icono a mostrar. Puede ser la ruta a un archivo o el identificador a un icono o bitmap.
        Options: Especifica una cadena con una o más de las palabras claves descritas a continuación.
            wN / hN  = Las dimensiones de la ventana. Si no se especifica, se calcula automáticamente.
            IconN    = Si se especifica un archivo que contiene iconos en “Icon”, especifica el índice. Por defecto es 1.
            tN       = El tiempo, en milisegundos, que deben pasar para que la ventana se destruya automáticamente. Por defecto no se establece.
            OwnerN   = El identificador de la ventana propietaria. Por defecto es 0.
    Observaciones:
        Si se especifico un tiempo fuera, la ventana no será destruida en caso de que el cursor se encuentre sobre ella.
    Ejemplo:
        TrayTipEx('TrayTipEx Window Title! #1', '<A HREF="https://autohotkey.com">Visita AutoHotkey.com</A>', A_WinDir . '\explorer.exe')
        TrayTipEx('TrayTipEx Window Title! #2', 'TrayTipEx Window Text!.', A_WinDir . '\regedit.exe', 't3')
        TrayTipEx('TrayTipEx Window Title! #3', 'TrayTipEx Window Text!.', A_ComSpec)
*/
TrayTipEx(Title, Message, Icon := '', Options := '')
{
    Static TrayTips := {}    ; almacena todos los TrayTips activos, la clave es el identificador de la ventana y su valor el objeto GUI

    ; sumamos el alto de todas las ventanas TrayTips existentes +2xC/U para luego calcular la posición «Y» de la nueva ventana TrayTip para que no tape a las ya existentes
    Local X := 0, Y := 0
    For WindowId, GuiObj in TrayTips
        Y += GuiObj.ClientPos.H + 2    ; 2 = separación vertical entre cada ventana TrayTip

    ; comprobamos el parámetro «Icon»
    Local HICON := Icon is 'Number' ? Icon : 0
    If (!HICON && (!FileExist(Icon) || DirExist(Icon)))
        Icon := A_IsCompiled ? A_ScriptFullPath : A_AhkPath

    ; recuperamos las opciones
    Local M
        , W         := RegExMatch(Options, 'i)W([\-\d\.]+)(p*)'    , M) ? M[1]            : SysGet(78) // 100 * 40    ; 40% del ancho total
        , H         := RegExMatch(Options, 'i)H([\-\d\.]+)(p*)'    , M) ? M[1]            : SysGet(79) // 100 * 15    ; 15% del alto total
        , Timeout   := RegExMatch(Options, 'i)T([\-\d\.]+)(p*)'    , M) ? M[1]            : 0                         ; el tiempo fuera | 0 = sin
        , IconIndex := RegExMatch(Options, 'i)Icon([\-\d\.]+)(p*)' , M) ? M[1]            : 1                         ; el índice del icono
        , Owner     := RegExMatch(Options, 'i)Owner([\-\d\.]+)(p*)', M) ? ' Owner' . M[1] : ''                        ; el identificador de la ventana propietaria
    Local ImageType := HICON ? (DllCall('Gdi32.dll\GetObjectType', 'Ptr', HICON, 'UInt') == 7 ? 'HBITMAP' : 'HICON') : ''    ; OBJ_BITMAP = 7
    IconIndex := HICON ? '' : ' Icon' . IconIndex

    ; creamos el GUI | nuestra nueva ventana TrayTip :) 
    Local Gui := GuiCreate('-DPIScale +ToolWindow -Caption +AlwaysOnTop' . Owner, '')
    TrayTips[Gui.Hwnd] := Gui    ; añadimos el GUI a la lista
    Gui.BackColor := 0x161616    ; el color de fondo (oscuro =D)
    Gui.SetFont('s9 q5', 'Segoe UI')    ; cambiamos la fuente
    Gui.AddPic('x8 y8 w70 h70 vpic' . IconIndex, HICON ? '*' . ImageType . ':' . HICON : Icon)    ; añadimos la imagen/icono a mostrar
    Gui.AddLink('x87 y32 w' . (W-51) . ' h' . (H-30) . ' vmsg c0xFFFFFF', Trim(Message, '`r`n`t '))    ; añadimos el mansaje para el usuario
    Gui.AddButton('x' . (W-25) . ' y2 w24 h24 vx', 'X')
    ImageButton.Create(Gui.Control['x'].Hwnd, [0, 0x161616,  'Black', 0xDFDFFF, 2, 0x161616, 0x161616, 1]
                                            , [0, 0x161616, 0x3C3C3C, 0xFF0000, 2, 0x161616, 0x161616, 1]
                                            , [0, 0x161616, 0x464646, 0xFF0000, 2, 0x161616, 0x161616, 1]
                                            , [0, 0xCCCCCC,  'Black', 0x4A4A4A, 2, 0x161616, 0xA7B7C9, 1]
                                            , [0, 0x161616,  'Black', 0xDFDFFF, 2, 0x161616, 0x161616, 2]
                                            , [0, 0x161616,  'Black', 0xFF0000, 2, 0x161616, 0x161616, 1] )    ; establecemos el estilo del botón cerrar X
    Gui.AddText('x1 y1 w' . (W-1) . ' h' . (H-1) . ' Border BackGroundTrans')    ; añadimos un fino borde a la ventana
    Gui.SetFont('s10 Bold', 'Segoe Print')    ; cambiamos la fuente
    Gui.AddText('x87 y8 w' . (W-125) . ' h22 c0x0080FF', Trim(Title))    ; añadimos el título

    SoundPlay(A_WinDir . '\media\notify.wav')    ; reproducimos un sonido para alertar al usuario del TrayTip

    ; recuperamos las dimensiones del monitor donde se visualiza la ventana TrayTip y las utilizamos para ajustar las coordenadas X,Y
    Local MONITORINFO
    NumPut(VarSetCapacity(MONITORINFO, 40, 0), &MONITORINFO, "UInt")
    DllCall('User32.dll\GetMonitorInfoW', 'Ptr', DllCall('User32.dll\MonitorFromWindow', 'Ptr', Gui.Hwnd, 'UInt', 2, 'Ptr'), 'Ptr', &MONITORINFO)
    Local W2 := NumGet(&MONITORINFO + 28, 'Int')
        , H2 := NumGet(&MONITORINFO + 32, 'Int')
    X := W2 - W - 5, Y := H2 - H - 5 - Y

    Gui.Show('x' . X . ' y' . Y . ' w' . W . ' h' . H . ' Hide')    ; establecemos la posición y dimensiones de la ventana TrayTip
    DllCall('User32.dll\AnimateWindow', 'Ptr', Gui.Hwnd, 'UInt', 500, 'UInt', 0xA0000)    ; mostramos la ventana con una animación de 500 milisegundos
    WinSetRegion('1-1 w' . W . ' h' . H . ' r6-6', 'ahk_id' . Gui.Hwnd)    ; redondeamos las puntas de la ventana
    WinSetTransparent(240, "ahk_Id" . Gui.Hwnd)    ; añadimos un poco de transparencia a la ventana (WINAPI::AnimateWindow no funciona bien si la ventana es transparente)
    WinRedraw('ahk_Id' . Gui.Hwnd)    ; redibujamos toda la ventana ya que la función WINAPI::AnimateWindow a veces causa que los controles se visualizen mal

    ; establecemos datos comunes que serán pasados a las funciónes asociadas a la ventana TrayTip
    Local Data := {TrayTips: TrayTips, Gui: Gui, TimeoutFunc: 0, X: X, H: H2}

    ; establecemos el tiempo fuera, si se especificó
    If (Timeout)
        SetTimer(Data.TimeoutFunc := Func('TrayTipEx_Timeout').Bind(Data), Timeout * -1000)
    
    ; establecemos algunos eventos de la ventana y controles
    Gui.OnEvent('Close', Func('TrayTipEx_Close').Bind(Data))    ; al cerrar la ventana
    Gui.Control['X'].OnEvent('Click', Func('TrayTipEx_Close').Bind(Data))    ; al cerrar la ventana desde el botón X
    Gui.Control['pic'].OnEvent('Click', 'TrayTipEx_Move')    ; permite mover la ventana arrastrando la imagen/icono
    
    ; devolvemos el objeto GUI
    Return Gui
}

TrayTipEx_Move(CtrlObj)
{
    DllCall('User32.dll\PostMessageW', 'Ptr', CtrlObj.Gui.Hwnd, 'UInt', 0x00A1, 'UInt', 2, 'Ptr', 0)    ; permite mover la ventana arrastrando el control especificado (CtrlObj::pic)
}

TrayTipEx_Timeout(Data)
{
    Try    ; evitamos un mensaje de error si el objeto GUI ya no es válido
    {
        Local WindowId    ; almacena el identificador de la ventana bajo el cursor
        Loop    ; evitamos cerrar la ventana si el cursor se encuentra sobre ella con un retraso de 500 milisegundos
            MouseGetPos(,, WindowId), Sleep(A_Index > 1 ? 500 : 0)    ; recupera el identificador de la ventana bajo el cursor y espera 500 milisegundos (a partir de la segunda iteración)
        Until (Data.TimeoutFunc == 0 || WindowId != Data.Gui.Hwnd)
    }

    If (IsObject(Data.TimeoutFunc))    ; solo llamamos a TrayTipEx_Close si ya no se ha llamado antes para esta ventana
        TrayTipEx_Close(Data)    ; cerramos la ventana
}

TrayTipEx_Close(Data)    ; EN FUTURAS ACTUALIZACIÓNES SE MEJORARÁ EL ALGORITMO PARA RE-UBICAR LAS VENTANAS TRAYTIPS AL ELIMINAR UNA
{
    Critical    ; previene que el thread actual sea interrumpido por otro, esto evita mensajes de error al manipular el objeto GUI
    If (IsObject(Data.TimeoutFunc))    ; al cerrar la ventana, comprobamos si se ha establecido un tiempo fuera, si es así, lo eliminamos y liberamos el objeto Func()
        SetTimer(Data.TimeoutFunc, 'Delete'), Data.TimeoutFunc := 0
    
    Data.TrayTips.Delete(Data.Gui.Hwnd)    ; eliminamos esta ventana de la lista de TrayTips
    Try    ; evitamos mostrar un error si la ventana ya ha sido destruida
    {
        Data.Gui.BackColor := 0x252525    ; cambiamos el color de fondo a un color más grisáceo para dar un efecto más agradable al destruir la ventana
        WinSetTransparent('Off', 'ahk_id' . Data.Gui.Hwnd)    ; quitamos la transparencia para evitar el mal funcionamiento de WINAPI::AnimateWindow
        DllCall('User32.dll\AnimateWindow', 'Ptr', Data.Gui.Hwnd, 'UInt', 500, 'UInt', 0x90000)    ; ocultamos la ventana con una animación de 500 milisegundos
        Data.Gui.Destroy()    ; destruimos la ventana
    }

    ; ................................................................................................................................................
    ; NOTA! ACTUALMENTE EL ORDENAMIENTO NO TIENE SENTIDO, EN FUTURAS ACTUALIZACIONES SE MEJORARÁ EL ALGORITMO UTILIZADO AQUÍ ABAJO
    ; ................................................................................................................................................
    Local TrayTips := []    ; almacenará una la lista ordenada de los TrayTips existentes, de abajo hacia arriba
    For WindowId, Gui in Data.TrayTips    ; añadimos todos los identificadores al array TrayTips
        ObjPush(TrayTips, WindowId)
    If (ObjLength(TrayTips) == 0)    ; si no se han encontrado mas TrayTips terminamos
        Return

    ; ordena la lista de los TrayTips existentes, de arriba hacia abajo
    Local WindowId
    Loop (ObjLength(TrayTips))
        Loop (ObjLength(TrayTips))
            If (A_Index > 1 && Data.TrayTips[TrayTips[A_Index-1]].ClientPos.Y > Data.TrayTips[TrayTips[A_Index]].ClientPos.Y)
                WindowId := TrayTips[A_Index-1]
              , TrayTips[A_Index-1] := TrayTips[A_Index]
              , TrayTips[A_Index] := WindowId

    ; al eliminar la ventana, debemos acomodar a todas las demás ventanas TrayTips para que alguna, si la hay, ocupe su lugar
    Local NY, Gui, ClientPos, Y := 0
    Loop (ObjLength(TrayTips))
    {
        Gui := Data.TrayTips[TrayTips[A_Index]]    ; recuperamos el objeto GUI
        ClientPos := Gui.ClientPos    ; almacena las dimensiones de la ventana TrayTip actual (sin incluir barra de título y bordes)
        NY := Data.H - 5 - ClientPos.H - Y    ; 'Data.H' contiene la altura del monitor donde se visualizan las ventanas TrayTips para este Script
                                              ; '5' representa el espaciado entre la ventana más próxima a la parte inferior de la pantalla (para que no quede fea pegada con el límite del monitor)
                                              ; 'ClientPos.H' representa la altura de la ventana TrayTip actual en el bucle For
                                              ; 'Y' contiene la suma de la altura de todas las ventanas TrayTips anteriores, para evitar taparlas y acomodarlas correctamente
                                              ; Todo esto da como resultado la posición 'Y' nueva para esta ventana TrayTip que será almacenada en la variable 'NY'
        Loop    ; ajustamos la posición de la ventana moviendola de a 1 pixel para dar un efecto de 'animación'
            Gui.Show('y'  . ((ClientPos.Y > NY)     ? (ClientPos.Y -= 1) : (ClientPos.Y < NY)     ? (ClientPos.Y += 1) : ClientPos.Y)
                   . ' x' . ((ClientPos.X > Data.X) ? (ClientPos.X -= 1) : (ClientPos.X < Data.X) ? (ClientPos.X += 1) : ClientPos.X))
          , Sleep(!Mod(A_Index, 10))    ; retraso (para la 'animación')
        Until (ClientPos.Y == NY && ClientPos.X == Data.X)
        WinRedraw('ahk_id' . Gui.Hwnd)
        Y += ClientPos.H + 2
    }
}
Last edited by Flipeador on 03 Feb 2017, 12:29, edited 30 times in total.
User avatar
Flipeador
Posts: 1204
Joined: 15 Nov 2014, 21:31
Location: Argentina
Contact:

ACTUALIZACIONES!!

19 May 2017, 21:09

La mayoría de las funciones trabajan a partir de Windows Vista, y AHK v2 con la nueva GUI API. Estaré agregando más diálogos...
Actualización 23/07/2017!:
  • Todos las funciones han sido reescritas por completo.
  • He eliminado los dos temas aparte que tenía sobre InputBoxEx, TrayTipEx y TaskDialok y los he puesto todos juntos aquí mismo.
  • Ahora InputBoxEx y ChooseImage tienen una interfaz oscura.

Actualización 08/03/2018!:
  • La función TaskDialog ha sido reescrita.
  • La función TrayTip2 ha sido reescrita y renombrada a TrayTipEx (en la próxima actualización se mejorará el algoritmo al momento de cerrar un TrayTip y re-posicionar los demás).

[27/04/2018] Se reescribieron las funciones SaveFile, ChooseFile y ChooseDir (ésta última fue renombrada a ChooseFolder).
Nota 31/03/2018: Debido a los cambios que se están haciendo en AHKv2, puede que algunas funciones den errores, se irán actualizando y reescribiendo de a poco.
Puede encontrar las funciones ChooseFile, ChooseFolder y SaveFile para v1 en este enlace: https://autohotkey.com/boards/viewtopic ... 36#p231879.

Return to “Scripts y Funciones”

Who is online

Users browsing this forum: No registered users and 15 guests