// http://akelpad.sourceforge.net/forum/viewtopic.php?p=27171#27171
// Version: 2016-08-05
// Author: KDJ
//
// *** Run command and capture output ***
//
// Run in AkelPad window:
//   Call("Scripts::Main", 1, "RunCommand.js")
// Run from command line (required AkelEdit.dll and registration: regsvr32.exe Scripts.dll):
//   wscript.exe RunCommand.js
//
// Keyboard:
//   F1 - Windows command line list ("CMD ?")
//   F4 - maximize/restore window (also Alt+Enter)
//
// Remark:
//   The script should be saved in Unicode format.

if (typeof AkelPad == "undefined")
{
  try
  {
    AkelPad = new ActiveXObject("AkelPad.Document");
    _PtrAdd = function(n1, n2) {return AkelPad.Global._PtrAdd(n1, n2);};
    _X64    = AkelPad.Constants._X64;
  }
  catch (oError)
  {
    WScript.Echo("You need to register Scripts.dll");
    WScript.Quit();
  }
}

var oSys     = AkelPad.SystemFunction();
var hInstDLL = AkelPad.GetInstanceDll();
var sClass   = "AkelPad::Scripts::" + WScript.ScriptName + "::" + hInstDLL;
var hDlg     = oSys.Call("User32::FindWindowExW", 0, 0, sClass, 0);

if (hDlg)
{
  if (! oSys.Call("User32::IsWindowVisible", hDlg))
    oSys.Call("User32::ShowWindow", hDlg, 8 /*SW_SHOWNA*/);
  if (oSys.Call("User32::IsIconic", hDlg))
    oSys.Call("User32::ShowWindow", hDlg, 9 /*SW_RESTORE*/);

  oSys.Call("User32::SetForegroundWindow", hDlg);
  WScript.Quit();
}

var hMainWnd = AkelPad.GetMainWnd();
var hGuiFont = oSys.Call("Gdi32::GetStockObject", 17 /*DEFAULT_GUI_FONT*/);
var hIconSmall = oSys.Call("User32::LoadImageW",
                   hInstDLL, //hinst
                   101,      //lpszName
                   1,        //uType=IMAGE_ICON
                   16,       //cxDesired
                   16,       //cyDesired
                   0);       //fuLoad
var hIconBig = oSys.Call("User32::LoadImageW",
                 hInstDLL, //hinst
                 101,      //lpszName
                 1,        //uType=IMAGE_ICON
                 32,       //cxDesired
                 32,       //cyDesired
                 0);       //fuLoad
var sAELib;
var hAELib;

if (! hMainWnd)
{
  sAELib = "AkelEdit.dll";
  if (! (hAELib = oSys.Call("Kernel32::LoadLibraryW", AkelPad.GetFilePath(WScript.ScriptFullName, 1 /*CPF_DIR*/) + "\\AkelEdit_" + (_X64 ? "x64\\" : "x86\\") + sAELib)))
  {
    if (! (hAELib = oSys.Call("Kernel32::LoadLibraryW", sAELib)))
    {
      WScript.Echo("Can not load library: " + sAELib);
      WScript.Quit();
    }
  }
}

var Scale =
{
  Init: function()
  {
    var hDC = oSys.Call("User32::GetDC", hMainWnd);
    this.ScaleX = oSys.Call("Gdi32::GetDeviceCaps", hDC, 88 /*LOGPIXELSX*/);
    this.ScaleY = oSys.Call("Gdi32::GetDeviceCaps", hDC, 90 /*LOGPIXELSY*/);
    oSys.Call("User32::ReleaseDC", hMainWnd, hDC);
    //Align to 16 pixel
    this.ScaleX += (16 - this.ScaleX % 16) % 16;
    this.ScaleY += (16 - this.ScaleY % 16) % 16;
  },
  X:  function(n) {return oSys.Call("Kernel32::MulDiv", n, this.ScaleX, 96);},
  Y:  function(n) {return oSys.Call("Kernel32::MulDiv", n, this.ScaleY, 96);},
  UX: function(n) {return oSys.Call("Kernel32::MulDiv", n, 96, this.ScaleX);},
  UY: function(n) {return oSys.Call("Kernel32::MulDiv", n, 96, this.ScaleY);}
}
Scale.Init();

var oFSO      = new ActiveXObject("Scripting.FileSystemObject");
var sCmd      = "";
var sDir      = "";
var sLastFile = "";
var bShowWnd  = 0;
var bFontDef  = 1;
var bColorDef = 1;
var aColor    = [];
var aColorDef = [];
var nHistMax  = 10;
var aHist     = [];
var oRun      = {"hProc": 0, "hThread": 0, "PID": 0, "Stop": 0, EndText: ""};
var aFont;

GetLangStrings();

var IDCMDS = 1000;
var IDDIRS = 1001;
var IDOUTS = 1002;
var IDCMDE = 1003;
var IDDIRE = 1004;
var IDOUTE = 1005;
var IDRUNB = 1006;
var IDCMDB = 1007;
var IDFILB = 1008;
var IDDIRB = 1009;
var IDHISB = 1010;
var IDSETB = 1011;
var aDlg   = [];

aDlg.MinW = Scale.X(475);
aDlg.MinH = Scale.Y(320);
aDlg.X    = 200;
aDlg.Y    = 200;
aDlg.W    = aDlg.MinW;
aDlg.H    = aDlg.MinH;
aDlg.Max  = 0;

aDlg[IDCMDS] = {T: sTxtCommand,  C: "STATIC",    S: 0x50000000 /*WS_CHILD|WS_VISIBLE*/};
aDlg[IDDIRS] = {T: sTxtWorkDir,  C: "STATIC",    S: 0x50000000 /*WS_CHILD|WS_VISIBLE*/};
aDlg[IDOUTS] = {T: sTxtOutput,   C: "STATIC",    S: 0x50000000 /*WS_CHILD|WS_VISIBLE*/};
aDlg[IDCMDE] = {                 C: "AkelEditW", S: 0x50A10000 /*WS_CHILD|WS_VISIBLE|WS_BORDER|WS_VSCROLL|WS_TABSTOP*/};
aDlg[IDDIRE] = {                 C: "AkelEditW", S: 0x50810000 /*WS_CHILD|WS_VISIBLE|WS_BORDER|WS_TABSTOP*/};
aDlg[IDOUTE] = {                 C: "AkelEditW", S: 0x50B10004 /*WS_CHILD|WS_VISIBLE|WS_BORDER|WS_VSCROLL|WS_HSCROLL|WS_TABSTOP|ES_MULTILINE*/};
aDlg[IDRUNB] = {T: sTxtRun,      C: "BUTTON",    S: 0x50000001 /*WS_CHILD|WS_VISIBLE|BS_DEFPUSHBUTTON*/};
aDlg[IDCMDB] = {T: "&CMD ?",     C: "BUTTON",    S: 0x50000000 /*WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON*/};
aDlg[IDFILB] = {T: sTxtFiles,    C: "BUTTON",    S: 0x50000000 /*WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON*/};
aDlg[IDDIRB] = {T: sTxtDirs,     C: "BUTTON",    S: 0x50000000 /*WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON*/};
aDlg[IDHISB] = {T: sTxtHistory,  C: "BUTTON",    S: 0x50000000 /*WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON*/};
aDlg[IDSETB] = {T: sTxtSettings, C: "BUTTON",    S: 0x50000000 /*WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON*/};

ReadIni();

AkelPad.ScriptNoMutex(0x11 /*ULT_LOCKSENDMESSAGE|ULT_UNLOCKSCRIPTSQUEUE*/);
AkelPad.WindowRegisterClass(sClass);

oSys.Call("User32::CreateWindowExW",
  0,               //dwExStyle
  sClass,          //lpClassName
  sTxtDlgTitle,    //lpWindowName
  0x80CF0000,      //dwStyle=WS_POPUP|WS_CAPTION|WS_SYSMENU|WS_SIZEBOX|WS_MINIMIZEBOX|WS_MAXIMIZEBOX
  aDlg.X,          //x
  aDlg.Y,          //y
  aDlg.W,          //nWidth
  aDlg.H,          //nHeight
  hMainWnd,        //hWndParent
  0,               //hMenu
  hInstDLL,        //hInstance
  DialogCallback); //Script function callback. To use it class must be registered by WindowRegisterClass.

oSys.Call("User32::ShowWindow", hDlg, aDlg.Max ? 3 /*SW_MAXIMIZE*/ : 1 /*SW_SHOWNORMAL*/);

AkelPad.WindowGetMessage();
AkelPad.WindowUnregisterClass(sClass);
oSys.Call("Kernel32::FreeLibrary", hAELib);
oSys.Call("User32::DestroyIcon", hIconSmall);
oSys.Call("User32::DestroyIcon", hIconBig);

function DialogCallback(hWnd, uMsg, wParam, lParam)
{
  var nID, nCode, i;

  if (uMsg == 1 /*WM_CREATE*/)
  {
    hDlg = hWnd;
    InitDlg();
  }

  else if (uMsg == 7 /*WM_SETFOCUS*/)
    oSys.Call("User32::SetFocus", oRun.hProc ? aDlg[IDRUNB].HWND : aDlg.Focus);

  else if (uMsg == 36 /*WM_GETMINMAXINFO*/)
  {
    AkelPad.MemCopy(_PtrAdd(lParam, 24), aDlg.MinW, 3 /*DT_DWORD*/); //ptMinTrackSize_x
    AkelPad.MemCopy(_PtrAdd(lParam, 28), aDlg.MinH, 3 /*DT_DWORD*/); //ptMinTrackSize_y
  }

  else if (uMsg == 3 /*WM_MOVE*/)
  {
    if (! (oSys.Call("User32::IsZoomed", hDlg) || oSys.Call("User32::IsIconic", hDlg)))
      GetWindowPos(hDlg, aDlg);
  }

  else if (uMsg == 5 /*WM_SIZE*/)
  {
    if (wParam == 0 /*SIZE_RESTORED*/)
      GetWindowPos(hDlg, aDlg);

    ResizeDlg(LoWord(lParam), HiWord(lParam));
  }

  else if (uMsg == 15 /*WM_PAINT*/)
    PaintSizeGrip();

  else if (uMsg == 256 /*WM_KEYDOWN*/)
  {
    if (wParam == 0x70 /*VK_F1*/)
      CommandList();
    else if (wParam == 0x73 /*VK_F4*/)
      oSys.Call("User32::ShowWindow", hDlg, oSys.Call("User32::IsZoomed", hDlg) ? 9 /*SW_RESTORE*/ : 3 /*SW_MAXIMIZE*/);
    else if (wParam == 13 /*VK_RETURN*/)
    {
      nID = oSys.Call("User32::GetDlgCtrlID", oSys.Call("User32::GetFocus"));
      if (sCmd && (nID >= IDCMDE) && (nID <= IDOUTE))
        PostMessage(hDlg, 273 /*WM_COMMAND*/, IDRUNB, aDlg[IDRUNB].HWND);
    }
  }

  else if (uMsg == 260 /*WM_SYSKEYDOWN*/)
  {
    if (wParam == 13 /*VK_RETURN*/)
      oSys.Call("User32::ShowWindow", hDlg, oSys.Call("User32::IsZoomed", hDlg) ? 9 /*SW_RESTORE*/ : 3 /*SW_MAXIMIZE*/);
  }

  else if (uMsg == 123 /*WM_CONTEXTMENU*/)
  {
    if ((wParam == aDlg[IDCMDE].HWND) || (wParam == aDlg[IDDIRE].HWND) || (wParam == aDlg[IDOUTE].HWND))
      MenuEdit(wParam, LoWord(lParam), HiWord(lParam));
  }

  else if (uMsg == 273 /*WM_COMMAND*/)
  {
    nID   = LoWord(wParam);
    nCode = HiWord(wParam);

    if ((nID >= IDCMDE) && (nID <= IDOUTE))
    {
      if (nCode == 0x0100 /*EN_SETFOCUS*/)
      {
        aDlg.Focus = lParam;
        PostMessage(lParam, 3228 /*AEM_SETOPTIONS*/, 2 /*AECOOP_OR*/, 0x00000800 /*AECO_ACTIVELINE*/);
        PostMessage(aDlg[IDRUNB].HWND, 0xF4 /*BM_SETSTYLE*/, 1 /*BS_DEFPUSHBUTTON*/, 1);
        for (i = IDCMDB; i <= IDSETB; ++i)
          PostMessage(aDlg[i].HWND, 0xF4 /*BM_SETSTYLE*/, 0 /*BS_PUSHBUTTON*/, 1);
      }
      else if (nCode == 0x0200 /*EN_KILLFOCUS*/)
        PostMessage(lParam, 3228 /*AEM_SETOPTIONS*/, 3 /*AECOOP_AND*/, ~0x00000800 /*AECO_ACTIVELINE*/);
      else if (nCode == 0x0300 /*EN_CHANGE*/)
      {
        if (nID == IDCMDE)
        {
          sCmd = GetTextAE(lParam);
          EnableWindows();
        }
        else if (nID == IDDIRE)
          sDir = GetTextAE(lParam);
      }
    }

    else if (nID == IDRUNB)
    {
      if (oRun.hProc)
        StopCmd();
      else
        RunCmd();
    }

    else if (nID == IDCMDB)
      CommandList();

    else if (nID == IDFILB)
      Files();

    else if (nID == IDDIRB)
    {
      if (hMainWnd)
        MenuDirs();
      else
        BrowseDirs();
    }

    else if (nID == IDHISB)
      History();

    else if (nID == IDSETB)
      Settings();

    else if (nID == 2 /*IDCANCEL*/)
      PostMessage(hDlg, 16 /*WM_CLOSE*/, 0, 0);
  }

  else if (uMsg == 16 /*WM_CLOSE*/)
  {
    if (oRun.hProc)
      return 1;
    else
    {
      WriteIni();
      oSys.Call("User32::DestroyWindow", hDlg);
    }
  }

  else if (uMsg == 2 /*WM_DESTROY*/)
    oSys.Call("User32::PostQuitMessage", 0);

  return 0;
}

function LoWord(nDwNum)
{
  return nDwNum & 0xFFFF;
}

function HiWord(nDwNum)
{
  return (nDwNum >> 16) & 0xFFFF;
}

function MkLong(nLoWord, nHiWord)
{
  return (nLoWord & 0xFFFF) | (nHiWord << 16);
}

function SendMessage(hWnd, uMsg, wParam, lParam)
{
  return AkelPad.SendMessage(hWnd, uMsg, wParam, lParam);
}

function PostMessage(hWnd, uMsg, wParam, lParam)
{
  return oSys.Call("User32::PostMessageW", hWnd, uMsg, wParam, lParam);
}

function InitDlg()
{
  var lpRect = AkelPad.MemAlloc(16 /*sizeof(RECT)*/);
  var sText;
  var i;

  for (i = IDCMDS; i < aDlg.length; ++i)
  {
    aDlg[i].HWND = oSys.Call("User32::CreateWindowExW",
      0,          //dwExStyle
      aDlg[i].C,  //lpClassName
      aDlg[i].T,  //lpWindowName
      aDlg[i].S,  //dwStyle
      0, 0, 0, 0, //x, y, nWidth, nHeight
      hDlg,       //hWndParent
      i,          //ID
      hInstDLL,   //hInstance
      0);         //lpParam
    SendMessage(aDlg[i].HWND, 48 /*WM_SETFONT*/, hGuiFont, 1);
  }

  SetEditFont();
  EditColors(0, aColorDef);

  if (aColor.length < 7)
  {
    for (i = 0; i < 7; ++i)
      aColor[i] = aColorDef[i];
  }

  if (! bColorDef)
    EditColors(1, aColor);

  AkelPad.MemCopy(_PtrAdd(lpRect, 0), 3, 3 /*DT_DWORD*/);
  AkelPad.MemCopy(_PtrAdd(lpRect, 4), 3, 3 /*DT_DWORD*/);

  for (i = IDCMDE; i <= IDOUTE; ++i)
    SendMessage(aDlg[i].HWND, 3178 /*AEM_SETRECT*/, 0x03 /*AERC_MARGINS|AERC_UPDATE*/, lpRect);

  AkelPad.MemFree(lpRect);

  SendMessage(aDlg[IDCMDE].HWND, 1093 /*EM_SETEVENTMASK*/, 0, 0x1 /*ENM_CHANGE*/);
  SendMessage(aDlg[IDDIRE].HWND, 1093 /*EM_SETEVENTMASK*/, 0, 0x1 /*ENM_CHANGE*/);

  SendMessage(aDlg[IDCMDE].HWND, 197 /*EM_SETLIMITTEXT*/, 32767 /*command line string max length*/, 0);
  SendMessage(aDlg[IDDIRE].HWND, 197 /*EM_SETLIMITTEXT*/, 259 /*MAX_PATH - 1*/, 0);

  SendMessage(aDlg[IDCMDE].HWND, 3242 /*AEM_SETWORDWRAP*/, 2 /*AEWW_SYMBOL*/, 0);

  oSys.Call("User32::SetWindowTextW", aDlg[IDCMDE].HWND, sCmd);
  oSys.Call("User32::SetWindowTextW", aDlg[IDDIRE].HWND, sDir);

  if (AkelPad.GetSelStart() != AkelPad.GetSelEnd())
  {
    if (sText = AkelPad.GetSelText().replace(/^\s+|\s+$/g, ""))
      ReplaceTextAE(aDlg[IDCMDE].HWND, sText);
  }

  if (! hMainWnd)
  {
    SendMessage(hDlg, 0x0080 /*WM_SETICON*/, 0 /*ICON_SMALL*/, hIconSmall);
    SendMessage(hDlg, 0x0080 /*WM_SETICON*/, 1 /*ICON_BIG*/,   hIconBig);
  }

  EnableWindows();
  aDlg.Focus = aDlg[IDCMDE].HWND;
}

function EnableWindows()
{
  var i;

  for (i = IDCMDE; i <= IDOUTE; ++i)
    oSys.Call("User32::EnableWindow", aDlg[i].HWND, (! oRun.hProc));

  oSys.Call("User32::EnableWindow", aDlg[IDRUNB].HWND, sCmd.length);
  oSys.Call("User32::EnableWindow", aDlg[IDCMDB].HWND, (! oRun.hProc));
  oSys.Call("User32::EnableWindow", aDlg[IDFILB].HWND, (! oRun.hProc));
  oSys.Call("User32::EnableWindow", aDlg[IDDIRB].HWND, (! oRun.hProc));
  oSys.Call("User32::EnableWindow", aDlg[IDHISB].HWND, (! oRun.hProc) && aHist.length);
  oSys.Call("User32::EnableWindow", aDlg[IDSETB].HWND, (! oRun.hProc));

  EditColors(1, bColorDef ? aColorDef : aColor);
}

function SetEditFont()
{
  var hFont = bFontDef ? hGuiFont : ConvertFontFormat(aFont, 3, 2);
  var i;

  for (i = IDCMDE; i <= IDOUTE; ++i)
  {
    SendMessage(aDlg[i].HWND, 48 /*WM_SETFONT*/, hFont, 1);
    oSys.Call("User32::InvalidateRect", aDlg[i].HWND, 0, true);
  }
}

function EditColors(bSet, aColor)
{
  var lpAECOLORS = AkelPad.MemAlloc(17 * 4);
  var i;

  AkelPad.MemCopy(lpAECOLORS, 0x000000FE /*AECLR_CARET|AECLR_BASICTEXT|AECLR_BASICBK|AECLR_SELTEXT|AECLR_SELBK|AECLR_ACTIVELINETEXT|AECLR_ACTIVELINEBK*/, 3 /*DT_DWORD*/);

  if (bSet)
  {
    for (i = 0; i < 7; ++i)
      AkelPad.MemCopy(_PtrAdd(lpAECOLORS, 4 + i * 4), aColor[i], 3 /*DT_DWORD*/);

    for (i = IDCMDE; i <= IDOUTE; ++i)
      SendMessage(aDlg[i].HWND, 3232 /*AEM_SETCOLORS*/, 0, lpAECOLORS);
  }
  else //get
  {
    SendMessage(aDlg[IDCMDE].HWND, 3231 /*AEM_GETCOLORS*/, 0, lpAECOLORS);

    for (i = 0; i < 7; ++i)
      aColor[i] = AkelPad.MemRead(_PtrAdd(lpAECOLORS, 4 + i * 4), 3 /*DT_DWORD*/);
  }

  AkelPad.MemFree(lpAECOLORS);
}

function GetTextAE(hWnd, bSel)
{
  AkelPad.SetEditWnd(hWnd);
  var sText = bSel ? AkelPad.GetSelText(): AkelPad.GetTextRange(0, -1);
  AkelPad.SetEditWnd(0);
  return sText;
}

function ReplaceTextAE(hWnd, sText)
{
  AkelPad.SetEditWnd(hWnd);
  AkelPad.SetSel(0, -1);
  AkelPad.ReplaceSel(sText);
  AkelPad.SetEditWnd(0);
}

function GetWindowPos(hWnd, oRect)
{
  var lpRect = AkelPad.MemAlloc(16 /*sizeof(RECT)*/);

  oSys.Call("User32::GetWindowRect", hWnd, lpRect);

  oRect.X = AkelPad.MemRead(_PtrAdd(lpRect,  0), 3 /*DT_DWORD*/);
  oRect.Y = AkelPad.MemRead(_PtrAdd(lpRect,  4), 3 /*DT_DWORD*/);
  oRect.W = AkelPad.MemRead(_PtrAdd(lpRect,  8), 3 /*DT_DWORD*/) - oRect.X;
  oRect.H = AkelPad.MemRead(_PtrAdd(lpRect, 12), 3 /*DT_DWORD*/) - oRect.Y;

  AkelPad.MemFree(lpRect);
}

function ResizeDlg(nW, nH)
{
  var nFlags = 0x14; //SWP_NOACTIVATE|SWP_NOZORDER
  var nW70   = Scale.X(70);
  var nW100  = Scale.X(100);
  var nH13   = Scale.Y(13);
  var nH16   = Scale.Y(16);
  var nH23   = Scale.Y(23);
  var nH60   = Scale.Y(60);
  var nY     = 10;
  var nBX    = Math.round((nW - (IDSETB - IDRUNB + 1) * nW70 - (IDSETB - IDRUNB) * 5) / 2);
  var i;

  oSys.Call("User32::SetWindowPos",
    aDlg[IDCMDS].HWND, 0,
    10,
    nY,
    nW100,
    nH13,
    nFlags);
  oSys.Call("User32::SetWindowPos",
    aDlg[IDCMDE].HWND, 0,
    10,
    nY += nH13 + 2,
    nW - 20,
    nH60,
    nFlags);
  oSys.Call("User32::SetWindowPos",
    aDlg[IDDIRS].HWND, 0,
    10,
    nY += nH60 + 10,
    nW100,
    nH13,
    nFlags);
  oSys.Call("User32::SetWindowPos",
    aDlg[IDDIRE].HWND, 0,
    10,
    nY += nH13 + 2,
    nW - 20,
    nH23,
    nFlags);
  nY += nH23 + 10;
  for (i = IDRUNB; i <= IDSETB; ++i)
    oSys.Call("User32::SetWindowPos",
      aDlg[i].HWND, 0,
      nBX + (i - IDRUNB) * (nW70 + 5),
      nY,
      nW70,
      nH23,
      nFlags);
  oSys.Call("User32::SetWindowPos",
    aDlg[IDOUTS].HWND, 0,
    10,
    nY += nH23 + 5,
    nW100,
    nH13,
    nFlags);
  oSys.Call("User32::SetWindowPos",
    aDlg[IDOUTE].HWND, 0,
    10,
    nY += nH13 + 2,
    nW - 20,
    nH - (nY + 2) - 10,
    nFlags);
  oSys.Call("user32::InvalidateRect", hDlg, 0, true);
}

function PaintSizeGrip()
{
  var lpPaint = AkelPad.MemAlloc(_X64 ? 72 : 64 /*sizeof(PAINTSTRUCT)*/);
  var lpRect  = AkelPad.MemAlloc(16 /*sizeof(RECT)*/);
  var hDC;

  if (hDC = oSys.Call("User32::BeginPaint", hDlg, lpPaint))
  {
    oSys.Call("User32::GetClientRect", hDlg, lpRect);

    AkelPad.MemCopy(_PtrAdd(lpRect, 0), AkelPad.MemRead(_PtrAdd(lpRect,  8), 3 /*DT_DWORD*/) - oSys.Call("User32::GetSystemMetrics",  2 /*SM_CXVSCROLL*/), 3 /*DT_DWORD*/);
    AkelPad.MemCopy(_PtrAdd(lpRect, 4), AkelPad.MemRead(_PtrAdd(lpRect, 12), 3 /*DT_DWORD*/) - oSys.Call("User32::GetSystemMetrics", 20 /*SM_CYVSCROLL*/), 3 /*DT_DWORD*/);

    oSys.Call("User32::DrawFrameControl", hDC, lpRect, 3 /*DFC_SCROLL*/, 0x8 /*DFCS_SCROLLSIZEGRIP*/);
    oSys.Call("User32::EndPaint", hDlg, lpPaint);
  }

  AkelPad.MemFree(lpPaint);
  AkelPad.MemFree(lpRect);
}

function MenuEdit(hWnd, nX, nY)
{
  var MF_STRING    = 0x0000;
  var MF_GRAYED    = 0x0001;
  var MF_SEPARATOR = 0x0800;
  var bRO   = oSys.Call("User32::GetWindowLongW", hWnd, -16 /*GWL_STYLE*/) & 0x0800 /*ES_READONLY*/;
  var hMenu = oSys.Call("User32::CreatePopupMenu");
  var lpPoint;
  var nCmd;

  oSys.Call("User32::SetFocus", hWnd);

  if (nX == 0xFFFF) //context menu from keyboard
  {
    lpPoint = AkelPad.MemAlloc(8 /*sizeof(POINT)*/);
    oSys.Call("User32::GetCaretPos", lpPoint);
    oSys.Call("User32::ClientToScreen", hWnd, lpPoint);
    nX = AkelPad.MemRead(_PtrAdd(lpPoint, 0), 3 /*DT_DWORD*/);
    nY = AkelPad.MemRead(_PtrAdd(lpPoint, 4), 3 /*DT_DWORD*/) + SendMessage(hWnd, 3188 /*AEM_GETCHARSIZE*/, 0 /*AECS_HEIGHT*/, 0);
    AkelPad.MemFree(lpPoint);
  }

  oSys.Call("User32::AppendMenuW", hMenu, SendMessage(hWnd,  198 /*EM_CANUNDO*/, 0, 0) ? MF_STRING : MF_GRAYED, 1, sMnuUndo + "\tCtrl+Z");
  oSys.Call("User32::AppendMenuW", hMenu, SendMessage(hWnd, 1109 /*EM_CANREDO*/, 0, 0) ? MF_STRING : MF_GRAYED, 2, sMnuRedo + "\tCtrl+Shift+Z");
  oSys.Call("User32::AppendMenuW", hMenu, MF_SEPARATOR, 0, 0);
  oSys.Call("User32::AppendMenuW", hMenu, (! bRO) && SendMessage(hWnd, 3125 /*AEM_GETSEL*/, 0, 0) ? MF_STRING : MF_GRAYED, 3, sMnuCut + "\tCtrl+X");
  oSys.Call("User32::AppendMenuW", hMenu, SendMessage(hWnd, 3125 /*AEM_GETSEL*/, 0, 0) ? MF_STRING : MF_GRAYED, 4, sMnuCopy + "\tCtrl+C");
  oSys.Call("User32::AppendMenuW", hMenu, SendMessage(hWnd, 1074 /*EM_CANPASTE*/, 0, 0) ? MF_STRING : MF_GRAYED, 5, sMnuPaste + "\tCtrl+V");
  oSys.Call("User32::AppendMenuW", hMenu, (! bRO) && SendMessage(hWnd, 3125 /*AEM_GETSEL*/, 0, 0) ? MF_STRING : MF_GRAYED, 6, sMnuDelete + "\tDel");
  oSys.Call("User32::AppendMenuW", hMenu, MF_SEPARATOR, 0, 0);
  oSys.Call("User32::AppendMenuW", hMenu, oSys.Call("User32::GetWindowTextLengthW", hWnd) ? MF_STRING : MF_GRAYED, 7, sMnuSelectAll + "\tCtrl+A");

  nCmd = oSys.Call("User32::TrackPopupMenu", hMenu, 0x180 /*TPM_NONOTIFY|TPM_RETURNCMD*/, nX, nY, 0, hWnd, 0);

  oSys.Call("User32::DestroyMenu", hMenu);

  if (nCmd == 1)
    SendMessage(hWnd, 199 /*EM_UNDO*/, 0, 0);
  else if (nCmd == 2)
    SendMessage(hWnd, 1108 /*EM_REDO*/, 0, 0);
  else if (nCmd == 3)
    SendMessage(hWnd, 768 /*WM_CUT*/, 0, 0);
  else if (nCmd == 4)
    SendMessage(hWnd, 769 /*WM_COPY*/, 0, 0);
  else if (nCmd == 5)
    SendMessage(hWnd, 770 /*WM_PASTE*/, 0, 0);
  else if (nCmd == 6)
    SendMessage(hWnd, 771 /*WM_CLEAR*/, 0, 0);
  else if (nCmd == 7)
    SendMessage(hWnd, 177 /*EM_SETSEL*/, 0, -1);
}

function RunCmd()
{
  if (sDir && (! oFSO.FolderExists(sDir)))
  {
    oSys.Call("User32::SetWindowTextW", aDlg[IDOUTE].HWND, sTxtCantExec + "\n" + sTxtNoDir);
    return;
  }

  var hFocus        = oSys.Call("User32::GetFocus");
  var hCurProcess   = oSys.Call("Kernel32::GetCurrentProcess");
  var nBufSize      = 65536;
  var lpSA          = AkelPad.MemAlloc(_X64 ? 24 : 12 /*sizeof(SECURITY_ATTRIBUTES)*/);
  var lpSI          = AkelPad.MemAlloc(_X64 ? 104 : 68 /*sizeof(STARTUPINFO)*/);
  var lpPI          = AkelPad.MemAlloc(_X64 ? 24 : 16 /*sizeof(PROCESS_INFORMATION)*/);
  var lpInpRead     = AkelPad.MemAlloc(_X64 ? 8 : 4);
  var lpInpWriteTmp = AkelPad.MemAlloc(_X64 ? 8 : 4);
  var lpInpWrite    = AkelPad.MemAlloc(_X64 ? 8 : 4);
  var lpOutReadTmp  = AkelPad.MemAlloc(_X64 ? 8 : 4);
  var lpOutRead     = AkelPad.MemAlloc(_X64 ? 8 : 4);
  var lpOutWrite    = AkelPad.MemAlloc(_X64 ? 8 : 4);
  var lpErrWrite    = AkelPad.MemAlloc(_X64 ? 8 : 4);
  var hInpRead;
  var hInpWriteTmp;
  var hInpWrite;
  var hOutReadTmp;
  var hOutRead;
  var hOutWrite;
  var hErrWrite;
  var lpDir;
  var lpBuffer;
  var lpBytesAvail;
  var lpBytesRead;
  var lpExitCode;
  var nBytesAvail;
  var lpMsg;

  AkelPad.MemCopy(_PtrAdd(lpSA, 0), _X64 ? 24 : 12, 3 /*DT_DWORD*/); //nLength
  AkelPad.MemCopy(_PtrAdd(lpSA, _X64 ? 16 : 8),  1, 3 /*DT_DWORD*/); //bInheritHandle

  oSys.Call("Kernel32::CreatePipe", lpInpRead,    lpInpWriteTmp, lpSA, nBufSize);
  oSys.Call("Kernel32::CreatePipe", lpOutReadTmp, lpOutWrite,    lpSA, nBufSize);
  hInpRead     = AkelPad.MemRead(lpInpRead,     2 /*DT_QWORD*/);
  hInpWriteTmp = AkelPad.MemRead(lpInpWriteTmp, 2 /*DT_QWORD*/);
  hOutReadTmp  = AkelPad.MemRead(lpOutReadTmp,  2 /*DT_QWORD*/);
  hOutWrite    = AkelPad.MemRead(lpOutWrite,    2 /*DT_QWORD*/);

  oSys.Call("Kernel32::DuplicateHandle", hCurProcess, hInpWriteTmp, hCurProcess, lpInpWrite, 0, 0 /*bInheritHandle*/, 2 /*DUPLICATE_SAME_ACCESS*/);
  oSys.Call("Kernel32::DuplicateHandle", hCurProcess, hOutReadTmp,  hCurProcess, lpOutRead,  0, 0 /*bInheritHandle*/, 2 /*DUPLICATE_SAME_ACCESS*/);
  oSys.Call("Kernel32::DuplicateHandle", hCurProcess, hOutWrite,    hCurProcess, lpErrWrite, 0, 1 /*bInheritHandle*/, 2 /*DUPLICATE_SAME_ACCESS*/);
  hInpWrite = AkelPad.MemRead(lpInpWrite, 2 /*DT_QWORD*/);
  hOutRead  = AkelPad.MemRead(lpOutRead,  2 /*DT_QWORD*/);
  hErrWrite = AkelPad.MemRead(lpErrWrite, 2 /*DT_QWORD*/);

  if (sDir)
  {
    lpDir = AkelPad.MemAlloc(260 * 2 /*sizeof(MAX_PATH)*/);
    AkelPad.MemCopy(lpDir, sDir, 1 /*DT_UNICODE*/);
  }

  AkelPad.MemCopy(_PtrAdd(lpSI, 0),         _X64 ? 104 : 68, 3 /*DT_DWORD*/); //cb=sizeof(STARTUPINFO)
  AkelPad.MemCopy(_PtrAdd(lpSI, _X64 ? 60 : 44), 0x00000101, 3 /*DT_DWORD*/); //dwFlags=STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW
  AkelPad.MemCopy(_PtrAdd(lpSI, _X64 ? 64 : 48),   bShowWnd, 4 /*DT_WORD*/ ); //wShowWindow
  AkelPad.MemCopy(_PtrAdd(lpSI, _X64 ? 80 : 56),   hInpRead, 2 /*DT_QWORD*/); //hStdInput
  AkelPad.MemCopy(_PtrAdd(lpSI, _X64 ? 88 : 60),  hOutWrite, 2 /*DT_QWORD*/); //hStdOutput
  AkelPad.MemCopy(_PtrAdd(lpSI, _X64 ? 96 : 64),  hErrWrite, 2 /*DT_QWORD*/); //hStdError

  if (oSys.Call("Kernel32::CreateProcessW", 0, sCmd, 0, 0, 1 /*bInheritHandles*/, 0x10 /*CREATE_NEW_CONSOLE*/, 0, lpDir, lpSI, lpPI) || oSys.Call("Kernel32::CreateProcessW", 0, "cmd /c " + sCmd, 0, 0, 1 /*bInheritHandles*/, 0x10 /*CREATE_NEW_CONSOLE*/, 0, lpDir, lpSI, lpPI))
  {
    oRun.hProc   = AkelPad.MemRead(_PtrAdd(lpPI, 0),             2 /*DT_QWORD*/);
    oRun.hThread = AkelPad.MemRead(_PtrAdd(lpPI, _X64 ?  8 : 4), 2 /*DT_QWORD*/);
    oRun.PID     = AkelPad.MemRead(_PtrAdd(lpPI, _X64 ? 16 : 8), 3 /*DT_DWORD*/);
    lpBuffer     = AkelPad.MemAlloc(nBufSize);
    lpBytesAvail = AkelPad.MemAlloc(4);
    lpBytesRead  = AkelPad.MemAlloc(4);
    lpExitCode   = AkelPad.MemAlloc(4);
    lpMsg        = AkelPad.MemAlloc(_X64 ? 48 : 28 /*sizeof(MSG)*/);

    oSys.Call("User32::SetWindowTextW", aDlg[IDRUNB].HWND, sTxtStop);
    oSys.Call("User32::SetWindowTextW", aDlg[IDOUTE].HWND, "");
    oSys.Call("User32::SetFocus", aDlg[IDRUNB].HWND);
    SendMessage(aDlg[IDRUNB].HWND, 0xF4 /*BM_SETSTYLE*/, 1 /*BS_DEFPUSHBUTTON*/, 1);
    EnableWindows();

    oSys.Call("User32::WaitForInputIdle", oRun.hProc, 1000);
    oSys.Call("User32::SetForegroundWindow", hDlg);

    while (oSys.Call("Kernel32::PeekNamedPipe", hOutRead, 0, 0, 0, lpBytesAvail, 0) && oSys.Call("Kernel32::GetExitCodeProcess", oRun.hProc, lpExitCode))
    {
      while (oSys.Call("User32::PeekMessageW", lpMsg, hDlg, 0, 0, 0x1 /*PM_REMOVE*/))
      {
        if ((AkelPad.MemRead(_PtrAdd(lpMsg, _X64 ? 8 : 4) /*uMsg*/, 3 /*DT_DWORD*/) == 256 /*WM_KEYDOWN*/) && (AkelPad.MemRead(_PtrAdd(lpMsg, _X64 ? 16 : 8) /*wParam*/, 2 /*DT_QWORD*/) == 13 /*VK_RETURN*/))
          SendMessage(hDlg, 273 /*WM_COMMAND*/, IDRUNB, aDlg[IDRUNB].HWND);

        oSys.Call("User32::TranslateMessage", lpMsg);
        oSys.Call("User32::DispatchMessageW", lpMsg);
      }

      if (oRun.Stop)
      {
        SendMessage(aDlg[IDOUTE].HWND, 177 /*EM_SETSEL*/, -1, -1);
        SendMessage(aDlg[IDOUTE].HWND, 194 /*EM_REPLACESEL*/, 0, "...\n" + oRun.EndText);
        break;
      }
      else if (nBytesAvail = AkelPad.MemRead(lpBytesAvail, 3 /*DT_DWORD*/))
      {
        if (nBytesAvail >= nBufSize)
          nBytesAvail = nBufSize - 1;

        oSys.Call("Kernel32::ReadFile", hOutRead, lpBuffer, nBytesAvail, lpBytesRead, 0);
        AkelPad.MemCopy(_PtrAdd(lpBuffer, AkelPad.MemRead(lpBytesRead, 3 /*DT_DWORD*/)), 0, 5 /*DT_BYTE*/);
        oSys.Call("User32::OemToCharA", lpBuffer, lpBuffer);
        SendMessage(aDlg[IDOUTE].HWND, 177 /*EM_SETSEL*/, -1, -1);
        SendMessage(aDlg[IDOUTE].HWND, 2925 /*EM_REPLACESELA*/, 0, lpBuffer);
      }
      else if (AkelPad.MemRead(lpExitCode, 3 /*DT_DWORD*/) == 259 /*STILL_ACTIVE*/)
        WScript.Sleep(10);
      else
        break;
    }

    AkelPad.MemFree(lpBuffer);
    AkelPad.MemFree(lpBytesAvail);
    AkelPad.MemFree(lpBytesRead);
    AkelPad.MemFree(lpExitCode);
    AkelPad.MemFree(lpMsg);

    oSys.Call("Kernel32::CloseHandle", oRun.hProc);
    oSys.Call("Kernel32::CloseHandle", oRun.hThread);
    oRun.hProc   = 0;
    oRun.hThread = 0;
    oRun.PID     = 0;
    oRun.EndText = "";

    AddToHistory();
    EnableWindows();
    oSys.Call("User32::SetWindowTextW", aDlg[IDRUNB].HWND, sTxtRun);
    oSys.Call("User32::SetFocus", oRun.Stop ? hFocus : aDlg[IDOUTE].HWND);
    oRun.Stop = 0;
  }
  else
    oSys.Call("User32::SetWindowTextW", aDlg[IDOUTE].HWND, sTxtCantExec);

  AkelPad.MemFree(lpSA);
  AkelPad.MemFree(lpPI);
  AkelPad.MemFree(lpSI);
  AkelPad.MemFree(lpInpRead);
  AkelPad.MemFree(lpInpWriteTmp);
  AkelPad.MemFree(lpInpWrite);
  AkelPad.MemFree(lpOutReadTmp);
  AkelPad.MemFree(lpOutRead);
  AkelPad.MemFree(lpOutWrite);
  AkelPad.MemFree(lpErrWrite);
  AkelPad.MemFree(lpDir);

  oSys.Call("Kernel32::CloseHandle", hInpRead);
  oSys.Call("Kernel32::CloseHandle", hInpWriteTmp);
  oSys.Call("Kernel32::CloseHandle", hInpWrite);
  oSys.Call("Kernel32::CloseHandle", hOutReadTmp);
  oSys.Call("Kernel32::CloseHandle", hOutRead);
  oSys.Call("Kernel32::CloseHandle", hOutWrite);
  oSys.Call("Kernel32::CloseHandle", hErrWrite);
}

function StopCmd()
{
  var lpCallback;
  var lpPID;
  var lpExitCode;

  try
  {
    lpCallback = oSys.RegisterCallback(EnumWindowsProc);
  }
  catch (oError)
  {}

  //try to stop by send WM_CLOSE into process windows
  if (lpCallback)
  {
    lpPID = AkelPad.MemAlloc(4);
    oSys.Call("User32::EnumWindows", lpCallback, lpPID);
    oSys.UnregisterCallback(lpCallback);
    AkelPad.MemFree(lpPID);
  }

  //if process is still active, terminate it
  lpExitCode = AkelPad.MemAlloc(4);
  oSys.Call("Kernel32::GetExitCodeProcess", oRun.hProc, lpExitCode);

  if (AkelPad.MemRead(lpExitCode, 3 /*DT_DWORD*/) == 259 /*STILL_ACTIVE*/)
  {
    oSys.Call("Kernel32::TerminateProcess", oRun.hProc, 1);
    oRun.EndText = sTxtStopTermin;
  }
  else
    oRun.EndText = sTxtStopClose;

  AkelPad.MemFree(lpExitCode);

  oRun.Stop = 1;
}

function EnumWindowsProc(hWnd, lpPID)
{
  oSys.Call("User32::GetWindowThreadProcessId", hWnd, lpPID);

  if (AkelPad.MemRead(lpPID, 3 /*DT_DWORD*/) == oRun.PID)
  {
    SendMessage(hWnd, 16 /*WM_CLOSE*/, 0, 0);
    WScript.Sleep(50);
  }

  return 1;
}

function AddToHistory()
{
  for (var i = 0; i < aHist.length; ++i)
  {
    if ((aHist[i][0].toUpperCase() == sCmd.toUpperCase()) && (aHist[i][1].toUpperCase() == sDir.toUpperCase()))
    {
      aHist.splice(i, 1);
      break;
    }
  }

  aHist.unshift([sCmd, sDir]);

  if (aHist.length > nHistMax)
    aHist.length = nHistMax;
}

function CommandList()
{
  // http://technet.microsoft.com/en-us/library/bb490890.aspx
  // http://ss64.com/nt/

  var oRect = {};
  var nStr  = 0x0000; //MF_STRING
  var nSep  = 0x0800; //MF_SEPARATOR
  var hMenu = oSys.Call("User32::CreatePopupMenu");
  var aMenu;
  var nCmd;
  var i;

  GetWindowPos(aDlg[IDCMDE].HWND, oRect);

  aMenu = [
    [nStr, "ARP",           "Address Resolution Protocol"],
    [nStr, "ASSOC",         "Change file extension associations *"],
    [nStr, "AT",            "Schedule a command to run at a specific time"],
    [nStr, "ATTRIB",        "Change file attributes"],
    [nSep],
    [nStr, "BCDBOOT",       "Create or repair a system partition (Win7)"],
    [nStr, "BCDEDIT",       "Manage Boot Configuration Data (Win7)"],
    [nStr, "BOOTCFG",       "Edit Windows boot settings"],
    [nSep],
    [nStr, "CACLS",         "Change file permissions"],
    [nStr, "CALL",          "Call one batch program from another *"],
    [nStr, "CD",            "Change Directory (CHDIR) *"],
    [nStr, "CHKDSK",        "Check Disk - check and repair disk problems"],
    [nStr, "CHKNTFS",       "Check the NTFS file system"],
    [nStr, "CIPHER",        "Encrypt or Decrypt files/folders"],
    [nStr, "CLIP",          "Copy STDIN to the Windows clipboard (Win7)"],
    [nStr, "CMD",           "Start a new CMD shell"],
    [nStr, "CMDKEY",        "Manage stored usernames/passwords (Win7)"],
    [nStr, "COLOR",         "Change colors of the CMD window *"],
    [nStr, "COMP",          "Compare the contents of two files or sets of files"],
    [nStr, "COMPACT",       "Compress files or folders on an NTFS partition"],
    [nStr, "CONVERT",       "Convert a FAT drive to NTFS"],
    [nStr, "COPY",          "Copy one or more files to another location *"],
    [nSep],
    [nStr, "DATE",          "Display or set the date *"],
    [nStr, "DEFRAG",        "Defragment hard drive"],
    [nStr, "DEL",           "Delete one or more files (ERASE) *"],
    [nStr, "DIR",           "Display a list of files and folders *"],
    [nStr, "DISKPART",      "Disk Administration"],
    [nStr, "DRIVERQUERY",   "Display installed device drivers"],
    [nSep],
    [nStr, "ECHO",          "Display message on screen *"],
    [nStr, "ENDLOCAL",      "End localisation of environment changes in a batch file *"],
    [nStr, "ERASE",         "Delete one or more files (DEL) *"],
    [nStr, "EVENTCREATE",   "Add a message to the Windows event log"],
    [nStr, "EVENTTRIGGERS", "Displays and configures event triggers on local or remote machines"],
    [nStr, "EXIT",          "Quit the current script/routine and set an errorlevel *"],
    [nStr, "EXPAND",        "Uncompress CAB files"],
    [nSep],
    [nStr, "FC",            "Compare two files"],
    [nStr, "FIND",          "Search for a text string in a file"],
    [nStr, "FINDSTR",       "Search for strings in files"],
    [nStr, "FOR",           "Loop command: all options Files, Directory, List *"],
    [nStr, "FORFILES",      "Batch process multiple files (Win7)"],
    [nStr, "FORMAT",        "Format a disk"],
    [nStr, "FSUTIL",        "File and Volume utilities"],
    [nStr, "FTYPE",         "File extension file type associations *"],
    [nSep],
    [nStr, "GETMAC",        "Display the Media Access Control (MAC) address"],
    [nStr, "GOTO",          "Direct a batch program to jump to a labelled line *"],
    [nStr, "GPRESULT",      "Display Resultant Set of Policy information"],
    [nStr, "GPUPDATE",      "Update Group Policy settings"],
    [nStr, "GRAFTABL",      "Enables the ability to display an extended character set in graphics mode"],
    [nSep],
    [nStr, "HELP",          "Online Help"],
    [nStr, "HOSTNAME",      "Display the host name of the computer"],
    [nSep],
    [nStr, "ICACLS",        "Change file and folder permissions (Win7)"],
    [nStr, "IF",            "Conditionally perform a command *"],
    [nStr, "IPCONFIG",      "Configure IP"],
    [nSep],
    [nStr, "LABEL",         "Edit a disk label"],
    [nStr, "LOGMAN",        "Manage Performance Monitor logs"],
    [nStr, "LOGOFF",        "Log a user off"],
    [nSep],
    [nStr, "MAKECAB",       "Create .CAB files"],
    [nStr, "MD",            "Create new folders (MKDIR) *"],
    [nStr, "MKLINK",        "Create a symbolic link (linkd, Win7) *"],
    [nStr, "MODE",          "Configure a system device COM/LPT/CON"],
    [nStr, "MORE",          "Display output, one screen at a time"],
    [nStr, "MOUNTVOL",      "Manage a volume mount point"],
    [nStr, "MOVE",          "Move files from one folder to another *"],
    [nStr, "MSG",           "Send a message"],
    [nSep],
    [nStr, "NET",           "Manage network resources"],
    [nStr, "NETSH",         "Configure Network Interfaces, Windows Firewall and Remote access"],
    [nStr, "NETSTAT",       "Display networking statistics TCP/IP"],
    [nStr, "NLTEST",        "Network Location Test (Win7)"],
    [nStr, "NSLOOKUP",      "Name server lookup"],
    [nSep],
    [nStr, "OPENFILES",     "Query or display open files"],
    [nSep],
    [nStr, "PATH",          "Display or set a search path for executable files *"],
    [nStr, "PATHPING",      "Trace route plus network latency and packet loss"],
    [nStr, "PAUSE",         "Suspend processing of a batch file and display a message *"],
    [nStr, "PING",          "Test a network connection"],
    [nStr, "POPD",          "Return to a previous directory saved by PUSHD *"],
    [nStr, "POWERCFG",      "Configure power settings (Win7)"],
    [nStr, "PRINT",         "Print a text file"],
    [nStr, "PROMPT",        "Change the command prompt *"],
    [nStr, "PUSHD",         "Save and then change the current directory *"],
    [nSep],
    [nStr, "QPROCESS",      "Display processes (QUERY PROCESS)"],
    [nStr, "QWINSTA",       "Display all sessions (QUERY SESSION)"],
    [nStr, "QAPPSRV",       "List all servers (QUERY TERMSERVER)"],
    [nSep],
    [nStr, "RECOVER",       "Recover a damaged file from a defective disk"],
    [nStr, "REG",           "Registry: Read, Set, Export, Delete keys and values"],
    [nStr, "REGINI",        "Change Registry Permissions (Win7)"],
    [nStr, "REM",           "Record comments (remarks) in a batch file *"],
    [nStr, "REN",           "Rename a file or files (RENAME) *"],
    [nStr, "REPLACE",       "Replace or update one file with another"],
    [nStr, "RWINSTA",       "Delete a Remote Desktop Session (RESET SESSION)"],
    [nStr, "RD",            "Delete folders (RMDIR) *"],
    [nStr, "ROBOCOPY",      "Robust File and Folder Copy (Win7)"],
    [nStr, "ROUTE",         "Manipulate network routing tables"],
    [nSep],
    [nStr, "SET",           "Display, set, or remove session environment variables *"],
    [nStr, "SETLOCAL",      "Control the visibility of environment variables *"],
    [nStr, "SFC",           "System File Checker"],
    [nStr, "SHIFT",         "Shift the position of batch file parameters *"],
    [nStr, "SHUTDOWN",      "Shutdown the computer"],
    [nStr, "SORT",          "Sort input"],
    [nStr, "START",         "Start a program, command or batch file *"],
    [nStr, "SUBST",         "Associate a path with a drive letter"],
    [nStr, "SYSTEMINFO",    "List system configuration"],
    [nSep],
    [nStr, "TAKEOWN",       "Take ownership of a file (Win7)"],
    [nStr, "TASKLIST",      "List running applications and services"],
    [nStr, "TASKKILL",      "End a running process"],
    [nStr, "TIME",          "Display or set the system time *"],
    [nStr, "TIMEOUT",       "Delay processing of a batch file (Win7)"],
    [nStr, "TITLE",         "Set the window title for a CMD.EXE session *"],
    [nStr, "TRACERT",       "Trace route to a remote host"],
    [nStr, "TREE",          "Graphical display of folder structure"],
    [nStr, "TSDISCON",      "Disconnect a Remote Desktop Session"],
    [nStr, "TSKILL",        "End a running process"],
    [nStr, "TSSHUTDN",      "Remotely shut down or reboot a terminal server"],
    [nStr, "TYPE",          "Display the contents of a text file *"],
    [nSep],
    [nStr, "VER",           "Display version information *"],
    [nStr, "VERIFY",        "Verify that files have been saved *"],
    [nStr, "VOL",           "Display a disk label *"],
    [nSep],
    [nStr, "WAITFOR",       "Wait for or send a signal (Win7)"],
    [nStr, "WEVTUTIL",      "Clear event logs, enable/disable/query logs (Win7)"],
    [nStr, "WHOAMI",        "Output the current UserName and domain (Win7)"],
    [nStr, "WMIC",          "Windows Management Instrumentation Commands"],
    [nSep],
    [nStr, "XCOPY",         "Copy files and folders"]];

  for (i = 0; i < aMenu.length; ++i)
    oSys.Call("User32::AppendMenuW", hMenu, aMenu[i][0], i + 1, aMenu[i][1] + "\t" + aMenu[i][2]);

  nCmd = oSys.Call("User32::TrackPopupMenu", hMenu, 0x0188 /*TPM_NONOTIFY|TPM_RETURNCMD|TPM_TOPALIGN|TPM_RIGHTALIGN*/, oRect.X + oRect.W, oRect.Y + oRect.H, 0, hDlg, 0);

  oSys.Call("User32::DestroyMenu", hMenu);

  if (nCmd)
  {
    ReplaceTextAE(aDlg[IDCMDE].HWND, aMenu[nCmd - 1][1] + " /?");
    aDlg.Focus = aDlg[IDCMDE].HWND;
  }

  PostMessage(hDlg, 7 /*WM_SETFOCUS*/, 0, 0);
}

function Files()
{
  var oRect    = {};
  var sFilter  = sTxtExeFiles + " (*.exe)\0*.exe\0" + sTxtAllFiles + " (*.*)\0*.*\0\0";
  var sTitle   = sTxtFiles.replace("&", "");
  var lpFilter = AkelPad.MemAlloc(sFilter.length * 2 + 2);
  var lpFile   = AkelPad.MemAlloc(260 * 2);
  var lpTitle  = AkelPad.MemAlloc(sTitle.length * 2 + 2);
  var lpOFN    = AkelPad.MemAlloc(_X64 ? 152 : 88 /*sizeof(OPENFILENAME)*/);
  var nFlags   = 0x02080824 /*OFN_DONTADDTORECENT|OFN_EXPLORER|OFN_PATHMUSTEXIST|OFN_ENABLEHOOK|OFN_HIDEREADONLY*/;
  var hWndOwn;

  //to set position OpenFile dialog box
  GetWindowPos(aDlg[IDCMDE].HWND, oRect);
  hWndOwn = oSys.Call("User32::CreateWindowExW", 0, "STATIC", 0, 0x80000000 /*WS_POPUP*/, oRect.X, oRect.Y + oRect.H + 3, 0, 0, hDlg, 0, hInstDLL, 0);

  AkelPad.MemCopy(lpFilter, sFilter,   1 /*DT_UNICODE*/);
  AkelPad.MemCopy(lpFile,   sLastFile, 1 /*DT_UNICODE*/);
  AkelPad.MemCopy(lpTitle,  sTitle,    1 /*DT_UNICODE*/);

  AkelPad.MemCopy(_PtrAdd(lpOFN, 0),        _X64 ? 152 : 88, 3 /*DT_DWORD*/); //lStructSize
  AkelPad.MemCopy(_PtrAdd(lpOFN, _X64 ?   8 :  4),  hWndOwn, 2 /*DT_QWORD*/); //hwndOwner
  AkelPad.MemCopy(_PtrAdd(lpOFN, _X64 ?  24 : 12), lpFilter, 2 /*DT_QWORD*/); //lpstrFilter
  AkelPad.MemCopy(_PtrAdd(lpOFN, _X64 ?  44 : 24),        1, 3 /*DT_DWORD*/); //nFilterIndex
  AkelPad.MemCopy(_PtrAdd(lpOFN, _X64 ?  48 : 28),   lpFile, 2 /*DT_QWORD*/); //lpstrFile
  AkelPad.MemCopy(_PtrAdd(lpOFN, _X64 ?  56 : 32),      260, 3 /*DT_DWORD*/); //nMaxFile
  AkelPad.MemCopy(_PtrAdd(lpOFN, _X64 ?  88 : 48),  lpTitle, 2 /*DT_QWORD*/); //lpstrTitle
  AkelPad.MemCopy(_PtrAdd(lpOFN, _X64 ?  96 : 52),   nFlags, 3 /*DT_DWORD*/); //Flags
  AkelPad.MemCopy(_PtrAdd(lpOFN, _X64 ? 148 : 84),        1, 3 /*DT_DWORD*/); //FlagsEx=OFN_EX_NOPLACESBAR

  oSys.Call("User32::EnableWindow", hMainWnd, 0);
  oSys.Call("User32::EnableWindow", hDlg, 0);

  if (oSys.Call("Comdlg32::GetOpenFileNameW", lpOFN))
  {
    sLastFile = AkelPad.MemRead(lpFile, 1 /*DT_UNICODE*/);
    ReplaceTextAE(aDlg[IDCMDE].HWND, sLastFile);
    aDlg.Focus = aDlg[IDCMDE].HWND;
  }

  AkelPad.MemFree(lpFilter);
  AkelPad.MemFree(lpFile);
  AkelPad.MemFree(lpTitle);
  AkelPad.MemFree(lpOFN);

  oSys.Call("User32::EnableWindow", hMainWnd, 1);
  oSys.Call("User32::EnableWindow", hDlg, 1);
  oSys.Call("User32::DestroyWindow", hWndOwn);
  oSys.Call("User32::SetFocus", aDlg[IDDIRB].HWND);
  PostMessage(hDlg, 7 /*WM_SETFOCUS*/, 0, 0);
}

function MenuDirs()
{
  var MF_STRING = 0x0000;
  var MF_GRAYED = 0x0001;
  var MF_POPUP  = 0x0010;
  var aDir   = [];
  var oRect  = {};
  var hMenu  = oSys.Call("User32::CreatePopupMenu");
  var hMenu1 = oSys.Call("User32::CreatePopupMenu");
  var nTabs;
  var lpFile;
  var sFile;
  var nCmd;
  var i;

  if (AkelPad.IsMDI())
  {
    nTabs = AkelPad.SendMessage(hMainWnd, 1291 /*AKD_FRAMESTATS*/, 0 /*FWS_COUNTALL*/, 0);

    for (i = 0; i < nTabs; ++i)
    {
      lpFile = SendMessage(hMainWnd, 1223 /*AKD_GETFRAMEINFO*/, 32 /*FI_FILEW*/, SendMessage(hMainWnd, 1290 /*AKD_FRAMEFINDW*/, 8 /*FWF_BYTABINDEX*/, i));

      if (sFile = AkelPad.MemRead(lpFile, 1 /*DT_UNICODE*/))
        aDir.push([AkelPad.GetFilePath(sFile, 2 /*CPF_FILENAME*/), AkelPad.GetFilePath(sFile, 1 /*CPF_DIR*/)]);
    }
  }
  else
  {
    if (sFile = AkelPad.GetEditFile(0))
      aDir.push([AkelPad.GetFilePath(sFile, 2 /*CPF_FILENAME*/), AkelPad.GetFilePath(sFile, 1 /*CPF_DIR*/)]);
  }

  for (i = 0; i < aDir.length; ++i)
    oSys.Call("User32::AppendMenuW", hMenu1, MF_STRING, i + 2, aDir[i][0] + "\t" + aDir[i][1]);

  oSys.Call("User32::AppendMenuW", hMenu, MF_STRING, 1, sTxtBrowse);
  oSys.Call("User32::AppendMenuW", hMenu, aDir.length ? MF_POPUP : MF_GRAYED, hMenu1, "&AkelPad");

  GetWindowPos(aDlg[IDDIRB].HWND, oRect);

  nCmd = oSys.Call("User32::TrackPopupMenu", hMenu, 0x0180 /*TPM_NONOTIFY|TPM_RETURNCMD*/, oRect.X, oRect.Y + oRect.H, 0, hDlg, 0);

  oSys.Call("User32::DestroyMenu", hMenu);
  oSys.Call("User32::DestroyMenu", hMenu1);

  if (nCmd == 0)
    PostMessage(hDlg, 7 /*WM_SETFOCUS*/, 0, 0);
  else if (nCmd == 1)
    BrowseDirs();
  else
  {
    ReplaceTextAE(aDlg[IDDIRE].HWND, aDir[nCmd - 2][1]);
    aDlg.Focus = aDlg[IDDIRE].HWND;
    PostMessage(hDlg, 7 /*WM_SETFOCUS*/, 0, 0);
  }
}

function BrowseDirs()
{
  try
  {
    oSys.RegisterCallback(BFFCallback);
  }
  catch (oError)
  {
    AkelPad.MessageBox(hDlg, sTxtNoCallback, sTxtDlgTitle, 0x10 /*MB_ICONERROR*/);
    return;
  }

  var lpDir    = AkelPad.MemAlloc(260 * 2 /*sizeof(MAX_PATH)*/);
  var lpBrowse = AkelPad.MemAlloc(_X64 ? 64 : 32 /*sizeof(BROWSEINFO)*/);
  var lpIDL;

  if (sDir)
    AkelPad.MemCopy(lpDir, sDir, 1 /*DT_UNICODE*/);
  else
    oSys.Call("Kernel32::GetCurrentDirectoryW", 260, lpDir);

  AkelPad.MemCopy(_PtrAdd(lpBrowse, 0),                     hDlg, 2 /*DT_QWORD*/); //hWndOwner
  AkelPad.MemCopy(_PtrAdd(lpBrowse, _X64 ? 16 :  8),       lpDir, 2 /*DT_QWORD*/); //pszDisplayName
  AkelPad.MemCopy(_PtrAdd(lpBrowse, _X64 ? 32 : 16),  0x00000041, 3 /*DT_DWORD*/); //ulFlags=BIF_NEWDIALOGSTYLE|BIF_RETURNONLYFSDIRS
  AkelPad.MemCopy(_PtrAdd(lpBrowse, _X64 ? 40 : 20), BFFCallback, 2 /*DT_QWORD*/); //lpfn
  AkelPad.MemCopy(_PtrAdd(lpBrowse, _X64 ? 48 : 24),       lpDir, 2 /*DT_QWORD*/); //lParam

  oSys.Call("User32::EnableWindow", hMainWnd, 0);

  if (lpIDL = oSys.Call("Shell32::SHBrowseForFolderW", lpBrowse))
  {
    oSys.Call("Shell32::SHGetPathFromIDListW", lpIDL, lpDir);
    oSys.Call("Ole32::CoTaskMemFree", lpIDL);

    ReplaceTextAE(aDlg[IDDIRE].HWND, AkelPad.MemRead(lpDir, 1 /*DT_UNICODE*/));
    aDlg.Focus = aDlg[IDDIRE].HWND;
  }

  AkelPad.MemFree(lpDir);
  AkelPad.MemFree(lpBrowse);

  oSys.UnregisterCallback(BFFCallback);
  oSys.Call("User32::EnableWindow", hMainWnd, 1);
  oSys.Call("User32::SetFocus", aDlg[IDDIRB].HWND);
  PostMessage(hDlg, 7 /*WM_SETFOCUS*/, 0, 0);
}

function BFFCallback(hWnd, uMsg, lParam, lpData)
{
  if (uMsg == 1 /*BFFM_INITIALIZED*/)
  {
    var oRect = {};
    var hWndNS;
    var hWndTV;

    oSys.Call("User32::SetWindowTextW", hWnd, sTxtDirs.replace("&", ""));
    SendMessage(hWnd, 0x0080 /*WM_SETICON*/, 0 /*ICON_SMALL*/, hIconSmall);
    SendMessage(hWnd, 0x0467 /*BFFM_SETSELECTIONW*/, 1, lpData);

    //set focus to TreeView
    if (hWndNS = oSys.Call("User32::FindWindowExW", hWnd, 0, "SHBrowseForFolder ShellNameSpace Control", 0))
    {
      if (hWndTV = oSys.Call("User32::FindWindowExW", hWndNS, 0, "SysTreeView32", 0))
      {
        WScript.Sleep(50);
        PostMessage(hWnd, 0x0028 /*WM_NEXTDLGCTL*/, hWndTV, 1);
        PostMessage(hWndTV, 0x1114 /*TVM_ENSUREVISIBLE*/, 0, SendMessage(hWndTV, 0x110A /*TVM_GETNEXTITEM*/, 0x0009 /*TVGN_CARET*/, 0));
      }
    }

    GetWindowPos(aDlg[IDDIRE].HWND, oRect);
    oSys.Call("User32::SetWindowPos", hWnd, 0, oRect.X, oRect.Y + oRect.H + 3, 0, 0, 0x15 /*SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE*/);
  }

  return 0;
}

function History()
{
  var sCurCmd = sCmd;
  var sCurDir = sDir;
  var oRect   = {};
  var nBW     = Scale.X(70);
  var nBH     = Scale.Y(23);
  var nW, nH;

  var IDHISTLB  = 2000;
  var IDDELETEB = 2001;
  var IDCLEARB  = 2002;
  var IDOKB     = 2003;
  var IDCANCELB = 2004;
  var aWnd      = [];

  GetWindowPos(aDlg[IDDIRE].HWND, oRect);
  aWnd.T = sTxtHistory.replace("&", "");
  aWnd.X = oRect.X;
  aWnd.Y = oRect.Y + oRect.H + 3;
  aWnd.W = oRect.W;
  aWnd.H = Scale.Y(300);
  nW     = aWnd.W - oSys.Call("User32::GetSystemMetrics", 7 /*SM_CXFIXEDFRAME*/) * 2;
  nH     = aWnd.H - oSys.Call("User32::GetSystemMetrics", 4 /*SM_CYCAPTION*/) - oSys.Call("User32::GetSystemMetrics", 8 /*SM_CYFIXEDFRAME*/);

  aWnd[IDHISTLB]  = {X: 5, Y: 5, W: nW - 10, H: nH - nBH - 15, C: "LISTBOX", S: 0x50A10101 /*WS_CHILD|WS_VISIBLE|WS_VSCROLL|WS_BORDER|WS_TABSTOP|LBS_NOINTEGRALHEIGHT|LBS_NOTIFY*/};
  aWnd[IDDELETEB] = {X: Math.round((nW - nBW * 4 - 15) / 2), Y: nH - nBH - 5, W: nBW, H: nBH, T: sTxtDelete, C: "BUTTON", S: 0x50000000 /*WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON*/};
  aWnd[IDCLEARB]  = {X: aWnd[IDDELETEB].X + nBW + 5, Y: aWnd[IDDELETEB].Y, W: nBW, H: nBH, T: sTxtClear, C: "BUTTON", S: 0x50000000 /*WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON*/};
  aWnd[IDOKB]     = {X: aWnd[IDCLEARB].X + nBW + 5, Y: aWnd[IDDELETEB].Y, W: nBW, H: nBH, T: sTxtOK, C: "BUTTON", S: 0x50000001 /*WS_CHILD|WS_VISIBLE|BS_DEFPUSHBUTTON*/};
  aWnd[IDCANCELB] = {X: aWnd[IDOKB].X + nBW + 5, Y: aWnd[IDDELETEB].Y, W: nBW, H: nBH, T: sTxtCancel, C: "BUTTON", S: 0x50000000 /*WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON*/};

  oSys.Call("User32::CreateWindowExW",
    0,             //dwExStyle
    sClass,        //lpClassName
    aWnd.T,        //lpWindowName
    0x90C80000,    //dwStyle=WS_VISIBLE|WS_POPUP|WS_CAPTION|WS_SYSMENU
    aWnd.X,        //x
    aWnd.Y,        //y
    aWnd.W,        //nWidth
    aWnd.H,        //nHeight
    hDlg,          //hWndParent
    0,             //hMenu
    hInstDLL,      //hInstance
    HistCallback); //Script function callback. To use it class must be registered by WindowRegisterClass.

  oSys.Call("User32::EnableWindow", hMainWnd, 0);
  oSys.Call("User32::EnableWindow", hDlg, 0);

  function HistCallback(hWnd, uMsg, wParam, lParam)
  {
    var nID, nCode, nPos, i;

    if (uMsg == 1 /*WM_CREATE*/)
    {
      for (i = IDHISTLB; i < aWnd.length; ++i)
      {
        aWnd[i].HWND = oSys.Call("User32::CreateWindowExW",
          0,         //dwExStyle
          aWnd[i].C, //lpClassName
          aWnd[i].T, //lpWindowName
          aWnd[i].S, //dwStyle
          aWnd[i].X, //x
          aWnd[i].Y, //y
          aWnd[i].W, //nWidth
          aWnd[i].H, //nHeight
          hWnd,      //hWndParent
          i,         //ID
          hInstDLL,  //hInstance
          0);        //lpParam
        SendMessage(aWnd[i].HWND, 48 /*WM_SETFONT*/, hGuiFont, 1);
      }

      if (! hMainWnd)
        SendMessage(hWnd, 0x0080 /*WM_SETICON*/, 0 /*ICON_SMALL*/, hIconSmall);

      SendMessage(aWnd[IDHISTLB].HWND, 0x0180 /*LB_ADDSTRING*/, 0, "");
      for (i = 0; i < aHist.length; ++i)
        SendMessage(aWnd[IDHISTLB].HWND, 0x0180 /*LB_ADDSTRING*/, 0, aHist[i][0].substr(0, 1024));
      SendMessage(aWnd[IDHISTLB].HWND, 0x0186 /*LB_SETCURSEL*/, 0, 0);
      PostMessage(hWnd, 273 /*WM_COMMAND*/, MkLong(IDHISTLB, 1 /*LBN_SELCHANGE*/), aWnd[IDHISTLB].HWND);

      aWnd.Focus = aWnd[IDHISTLB].HWND;
    }

    else if (uMsg == 6 /*WM_ACTIVATE*/)
    {
      if (wParam == 0 /*WA_INACTIVE*/)
        aWnd.Focus = oSys.Call("User32::GetFocus");
    }

    else if (uMsg == 7 /*WM_SETFOCUS*/)
      oSys.Call("User32::SetFocus", aWnd.Focus);

    else if (uMsg == 256 /*WM_KEYDOWN*/)
    {
      if (wParam == 0x02E /*VK_DELETE*/)
        PostMessage(hWnd, 273 /*WM_COMMAND*/, IDDELETEB, aWnd[IDDELETEB].HWND);
      else if (wParam == 13 /*VK_RETURN*/)
      {
        if (oSys.Call("User32::GetFocus") == aWnd[IDHISTLB].HWND)
          PostMessage(hWnd, 16 /*WM_CLOSE*/, 1, 0);
      }
    }

    else if (uMsg == 273 /*WM_COMMAND*/)
    {
      nID   = LoWord(wParam);
      nCode = HiWord(wParam);

      if (nID == IDHISTLB)
      {
        if (nCode == 1 /*LBN_SELCHANGE*/)
        {
          nPos = SendMessage(aWnd[IDHISTLB].HWND, 0x0188 /*LB_GETCURSEL*/, 0, 0);
          if (nPos == 0)
          {
            if (aHist.length)
            {
              ReplaceTextAE(aDlg[IDCMDE].HWND, sCurCmd);
              ReplaceTextAE(aDlg[IDDIRE].HWND, sCurDir);
            }
            else
              PostMessage(hWnd, 16 /*WM_CLOSE*/, 0, 0);
          }
          else if (nPos > 0)
          {
            ReplaceTextAE(aDlg[IDCMDE].HWND, aHist[nPos - 1][0]);
            ReplaceTextAE(aDlg[IDDIRE].HWND, aHist[nPos - 1][1]);
          }
          oSys.Call("User32::EnableWindow", aWnd[IDDELETEB].HWND, (nPos > 0));
        }
        else if (nCode == 2 /*LBN_DBLCLK*/)
          PostMessage(hWnd, 16 /*WM_CLOSE*/, 1, 0);
        else if (nCode == 4 /*LBN_SETFOCUS*/)
          PostMessage(aWnd[IDOKB].HWND, 0xF4 /*BM_SETSTYLE*/, 1 /*BS_DEFPUSHBUTTON*/, 1);
      }

      else if (nID == IDDELETEB)
      {
        oSys.Call("User32::SetFocus", aWnd[IDHISTLB].HWND);

        nPos = SendMessage(aWnd[IDHISTLB].HWND, 0x0188 /*LB_GETCURSEL*/, 0, 0);

        if (nPos > 0)
        {
          aHist.splice(nPos - 1, 1);
          SendMessage(aWnd[IDHISTLB].HWND, 0x0182 /*LB_DELETESTRING*/, nPos, 0);

          if (nPos > aHist.length) --nPos;
          SendMessage(aWnd[IDHISTLB].HWND, 0x0186 /*LB_SETCURSEL*/, nPos, 0);
          PostMessage(hWnd, 273 /*WM_COMMAND*/, MkLong(IDHISTLB, 1 /*LBN_SELCHANGE*/), aWnd[IDHISTLB].HWND);
        }
      }

      else if (nID == IDCLEARB)
      {
        aHist.length = 0;
        PostMessage(hWnd, 16 /*WM_CLOSE*/, 0, 0);
      }

      else if (nID == IDOKB)
        PostMessage(hWnd, 16 /*WM_CLOSE*/, 1, 0);

      else if ((nID == IDCANCELB) || (nID == 2 /*IDCANCEL*/))
        PostMessage(hWnd, 16 /*WM_CLOSE*/, 0, 0);
    }

    else if (uMsg == 16 /*WM_CLOSE*/)
    {
      if (wParam)
        aDlg.Focus = aDlg[IDCMDE].HWND;
      else
      {
        ReplaceTextAE(aDlg[IDCMDE].HWND, sCurCmd);
        ReplaceTextAE(aDlg[IDDIRE].HWND, sCurDir);
      }

      oSys.Call("User32::EnableWindow", hMainWnd, 1);
      oSys.Call("User32::EnableWindow", hDlg, 1);
      oSys.Call("User32::DestroyWindow", hWnd);
    }

    return 0;
  }
}

function Settings()
{
  var bFontDef1  = bFontDef;
  var bColorDef1 = bColorDef;
  var aFont1     = [aFont[0], aFont[1], aFont[2]];
  var aColor1    = [aColor[0], aColor[1], aColor[2], aColor[3], aColor[4], aColor[5], aColor[6]];

  var oRect = {};
  var nW21  = Scale.X(21);
  var nW50  = Scale.X(50);
  var nW70  = Scale.X(70);
  var nW100 = Scale.X(100);
  var nW220 = Scale.X(220);
  var nH13  = Scale.Y(13);
  var nH16  = Scale.Y(16);
  var nH21  = Scale.Y(21);
  var nH23  = Scale.Y(23);

  var IDSHOWB     = 2000;
  var IDHISTE     = 2001;
  var IDHISTUD    = 2002;
  var IDHISTS     = 2003;
  var IDEDITGB    = 2004;
  var IDFONTGB    = 2005;
  var IDFONTDEFB  = 2006;
  var IDFONTB     = 2007;
  var IDCOLORGB   = 2008;
  var IDCOLORDEFB = 2009;
  var IDTCOLOR1B  = 2010;
  var IDBCOLOR1B  = 2011;
  var IDCOLOR1S   = 2012;
  var IDTCOLOR2B  = 2013;
  var IDBCOLOR2B  = 2014;
  var IDCOLOR2S   = 2015;
  var IDTCOLOR3B  = 2016;
  var IDBCOLOR3B  = 2017;
  var IDCOLOR3S   = 2018;
  var IDCOLOR4B   = 2019;
  var IDCOLOR4S   = 2020;
  var IDOKB       = 2021;
  var IDCANCELB   = 2022;
  var aWnd        = [];

  aWnd[IDSHOWB]     = {X: 10, Y: 10, W: nW220, H: nH16, T: sTxtShowWnd, C: "BUTTON", S: 0x50010003 /*WS_CHILD|WS_VISIBLE|WS_TABSTOP|BS_AUTOCHECKBOX*/};
  aWnd[IDHISTE]     = {X: 10, Y: aWnd[IDSHOWB].Y + aWnd[IDSHOWB].H + 10, W: nW50, H: nH21, C: "EDIT", S: 0x50012000 /*WS_CHILD|WS_VISIBLE|WS_TABSTOP|ES_NUMBER*/, ES: 0x00000200 /*WS_EX_CLIENTEDGE*/};
  aWnd[IDHISTUD]    = {C: "msctls_updown32", S: 0x50000026 /*WS_CHILD|WS_VISIBLE|UDS_ALIGNRIGHT|UDS_ARROWKEYS|UDS_SETBUDDYINT*/};
  aWnd[IDHISTS]     = {X: aWnd[IDHISTE].X + aWnd[IDHISTE].W + 5, Y: aWnd[IDHISTE].Y + 4, W: nW100, H: nH13, T: sTxtHistLen, C: "STATIC", S: 0x50000000 /*WS_CHILD|WS_VISIBLE*/};
  aWnd[IDEDITGB]    = {X: 10, Y: aWnd[IDHISTE].Y + aWnd[IDHISTE].H + 10, W: nW220, H: nH16 * 2 + nH23 + nH21 * 4 + 115, T: sTxtEditWnds, C: "BUTTON", S: 0x50000007 /*WS_CHILD|WS_VISIBLE|BS_GROUPBOX*/};
  aWnd[IDFONTGB]    = {X: 20, Y: aWnd[IDEDITGB].Y + 20, W: nW220 - 20, H: nH16 + nH23 + 30, T: sTxtFont, C: "BUTTON", S: 0x50000307 /*WS_CHILD|WS_VISIBLE|BS_CENTER|BS_GROUPBOX*/};
  aWnd[IDFONTDEFB]  = {X: 30, Y: aWnd[IDFONTGB].Y + 15, W: nW100, H: nH16, T: sTxtDefFont, C: "BUTTON", S: 0x50010003 /*WS_CHILD|WS_VISIBLE|WS_TABSTOP|BS_AUTOCHECKBOX*/};
  aWnd[IDFONTB]     = {X: 30, Y: aWnd[IDFONTDEFB].Y + aWnd[IDFONTDEFB].H + 5, W: nW220 - 40, H: nH23, C: "BUTTON", S: 0x50010000 /*WS_CHILD|WS_VISIBLE|WS_TABSTOP|BS_PUSHBUTTON*/};
  aWnd[IDCOLORGB]   = {X: 20, Y: aWnd[IDFONTGB].Y + aWnd[IDFONTGB].H + 10, W: nW220 - 20, H: nH16 + nH21 * 4 + 45, T: sTxtColors, C: "BUTTON", S: 0x50000307 /*WS_CHILD|WS_VISIBLE|BS_CENTER|BS_GROUPBOX*/};
  aWnd[IDCOLORDEFB] = {X: 30, Y: aWnd[IDCOLORGB].Y + 15, W: nW100, H: nH16, T: sTxtDefColors, C: "BUTTON", S: 0x50010003 /*WS_CHILD|WS_VISIBLE|WS_TABSTOP|BS_AUTOCHECKBOX*/};
  aWnd[IDTCOLOR1B]  = {X: 60, Y: aWnd[IDCOLORDEFB].Y + aWnd[IDCOLORDEFB].H + 5, W: nW21, H: nH21, C: "BUTTON", S: 0x5081000B /*WS_CHILD|WS_VISIBLE|WS_TABSTOP|WS_BORDER|BS_OWNERDRAW*/};
  aWnd[IDBCOLOR1B]  = {X: aWnd[IDTCOLOR1B].X + aWnd[IDTCOLOR1B].W + 5, Y: aWnd[IDTCOLOR1B].Y, W: nW21, H: nH21, C: "BUTTON", S: 0x5081000B /*WS_CHILD|WS_VISIBLE|WS_TABSTOP|WS_BORDER|BS_OWNERDRAW*/};
  aWnd[IDCOLOR1S]   = {X: aWnd[IDBCOLOR1B].X + aWnd[IDBCOLOR1B].W + 5, Y: aWnd[IDBCOLOR1B].Y + 4, W: nW100, H: nH13, T: sTxtBasic, C: "STATIC", S: 0x50000000 /*WS_CHILD|WS_VISIBLE*/};
  aWnd[IDTCOLOR2B]  = {X: aWnd[IDTCOLOR1B].X, Y: aWnd[IDTCOLOR1B].Y + aWnd[IDTCOLOR1B].H + 5, W: nW21, H: nH21, C: "BUTTON", S: 0x5081000B /*WS_CHILD|WS_VISIBLE|WS_TABSTOP|WS_BORDER|BS_OWNERDRAW*/};
  aWnd[IDBCOLOR2B]  = {X: aWnd[IDBCOLOR1B].X, Y: aWnd[IDTCOLOR2B].Y, W: nW21, H: nH21, C: "BUTTON", S: 0x5081000B /*WS_CHILD|WS_VISIBLE|WS_TABSTOP|WS_BORDER|BS_OWNERDRAW*/};
  aWnd[IDCOLOR2S]   = {X: aWnd[IDCOLOR1S].X, Y: aWnd[IDBCOLOR2B].Y + 4, W: nW100, H: nH13, T: sTxtSelection, C: "STATIC", S: 0x50000000 /*WS_CHILD|WS_VISIBLE*/};
  aWnd[IDTCOLOR3B]  = {X: aWnd[IDTCOLOR1B].X, Y: aWnd[IDTCOLOR2B].Y + aWnd[IDTCOLOR2B].H + 5, W: nW21, H: nH21, C: "BUTTON", S: 0x5081000B /*WS_CHILD|WS_VISIBLE|WS_TABSTOP|WS_BORDER|BS_OWNERDRAW*/};
  aWnd[IDBCOLOR3B]  = {X: aWnd[IDBCOLOR2B].X, Y: aWnd[IDTCOLOR3B].Y, W: nW21, H: nH21, C: "BUTTON", S: 0x5081000B /*WS_CHILD|WS_VISIBLE|WS_TABSTOP|WS_BORDER|BS_OWNERDRAW*/};
  aWnd[IDCOLOR3S]   = {X: aWnd[IDCOLOR2S].X, Y: aWnd[IDBCOLOR3B].Y + 4, W: nW100, H: nH13, T: sTxtCurLine, C: "STATIC", S: 0x50000000 /*WS_CHILD|WS_VISIBLE*/};
  aWnd[IDCOLOR4B]   = {X: aWnd[IDTCOLOR1B].X, Y: aWnd[IDTCOLOR3B].Y + aWnd[IDTCOLOR3B].H + 5, W: nW21, H: nH21, C: "BUTTON", S: 0x5081000B /*WS_CHILD|WS_VISIBLE|WS_TABSTOP|WS_BORDER|BS_OWNERDRAW*/};
  aWnd[IDCOLOR4S]   = {X: aWnd[IDCOLOR3S].X, Y: aWnd[IDCOLOR4B].Y + 4, W: nW100, H: nH13, T: sTxtCaret, C: "STATIC", S: 0x50000000 /*WS_CHILD|WS_VISIBLE*/};
  aWnd[IDOKB]       = {X: 10 + nW220 - nW70 * 2 - 5, Y: aWnd[IDEDITGB].Y + aWnd[IDEDITGB].H + 10, W: nW70, H: nH23, T: sTxtOK, C: "BUTTON", S: 0x50010001 /*WS_CHILD|WS_VISIBLE|WS_TABSTOP|BS_DEFPUSHBUTTON*/};
  aWnd[IDCANCELB]   = {X: aWnd[IDOKB].X + aWnd[IDOKB].W + 5, Y: aWnd[IDOKB].Y, W: nW70, H: nH23, T: sTxtCancel, C: "BUTTON", S: 0x50010000 /*WS_CHILD|WS_VISIBLE|WS_TABSTOP|BS_PUSHBUTTON*/};

  GetWindowPos(hDlg, oRect);
  aWnd.W = nW220 + 20 + oSys.Call("User32::GetSystemMetrics", 7 /*SM_CXFIXEDFRAME*/) * 2;
  aWnd.H = aWnd[IDOKB].Y + aWnd[IDOKB].H + 10 + oSys.Call("User32::GetSystemMetrics", 4 /*SM_CYCAPTION*/) + oSys.Call("User32::GetSystemMetrics", 8 /*SM_CYFIXEDFRAME*/);
  aWnd.X = oRect.X + (oRect.W - aWnd.W) / 2;
  aWnd.Y = oRect.Y + (oRect.H - aWnd.H) / 2;
  aWnd.T = sTxtSettings.replace("&", "");

  oSys.Call("User32::CreateWindowExW",
    0,            //dwExStyle
    sClass,       //lpClassName
    aWnd.T,       //lpWindowName
    0x90C80000,   //dwStyle=WS_VISIBLE|WS_POPUP|WS_CAPTION|WS_SYSMENU
    aWnd.X,       //x
    aWnd.Y,       //y
    aWnd.W,       //nWidth
    aWnd.H,       //nHeight
    hDlg,         //hWndParent
    0,            //hMenu
    hInstDLL,     //hInstance
    SetCallback); //Script function callback. To use it class must be registered by WindowRegisterClass.

  oSys.Call("User32::EnableWindow", hMainWnd, 0);
  oSys.Call("User32::EnableWindow", hDlg, 0);

  function SetCallback(hWnd, uMsg, wParam, lParam)
  {
    var nID, i;

    if (uMsg == 1 /*WM_CREATE*/)
    {
      for (i = IDSHOWB; i < aWnd.length; ++i)
      {
        aWnd[i].HWND = oSys.Call("User32::CreateWindowExW",
          aWnd[i].ES, //dwExStyle
          aWnd[i].C,  //lpClassName
          aWnd[i].T,  //lpWindowName
          aWnd[i].S,  //dwStyle
          aWnd[i].X,  //x
          aWnd[i].Y,  //y
          aWnd[i].W,  //nWidth
          aWnd[i].H,  //nHeight
          hWnd,       //hWndParent
          i,          //ID
          hInstDLL,   //hInstance
          0);         //lpParam
        SendMessage(aWnd[i].HWND, 48 /*WM_SETFONT*/, hGuiFont, 1);
      }

      if (! hMainWnd)
        SendMessage(hWnd, 0x0080 /*WM_SETICON*/, 0 /*ICON_SMALL*/, hIconSmall);

      SendMessage(aWnd[IDHISTUD].HWND, 1129 /*UDM_SETBUDDY*/, aWnd[IDHISTE].HWND, 0);
      SendMessage(aWnd[IDHISTUD].HWND, 1135 /*UDM_SETRANGE32*/, 0, 100);
      SendMessage(aWnd[IDHISTUD].HWND, 1137 /*UDM_SETPOS32*/, 0, nHistMax);
      SendMessage(aWnd[IDSHOWB].HWND,     241 /*BM_SETCHECK*/, bShowWnd, 0);
      SendMessage(aWnd[IDFONTDEFB].HWND,  241 /*BM_SETCHECK*/, bFontDef, 0);
      SendMessage(aWnd[IDCOLORDEFB].HWND, 241 /*BM_SETCHECK*/, bColorDef, 0);

      PostMessage(hWnd, 273 /*WM_COMMAND*/, IDFONTDEFB, aWnd[IDFONTDEFB].HWND);
      PostMessage(hWnd, 273 /*WM_COMMAND*/, IDCOLORDEFB, aWnd[IDCOLORDEFB].HWND);

      aWnd.Focus = aWnd[IDSHOWB].HWND;
    }

    else if (uMsg == 6 /*WM_ACTIVATE*/)
    {
      if (wParam == 0 /*WA_INACTIVE*/)
        aWnd.Focus = oSys.Call("User32::GetFocus");
    }

    else if (uMsg == 7 /*WM_SETFOCUS*/)
      oSys.Call("User32::SetFocus", aWnd.Focus);

    else if (uMsg == 43 /*WM_DRAWITEM*/)
    {
      if ((wParam == IDTCOLOR1B) || (wParam == IDBCOLOR1B) || (wParam == IDTCOLOR2B) || (wParam == IDBCOLOR2B) || (wParam == IDTCOLOR3B) || (wParam == IDBCOLOR3B) || (wParam == IDCOLOR4B))
      {
        DrawColorButton(wParam, lParam);
        return 1;
      }
    }

    else if (uMsg == 256 /*WM_KEYDOWN*/)
    {
      nID = oSys.Call("User32::GetDlgCtrlID", oSys.Call("User32::GetFocus"));

      if (wParam == 9 /*VK_TAB*/)
      {
        if ((nID != IDFONTB) && (nID != IDCANCELB))
          SendMessage(aWnd[IDOKB].HWND, 0xF4 /*BM_SETSTYLE*/, 1 /*BS_DEFPUSHBUTTON*/, 1);
      }
      else if (wParam == 13 /*VK_RETURN*/)
      {
        if ((nID != IDFONTB) && (nID != IDOKB) && (nID != IDCANCELB))
          PostMessage(hWnd, 273 /*WM_COMMAND*/, IDOKB, aWnd[IDOKB].HWND);
      }
    }

    else if (uMsg == 273 /*WM_COMMAND*/)
    {
      nID = LoWord(wParam);

      if ((nID == IDSHOWB) || (nID == IDHISTE))
        SendMessage(aWnd[IDOKB].HWND, 0xF4 /*BM_SETSTYLE*/, 1 /*BS_DEFPUSHBUTTON*/, 1);

      else if (nID == IDFONTDEFB)
      {
        bFontDef = SendMessage(lParam, 240 /*BM_GETCHECK*/, 0, 0);
        SetEditFont();
        oSys.Call("User32::SetWindowTextW", aWnd[IDFONTB].HWND, bFontDef ? ConvertFontFormat(hGuiFont, 2, 3).toString() : aFont.toString());
        oSys.Call("User32::EnableWindow", aWnd[IDFONTB].HWND, ! bFontDef);
        SendMessage(aWnd[IDOKB].HWND, 0xF4 /*BM_SETSTYLE*/, 1 /*BS_DEFPUSHBUTTON*/, 1);
      }

      else if (nID == IDFONTB)
      {
        ChooseFont(hWnd, aWnd[IDFONTB].HWND);
        SetEditFont();
        oSys.Call("User32::SetWindowTextW", aWnd[IDFONTB].HWND, aFont.toString());
      }

      else if (nID == IDCOLORDEFB)
      {
        bColorDef = SendMessage(lParam, 240 /*BM_GETCHECK*/, 0, 0);
        EditColors(1, bColorDef ? aColorDef : aColor);
        oSys.Call("User32::EnableWindow", aWnd[IDTCOLOR1B].HWND, ! bColorDef);
        oSys.Call("User32::EnableWindow", aWnd[IDBCOLOR1B].HWND, ! bColorDef);
        oSys.Call("User32::EnableWindow", aWnd[IDTCOLOR2B].HWND, ! bColorDef);
        oSys.Call("User32::EnableWindow", aWnd[IDBCOLOR2B].HWND, ! bColorDef);
        oSys.Call("User32::EnableWindow", aWnd[IDTCOLOR3B].HWND, ! bColorDef);
        oSys.Call("User32::EnableWindow", aWnd[IDBCOLOR3B].HWND, ! bColorDef);
        oSys.Call("User32::EnableWindow", aWnd[IDCOLOR4B].HWND,  ! bColorDef);
        SendMessage(aWnd[IDOKB].HWND, 0xF4 /*BM_SETSTYLE*/, 1 /*BS_DEFPUSHBUTTON*/, 1);
      }

      else if ((nID == IDTCOLOR1B) || (nID == IDBCOLOR1B) || (nID == IDTCOLOR2B) || (nID == IDBCOLOR2B) || (nID == IDTCOLOR3B) || (nID == IDBCOLOR3B) || (nID == IDCOLOR4B))
      {
        ChooseColor(hWnd, nID);
        EditColors(1, bColorDef ? aColorDef : aColor);
        SendMessage(aWnd[IDOKB].HWND, 0xF4 /*BM_SETSTYLE*/, 1 /*BS_DEFPUSHBUTTON*/, 1);
      }

      else if (nID == IDOKB)
      {
        bShowWnd = SendMessage(aWnd[IDSHOWB].HWND, 240 /*BM_GETCHECK*/, 0, 0);

        if (! HiWord(SendMessage(aWnd[IDHISTUD].HWND, 1128 /*UDM_GETPOS*/, 0, 0)))
        {
          nHistMax = LoWord(SendMessage(aWnd[IDHISTUD].HWND, 1128 /*UDM_GETPOS*/, 0, 0));
          if (aHist.length > nHistMax)
            aHist.length = nHistMax;
        }

        PostMessage(hWnd, 16 /*WM_CLOSE*/, 0, 1);
      }

      else if ((nID == IDCANCELB) || (nID == 2 /*IDCANCEL*/))
        PostMessage(hWnd, 16 /*WM_CLOSE*/, 0, 0);
    }

    else if (uMsg == 16 /*WM_CLOSE*/)
    {
      if (! lParam)
      {
        bFontDef  = bFontDef1;
        bColorDef = bColorDef1;

        for (i = 0; i < aFont.length; ++i)
          aFont[i] = aFont1[i];
        for (i = 0; i < aColor.length; ++i)
          aColor[i] = aColor1[i];
      }

      SetEditFont();
      EnableWindows();

      oSys.Call("User32::EnableWindow", hMainWnd, 1);
      oSys.Call("User32::EnableWindow", hDlg, 1);
      oSys.Call("User32::DestroyWindow", hWnd);
    }

    return 0;
  }

  function DrawColorButton(nID, lpDRAWITEMSTRUCT)
  {
    var hDC    = AkelPad.MemRead(_PtrAdd(lpDRAWITEMSTRUCT, _X64 ? 32 : 24), 2 /*DT_QWORD*/);
    var lpRect = _PtrAdd(lpDRAWITEMSTRUCT, _X64 ? 40 : 28);
    var nCI    = GetColorIndex(nID);
    var nRGB   = SendMessage(aWnd[IDCOLORDEFB].HWND, 240 /*BM_GETCHECK*/, 0, 0) ? aColorDef[nCI] : aColor[nCI];
    var hBrush = oSys.Call("Gdi32::CreateSolidBrush", nRGB);

    oSys.Call("User32::FillRect", hDC, lpRect, hBrush);
    if (oSys.Call("User32::GetFocus") == aWnd[nID].HWND)
      oSys.Call("User32::DrawFocusRect", hDC, lpRect);

    oSys.Call("Gdi32::DeleteObject", hBrush);
  }

  function GetColorIndex(nID)
  {
    var i;

    if (nID == IDTCOLOR1B)
      i = 1;
    else if (nID == IDBCOLOR1B)
      i = 2;
    else if (nID == IDTCOLOR2B)
      i = 3;
    else if (nID == IDBCOLOR2B)
      i = 4;
    else if (nID == IDTCOLOR3B)
      i = 5;
    else if (nID == IDBCOLOR3B)
      i = 6;
    else if (nID == IDCOLOR4B)
      i = 0;

    return i;
  }

  function ChooseColor(hWndOwn, nID)
  {
    var nChoCoSize = _X64 ? 72 : 36 /*sizeof(CHOOSECOLOR)*/;
    var lpChoCo    = AkelPad.MemAlloc(nChoCoSize);
    var lpCusCo    = AkelPad.MemAlloc(16 * 4 /*sizeof(COLORREF)*/);
    var nCI        = GetColorIndex(nID);

    AkelPad.MemCopy(_PtrAdd(lpChoCo, 0),              nChoCoSize,  3 /*DT_DWORD*/); //lStructSize
    AkelPad.MemCopy(_PtrAdd(lpChoCo, _X64 ?  8 :  4), hWndOwn,     2 /*DT_QWORD*/); //hWndOwner
    AkelPad.MemCopy(_PtrAdd(lpChoCo, _X64 ? 24 : 12), aColor[nCI], 3 /*DT_DWORD*/); //rgbResult
    AkelPad.MemCopy(_PtrAdd(lpChoCo, _X64 ? 32 : 16), lpCusCo,     2 /*DT_QWORD*/); //lpCustColors
    AkelPad.MemCopy(_PtrAdd(lpChoCo, _X64 ? 40 : 20), 0x103,       3 /*DT_DWORD*/); //Flags=CC_ANYCOLOR|CC_FULLOPEN|CC_RGBINIT

    if (oSys.Call("Comdlg32::ChooseColorW", lpChoCo))
    {
      aColor[nCI] = AkelPad.MemRead(_PtrAdd(lpChoCo, _X64 ? 24 : 12), 3 /*DT_DWORD*/);
      oSys.Call("User32::InvalidateRect", aWnd[nID].HWND, 0, true);
    }

    AkelPad.MemFree(lpChoCo);
    AkelPad.MemFree(lpCusCo);
  }
}

function ChooseFont(hWndOwn, hWndPos)
{
  var hMenu = oSys.Call("User32::CreatePopupMenu");
  var oRect = {};
  var nCmd;

  GetWindowPos(hWndPos, oRect);
  oSys.Call("User32::AppendMenuW", hMenu, 0 /*MF_STRING*/, 1, sTxtMonoFonts);
  oSys.Call("User32::AppendMenuW", hMenu, 0 /*MF_STRING*/, 2, sTxtAllFonts);

  nCmd = oSys.Call("User32::TrackPopupMenu", hMenu, 0x0180 /*TPM_RETURNCMD|TPM_NONOTIFY*/, oRect.X, oRect.Y + oRect.H, 0, hWndOwn, 0);
  oSys.Call("User32::DestroyMenu", hMenu);

  if (! nCmd)
    return;

  try
  {
    oSys.RegisterCallback(CFCallback);
  }
  catch (oError)
  {
    AkelPad.MessageBox(hWndOwn, sTxtNoCallback, sTxtDlgTitle, 0x10 /*MB_ICONERROR*/);
    return;
  }

  var nCFSize = _X64 ? 104 : 60 /*sizeof(CHOOSEFONTW)*/;
  var lpCF    = AkelPad.MemAlloc(nCFSize);
  var lpLF    = ConvertFontFormat(aFont, 3, 1);
  var nFlags  = 0x00010049 /*CF_ENABLEHOOK|CF_FORCEFONTEXIST|CF_INITTOLOGFONTSTRUCT|CF_SCREENFONTS*/ | ((nCmd == 1) ? 0x00004000 /*CF_FIXEDPITCHONLY*/ : 0);

  AkelPad.MemCopy(_PtrAdd(lpCF, 0),                 nCFSize, 3 /*DT_DWORD*/); //lStructSize
  AkelPad.MemCopy(_PtrAdd(lpCF, _X64 ?  8 :  4),    hWndOwn, 2 /*DT_QWORD*/); //hwndOwner
  AkelPad.MemCopy(_PtrAdd(lpCF, _X64 ? 24 : 12),       lpLF, 2 /*DT_QWORD*/); //lpLogFont
  AkelPad.MemCopy(_PtrAdd(lpCF, _X64 ? 36 : 20),     nFlags, 3 /*DT_DWORD*/); //Flags
  AkelPad.MemCopy(_PtrAdd(lpCF, _X64 ? 48 : 28),    hWndPos, 2 /*DT_QWORD*/); //lCustData
  AkelPad.MemCopy(_PtrAdd(lpCF, _X64 ? 56 : 32), CFCallback, 2 /*DT_QWORD*/); //lpfnHook

  if (oSys.Call("Comdlg32::ChooseFontW", lpCF))
    aFont = ConvertFontFormat(lpLF, 1, 3);

  oSys.UnregisterCallback(CFCallback);
  AkelPad.MemFree(lpCF);
  AkelPad.MemFree(lpLF);
}

function CFCallback(hWnd, uMsg, wParam, lParam)
{
  if (uMsg == 272 /*WM_INITDIALOG*/)
  {
    var oRectWnd = {};
    var oRectPos = {};

    SendMessage(hWnd, 0x0080 /*WM_SETICON*/, 0 /*ICON_SMALL*/, hIconSmall);
    SendMessage(hWnd, 12 /*WM_SETTEXT*/, 0, (AkelPad.MemRead(_PtrAdd(lParam, _X64 ? 36 : 20), 3 /*DT_DWORD*/) & 0x00004000 /*CF_FIXEDPITCHONLY*/) ? sTxtMonoFonts : sTxtAllFonts);

    GetWindowPos(hWnd, oRectWnd);
    GetWindowPos(AkelPad.MemRead(_PtrAdd(lParam, _X64 ? 48 : 28), 2 /*DT_QWORD*/), oRectPos);
    oRectWnd.X = oRectPos.X + (oRectPos.W - oRectWnd.W) / 2;
    oRectWnd.Y = oRectPos.Y + oRectPos.H;

    oSys.Call("User32::MoveWindow", hWnd, oRectWnd.X, oRectWnd.Y, oRectWnd.W, oRectWnd.H, 0);
  }

  return 0;
}

function ConvertFontFormat(vFont, nInType, nRetType)
{
  var nLFSize = 28 + 32 * 2 /*sizeof(LOGFONTW)*/;
  var lpLF    = AkelPad.MemAlloc(nLFSize);
  var hFont;
  var hDC;
  var nHeight;
  var nWeight;
  var bItalic;
  var vRetVal;
  var i;

  if (nInType == 1)
  {
    for (i = 0; i < nLFSize; ++i)
      AkelPad.MemCopy(_PtrAdd(lpLF, i), AkelPad.MemRead(_PtrAdd(vFont, i), 5 /*DT_BYTE*/), 5 /*DT_BYTE*/);
  }
  else if (nInType == 2)
  {
    if (! vFont)
      vFont = oSys.Call("Gdi32::GetStockObject", 13 /*SYSTEM_FONT*/);

    oSys.Call("Gdi32::GetObjectW", vFont, nLFSize, lpLF);
  }
  else if (nInType == 3)
  {
    hDC     = oSys.Call("User32::GetDC", hMainWnd);
    nHeight = -oSys.Call("Kernel32::MulDiv", vFont[2], oSys.Call("Gdi32::GetDeviceCaps", hDC, 90 /*LOGPIXELSY*/), 72);
    oSys.Call("User32::ReleaseDC", hMainWnd, hDC);

    nWeight = 400;
    bItalic = 0;
    if ((vFont[1] == 2) || (vFont[1] == 4))
      nWeight = 700;
    if (vFont[1] > 2)
      bItalic = 1;

    AkelPad.MemCopy(_PtrAdd(lpLF,  0), nHeight,  3 /*DT_DWORD*/);   //lfHeight
    AkelPad.MemCopy(_PtrAdd(lpLF, 16), nWeight,  3 /*DT_DWORD*/);   //lfWeight
    AkelPad.MemCopy(_PtrAdd(lpLF, 20), bItalic,  5 /*DT_BYTE*/);    //lfItalic
    AkelPad.MemCopy(_PtrAdd(lpLF, 28), vFont[0], 1 /*DT_UNICODE*/); //lfFaceName
  }

  if (nRetType == 1)
    vRetVal = lpLF;
  else if (nRetType == 2)
  {
    vRetVal = oSys.Call("Gdi32::CreateFontIndirectW", lpLF);
    AkelPad.MemFree(lpLF);
  }
  else if (nRetType == 3)
  {
    vRetVal    = [];
    vRetVal[0] = AkelPad.MemRead(_PtrAdd(lpLF, 28), 1 /*DT_UNICODE*/);

    if (AkelPad.MemRead(_PtrAdd(lpLF, 16), 3 /*DT_DWORD*/) < 600)
      vRetVal[1] = 1;
    else
      vRetVal[1] = 2;

    if (AkelPad.MemRead(_PtrAdd(lpLF, 20), 5 /*DT_BYTE*/))
      vRetVal[1] += 2;

    hDC        = oSys.Call("User32::GetDC", hMainWnd);
    vRetVal[2] = -oSys.Call("Kernel32::MulDiv", AkelPad.MemRead(lpLF, 3 /*DT_DWORD*/), 72, oSys.Call("Gdi32::GetDeviceCaps", hDC, 90 /*LOGPIXELSY*/));
    oSys.Call("User32::ReleaseDC", hMainWnd, hDC); 
    AkelPad.MemFree(lpLF);
  }

  return vRetVal;
}

function ReadIni()
{
  var sFile = WScript.ScriptFullName.replace(/js$/i, "ini");
  var oFile;

  if (oFSO.FileExists(sFile))
  {
    oFile = oFSO.OpenTextFile(sFile, 1, false, -1);

    try
    {
      eval(oFile.ReadAll());
    }
    catch (oError)
    {}

    oFile.Close();
  }

  aDlg.W = Math.max(Scale.X(aDlg.W), aDlg.MinW);
  aDlg.H = Math.max(Scale.Y(aDlg.H), aDlg.MinH);

  if (! aFont)
    aFont = ConvertFontFormat(hGuiFont, 2, 3);
}

function WriteIni()
{
  var oFile = oFSO.OpenTextFile(WScript.ScriptFullName.replace(/js$/i, "ini"), 2, true, -1);
  var sText = "";
  var i;

  sText +=
    'aDlg.X='     + aDlg.X + ';\r\n' +
    'aDlg.Y='     + aDlg.Y + ';\r\n' +
    'aDlg.W='     + Scale.UX(aDlg.W) + ';\r\n' +
    'aDlg.H='     + Scale.UY(aDlg.H) + ';\r\n' +
    'aDlg.Max='   + oSys.Call("User32::IsZoomed", hDlg) + ';\r\n' +
    'sCmd="'      + EscapeStr(sCmd) + '";\r\n' +
    'sDir="'      + EscapeStr(sDir) + '";\r\n' +
    'sLastFile="' + EscapeStr(sLastFile) + '";\r\n' +
    'bShowWnd='   + bShowWnd + ';\r\n' +
    'bFontDef='   + bFontDef + ';\r\n' +
    'aFont=["'    + EscapeStr(aFont[0]) + '",' + aFont[1] + ',' + aFont[2] + '];\r\n' +
    'bColorDef='  + bColorDef + ';\r\n' +
    'aColor=['    + aColor.toString() + '];\r\n' +
    'nHistMax='   + nHistMax + ';\r\n' +
    'aHist=[';

  for (i = 0; i < aHist.length; ++i)
    sText +=
      '["' +
      EscapeStr(aHist[i][0]) + '","' +
      EscapeStr(aHist[i][1]) + '"]' +
      ((i == aHist.length - 1) ? '' : ',');

  sText += '];';

  oFile.Write(sText);
  oFile.Close();
}

function EscapeStr(sStr)
{
  return sStr.replace(/[\\"]/g, '\\$&').replace(/\n/g, '\\n').replace(/\r/g, '\\r');
}

function GetLangStrings()
{
  if ((hMainWnd && (AkelPad.GetLangId(0 /*LANGID_FULL*/) == 1045)) || ((! hMainWnd) && (oSys.Call("Kernel32::GetUserDefaultLangID") == 1045))) //Polish
  {
    sTxtDlgTitle   = "Uruchom polecenie";
    sTxtCommand    = "Polecenie:";
    sTxtWorkDir    = "Katalog roboczy:";
    sTxtOutput     = "Wyjście:";
    sTxtRun        = "Uruchom";
    sTxtStop       = "Zatrzymaj";
    sTxtFiles      = "&Pliki";
    sTxtDirs       = "&Katalogi";
    sTxtBrowse     = "&Przeglądaj";
    sTxtHistory    = "&Historia";
    sTxtSettings   = "U&stawienia";
    sTxtCantExec   = "Nie można uruchomić polecenia.";
    sTxtNoDir      = "Katalog nie istnieje.";
    sTxtStopClose  = "Zatrzymano przez zamknięcie okna procesu.";
    sTxtStopTermin = "Zatrzymano przez przerwanie procesu.";
    sTxtNoCallback = "Nie można zarejestrować funkcji zwrotnej.";
    sTxtExeFiles   = "Pliki wykonywalne";
    sTxtAllFiles   = "Wszystkie pliki";
    sTxtDelete     = "&Usuń";
    sTxtClear      = "&Wyczyść";
    sTxtShowWnd    = "Pokaż okno uruchomionego polecenia";
    sTxtHistLen    = "Długość historii";
    sTxtEditWnds   = "Okna edycyjne";
    sTxtFont       = "Czcionka";
    sTxtDefFont    = "Domyślna";
    sTxtMonoFonts  = "Czcionki o stałej szerokości";
    sTxtAllFonts   = "Wszystkie czcionki";
    sTxtColors     = "Kolory";
    sTxtDefColors  = "Domyślne";
    sTxtBasic      = "Podstawowy";
    sTxtSelection  = "Zaznaczenie";
    sTxtCurLine    = "Bieżący wiersz";
    sTxtCaret      = "Kursor";
    sTxtOK         = "OK";
    sTxtCancel     = "Anuluj";
    //edit context menu
    sMnuUndo      = '&Cofnij';
    sMnuRedo      = '&Powtórz';
    sMnuCut       = '&Wytnij';
    sMnuCopy      = '&Kopiuj';
    sMnuPaste     = 'Wkl&ej';
    sMnuDelete    = '&Usuń';
    sMnuSelectAll = 'Zaznacz w&szystko';
  }
//  else if ((hMainWnd && (AkelPad.GetLangId(0 /*LANGID_FULL*/) == 1049)) || ((! hMainWnd) && (oSys.Call("Kernel32::GetUserDefaultLangID") == 1049))) //Russian
//  {
//  }
  else
  {
    sTxtDlgTitle   = "Run command";
    sTxtCommand    = "Command:";
    sTxtWorkDir    = "Working directory:";
    sTxtOutput     = "Output:";
    sTxtRun        = "Run";
    sTxtStop       = "Stop";
    sTxtFiles      = "&Files";
    sTxtDirs       = "&Directories";
    sTxtBrowse     = "&Browse";
    sTxtHistory    = "&History";
    sTxtSettings   = "&Settings";
    sTxtCantExec   = "Can not execute command.";
    sTxtNoDir      = "Directory does not exists.";
    sTxtStopClose  = "Stopped by closing the window of process.";
    sTxtStopTermin = "Stopped by process termination.";
    sTxtNoCallback = "Unable to register callback function.";
    sTxtExeFiles   = "Executable files";
    sTxtAllFiles   = "All files";
    sTxtDelete     = "&Delete";
    sTxtClear      = "&Clear";
    sTxtShowWnd    = "Show window of running command";
    sTxtHistLen    = "History length";
    sTxtEditWnds   = "Edit windows";
    sTxtFont       = "Font";
    sTxtDefFont    = "Default";
    sTxtMonoFonts  = "Monospace fonts";
    sTxtAllFonts   = "All fonts";
    sTxtColors     = "Colors";
    sTxtDefColors  = "Default";
    sTxtBasic      = "Basic";
    sTxtSelection  = "Selection";
    sTxtCurLine    = "Current line";
    sTxtCaret      = "Caret";
    sTxtOK         = "OK";
    sTxtCancel     = "Cancel";
    //edit context menu
    sMnuUndo      = '&Undo';
    sMnuRedo      = '&Redo';
    sMnuCut       = 'C&ut';
    sMnuCopy      = '&Copy';
    sMnuPaste     = '&Paste';
    sMnuDelete    = '&Delete';
    sMnuSelectAll = 'Select &all';
  }
}
