// EnumerateWindows_functions.js
// http://akelpad.sourceforge.net/forum/viewtopic.php?p=14988#14988
// Version: 2015-01-05
// Author: KDJ
//
// Contains functions:
// EnumTopLevelWindows()
// EnumChildWindows()
//
// Usage in script:
// if (! AkelPad.Include("EnumerateWindows_functions.js")) WScript.Quit();

//----------------------------------------------------------------------------------------------------
// aWndTop = EnumTopLevelWindows(nTitle, nVisible, nMinimized, nMaximized, nSize, nTopMost, nToolWin);
//
// Arguments:
// nTitle     - determines, whether the window contains the title,
// nVisible   - whether the window is visible,
// nMinimized - whether the window is minimized,
// nMaximized - whether the window is maximized,
// nSize      - whether the window have non zero size.
// nTopMost   - whether the window is top-most.
// nToolWin   - whether the window is tool window.
// Arguments can have the following value:
// 0 - no,
// 1 - yes,
// 2 - all windows, argument is ignored.
//
// Return value:
// Array of objects. Each element of array contains information about a single window:
// aWnd[n].Handle    - handle to window (number),
// aWnd[n].Menu      - handle to menu assigned to the window (number),
// aWnd[n].Title     - title of window (string),
// aWnd[n].Visible   - is window visible (bool),
// aWnd[n].Minimized - is window minimized (bool),
// aWnd[n].Maximized - is window maximized (bool),
// aWnd[n].X         - left-top corner x position (number),
// aWnd[n].Y         - left-top corner y position (number),
// aWnd[n].W         - window width (number),
// aWnd[n].H         - window height (number),
// aWnd[n].TopMost   - is window top-most (bool),
// aWnd[n].ToolWin   - is tool window (bool),
// aWnd[n].Class     - name of the window class (string),
// aWnd[n].PID       - identifier of the process, that created the window (number),
// aWnd[n].TID       - identifier of the thread, that created the window (number),
// aWnd[n].FileName  - full file name (with the path) of the process, that created the window (string),
// aWnd[n].BaseName  - file name of the process, that created the window (string).
//-----------------------------------------------------------------------------------------------
function EnumTopLevelWindows(nTitle, nVisible, nMinimized, nMaximized, nSize, nTopMost, nToolWin)
{
  var oSys = AkelPad.SystemFunction();
  var aWnd = [];
  var lpInfo;
  var hMenu;
  var sTitle;
  var bVisible;
  var bMinimized;
  var bMaximized;
  var nX;
  var nY;
  var nW;
  var nH;
  var bTopMost;
  var sClass;
  var nPID;
  var nTID;
  var hProcess;
  var sFileName;
  var sBaseName;

  try
  {
    oSys.RegisterCallback(EnumWindowsProc);
  }
  catch (oError)
  {
    AkelPad.MessageBox(0, 'Unable to register callback function: "EnumWindowsProc".', 'EnumTopLevelWindows', 0x10 /*MB_ICONERROR*/);
    return aWnd;
  }

  lpInfo = AkelPad.MemAlloc(260 * _TSIZE);

  oSys.Call("User32::EnumWindows", EnumWindowsProc, 0);

  oSys.UnregisterCallback(EnumWindowsProc);
  AkelPad.MemFree(lpInfo);

  return aWnd;

  function EnumWindowsProc(hWnd, lParam)
  {
    if (oSys.Call("User32::GetWindowText" + _TCHAR, hWnd, lpInfo, 260))
      sTitle = AkelPad.MemRead(lpInfo, _TSTR);
    else
      sTitle = "";

    hMenu      = oSys.Call("User32::GetMenu", hWnd);
    bVisible   = oSys.Call("User32::IsWindowVisible", hWnd);
    bMinimized = oSys.Call("User32::IsIconic", hWnd);
    bMaximized = oSys.Call("User32::IsZoomed", hWnd);

    if (oSys.Call("User32::GetWindowRect", hWnd, lpInfo))
    {
      nX = AkelPad.MemRead(_PtrAdd(lpInfo,  0), 3 /*DT_DWORD*/);
      nY = AkelPad.MemRead(_PtrAdd(lpInfo,  4), 3 /*DT_DWORD*/);
      nW = AkelPad.MemRead(_PtrAdd(lpInfo,  8), 3 /*DT_DWORD*/) - nX;
      nH = AkelPad.MemRead(_PtrAdd(lpInfo, 12), 3 /*DT_DWORD*/) - nY;
    }
    else
    {
      nX = 0;
      nY = 0;
      nW = 0;
      nH = 0;
    }

    bTopMost = oSys.Call("User32::GetWindowLong" + _TCHAR, hWnd, -20 /*GWL_EXSTYLE*/) & 0x00000008 /*WS_EX_TOPMOST*/;
    bToolWin = oSys.Call("User32::GetWindowLong" + _TCHAR, hWnd, -20 /*GWL_EXSTYLE*/) & 0x00000080 /*WS_EX_TOOLWINDOW*/;

    if (! (((nTitle == 0)     && sTitle)     || ((nTitle == 1)     && (! sTitle)) ||
           ((nVisible == 0)   && bVisible)   || ((nVisible == 1)   && (! bVisible)) ||
           ((nMinimized == 0) && bMinimized) || ((nMinimized == 1) && (! bMinimized)) ||
           ((nMaximized == 0) && bMaximized) || ((nMaximized == 1) && (! bMaximized)) ||
           ((nSize == 0)      && (nW + nH))  || ((nSize == 1)      && (! (nW + nH))) ||
           ((nTopMost == 0)   && bTopMost)   || ((nTopMost == 1)   && (! bTopMost)) ||
           ((nToolWin == 0)   && bToolWin)   || ((nToolWin == 1)   && (! bToolWin))))
    {
      if (oSys.Call("User32::GetClassName" + _TCHAR, hWnd, lpInfo, 260))
        sClass = AkelPad.MemRead(lpInfo, _TSTR);
      else
        sClass = "";

      nTID = oSys.Call("User32::GetWindowThreadProcessId", hWnd, lpInfo);
      nPID = AkelPad.MemRead(lpInfo, 3 /*DT_DWORD*/);

      hProcess = oSys.Call("Kernel32::OpenProcess", 0x0410 /*PROCESS_QUERY_INFORMATION|PROCESS_VM_READ*/, 0, nPID);

      if (oSys.Call("Psapi::GetModuleFileNameEx" + _TCHAR, hProcess, 0, lpInfo, 260))
        sFileName = AkelPad.MemRead(lpInfo, _TSTR);
      else
        sFileName = "<unknown>";

      if (oSys.Call("Psapi::GetModuleBaseName" + _TCHAR, hProcess, 0, lpInfo, 260))
        sBaseName = AkelPad.MemRead(lpInfo, _TSTR);
      else
        sBaseName = "<unknown>";

      oSys.Call("Kernel32::CloseHandle", hProcess);

      aWnd.push({Handle    : hWnd,
                 Menu      : hMenu,
                 Title     : sTitle,
                 Visible   : bVisible,
                 Minimized : bMinimized,
                 Maximized : bMaximized,
                 X         : nX,
                 Y         : nY,
                 W         : nW,
                 H         : nH,
                 TopMost   : bTopMost,
                 ToolWin   : bToolWin,
                 Class     : sClass,
                 PID       : nPID,
                 TID       : nTID,
                 FileName  : sFileName,
                 BaseName  : sBaseName});
    }

    return true;
  }
}

//------------------------------------------
// aWndChild = EnumChildWindows(hWndParent);
//
// Argument:
// hWndParent - handle to the parent window whose child windows are to be enumerated.
//
// Return value:
// Array of objects. Each element of array contains information about a single window:
// aWnd[n].Handle  - handle to window (number),
// aWnd[n].Text    - window text (string),
// aWnd[n].Visible - is window visible (bool),
// aWnd[n].Enabled - is window enabled (bool),
// aWnd[n].X       - left-top corner x position (number),
// aWnd[n].Y       - left-top corner y position (number),
// aWnd[n].W       - window width (number),
// aWnd[n].H       - window height (number),
// aWnd[n].Class   - name of the window class (string),
// aWnd[n].Style   - window style (number),
// aWnd[n].ExStyle - window exstyle (number).
// aWnd[n].ID      - window identifier (number).
//-----------------------------------
function EnumChildWindows(hWndParent)
{
  var oSys = AkelPad.SystemFunction();
  var aWnd = [];
  var lpInfo;
  var sText;
  var nX;
  var nY;
  var nW;
  var nH;
  var sClass;

  try
  {
    oSys.RegisterCallback(EnumChildProc);
  }
  catch (oError)
  {
    AkelPad.MessageBox(0, 'Unable to register callback function: "EnumChildProc".', 'EnumChildWindows', 0x10 /*MB_ICONERROR*/);
    return aWnd;
  }

  lpInfo = AkelPad.MemAlloc(260 * _TSIZE);

  oSys.Call("User32::EnumChildWindows", hWndParent, EnumChildProc, 0);

  oSys.UnregisterCallback(EnumChildProc);
  AkelPad.MemFree(lpInfo);

  return aWnd;

  function EnumChildProc(hWnd, lParam)
  {
    if (AkelPad.SendMessage(hWnd, 0x000D /*WM_GETTEXT*/, 260, lpInfo))
      sText = AkelPad.MemRead(lpInfo, _TSTR);
    else
      sText = "";

    if (oSys.Call("User32::GetWindowRect", hWnd, lpInfo))
    {
      nX = AkelPad.MemRead(_PtrAdd(lpInfo,  0), 3 /*DT_DWORD*/);
      nY = AkelPad.MemRead(_PtrAdd(lpInfo,  4), 3 /*DT_DWORD*/);
      nW = AkelPad.MemRead(_PtrAdd(lpInfo,  8), 3 /*DT_DWORD*/) - nX;
      nH = AkelPad.MemRead(_PtrAdd(lpInfo, 12), 3 /*DT_DWORD*/) - nY;
    }
    else
    {
      nX = 0;
      nY = 0;
      nW = 0;
      nH = 0;
    }

    if (oSys.Call("User32::GetClassName" + _TCHAR, hWnd, lpInfo, 260))
      sClass = AkelPad.MemRead(lpInfo, _TSTR);
    else
      sClass = "";

    aWnd.push({Handle  : hWnd,
               Text    : sText,
               Visible : oSys.Call("User32::IsWindowVisible", hWnd),
               Enabled : oSys.Call("User32::IsWindowEnabled", hWnd),
               X       : nX,
               Y       : nY,
               W       : nW,
               H       : nH,
               Class   : sClass,
               Style   : oSys.Call("User32::GetWindowLong" + _TCHAR, hWnd, -16 /*GWL_STYLE*/),
               ExStyle : oSys.Call("User32::GetWindowLong" + _TCHAR, hWnd, -20 /*GWL_EXSTYLE*/),
               ID      : oSys.Call("User32::GetWindowLong" + _TCHAR, hWnd, -12 /*GWL_ID*/)});

    return true;
  }
}
