// AZJIO 20.11.19
// Description(1033): Search on the Internet, with the ability to specify the domain
// Description(1049): Поиск выделенного в интернете, с возможностью указать домен

// Используя скрипт TabSwitch (Instructor) удалось переделать его в собственное меню.
// Смотреть строки 51 (пункты меню) и 115 (команды). 4 общих и остальные взависимости от расширения файла
//
// Ниже старые параметры ком строки, из которых я часть удалил и выпилил из скрипта за неактуальностью
//  `-WindowLeft=%bl -WindowTop=%bb`
// Description(1049): собственное меню
//
// Arguments:
// -FontName="Arial"    -Font name. Unchanged, if "".
// -FontStyle=3         -Font style (one of the following):
//                         0  ignored (default).
//                         1  normal.
//                         2  bold.
//                         3  italic.
//                         4  bold italic.
// -FontSize=10         -Font size. Unchanged, if 0 (default).
// -LineGap=10          -Space between items (default is 1).
// -SingleClick=false   -Single mouse click chooses item (default is true).
// -WindowLeft=100      -Left window position. Special values:
//                        -1 centered (default).
//                        -2 cursor position.
// -WindowTop=100       -Top window position. Special values:
//                        -1 centered (default).
//                        -2 cursor position.
// -WindowMaxHeight=500 -Maximum window height. Special values:
//                        -1 unlimited (default).
// -WindowMaxWidth=500  -Maximum window width. Special values:
//                        -1 unlimited (default).
//
// Usage:
// Toolbar button example:
//   -"Моё меню" Call("Scripts::Main", 1, "Search_internet.js", `-WindowLeft=%bl -WindowTop=%bb`)
// ContextMenu item example:
//   -"Моё меню" Call("Scripts::Main", 1, "Search_internet.js", `-WindowLeft=-2 -WindowTop=-2`)


var sSelText=AkelPad.GetSelText();
if (sSelText=="") {
	sSelText = getWordCaret()
	if (sSelText=="") {
		sSelText = getWordCaret()
		WScript.Echo("Select the text you want to search for.");
		WScript.Quit();
	}
}

function GetFrameList(lpFrameList) {
	var i = 0;
	// Здесь создаём пункты меню, копируя блок

			lpFrameList[i] = [0, 0];
			lpFrameList[i][0] = "Найти в Google";
			lpFrameList[i][1] = GetIcon(pPath + "\\AkelFiles\\icons\\ico\\google.ico", 0);
			++i;

			lpFrameList[i] = [0, 0];
			lpFrameList[i][0] = "Найти в Яндекс";
			lpFrameList[i][1] = GetIcon(pPath + "\\AkelFiles\\icons\\ico\\yandex.ico", 0);
			++i;

			lpFrameList[i] = [0, 0];
			lpFrameList[i][0] = "Найти на форуме AkelPad";
			lpFrameList[i][1] = GetIcon(pPath + "\\AkelFiles\\icons\\ico\\google.ico", 0);
			++i;

			lpFrameList[i] = [0, 0];
			lpFrameList[i][0] = "Найти в домене...";
			lpFrameList[i][1] = GetIcon(pPath + "\\AkelFiles\\icons\\ico\\google.ico", 0);
			++i;

	switch (sFileExt) {

		case "css":
		case "htm":
		case "html":
			lpFrameList[i] = [0, 0];
			lpFrameList[i][0] = "Найти на сайте htmlbook.ru";
			lpFrameList[i][1] = GetIcon(pPath + "\\AkelFiles\\icons\\ico\\google.ico", 0);
			++i;
			break;

		case "pb":
			lpFrameList[i] = [0, 0];
			lpFrameList[i][0] = "Найти на форуме purebasic.info";
			lpFrameList[i][1] = GetIcon(pPath + "\\AkelFiles\\icons\\ico\\google.ico", 0);
			++i;

			lpFrameList[i] = [0, 0];
			lpFrameList[i][0] = "Найти на форуме purebasic.fr";
			lpFrameList[i][1] = GetIcon(pPath + "\\AkelFiles\\icons\\ico\\google.ico", 0);
			++i;
			break;

		case "au3":
			lpFrameList[i] = [0, 0];
			lpFrameList[i][0] = "Найти на форуме autoitscript.com/forum";
			lpFrameList[i][1] = GetIcon(pPath + "\\AkelFiles\\icons\\ico\\google.ico", 0);
			++i;

			lpFrameList[i] = [0, 0];
			lpFrameList[i][0] = "Find on the forum: autoit-script.ru";
			lpFrameList[i][1] = GetIcon(pPath + "\\AkelFiles\\icons\\ico\\google.ico", 0);
			++i;
			break;

		case "lst":
			lpFrameList[i] = [0, 0];
			lpFrameList[i][0] = "Find on the forum: greenflash.su";
			lpFrameList[i][1] = GetIcon(pPath + "\\AkelFiles\\icons\\ico\\google.ico", 0);
			++i;
			break;

	}

	// Возвращаем индекс выделенного пункта меню
	return 0;
}


// Здесь создаём команды пунктов меню.
function Execute(idx_item) {
	var sLink
	switch (idx_item) { //сравнение ==
		case 0:
			sLink = 'https://www.google.com/search?source=hp&q=' + sSelText + '&oq=' + sSelText
			oSys.Call("Shell32::ShellExecuteW", 0, "open", sLink, 0, 0, 1);
			break;
		case 1:
			sLink = 'https://yandex.ru/search/?&text=' + sSelText
			oSys.Call("Shell32::ShellExecuteW", 0, "open", sLink, 0, 0, 1);
			break;
		case 2:
			sSelText += ' site:akelpad.sourceforge.net/forum/'
			sLink = 'https://www.google.com/search?source=hp&q=' + sSelText + '&oq=' + sSelText
			// sLink = 'https://yandex.ru/search/?&text=' + sSelText
			oSys.Call("Shell32::ShellExecuteW", 0, "open", sLink, 0, 0, 1);
			break;
		case 3:
			var sValue;
			if (sValue=AkelPad.InputBox(hMainWnd, WScript.ScriptName, "Задайте домен","")) { // если жмём "ОК"
				sSelText += ' site:' + sValue
				sLink = 'https://www.google.com/search?source=hp&q=' + sSelText + '&oq=' + sSelText
				// sLink = 'https://yandex.ru/search/?&text=' + sSelText
				oSys.Call("Shell32::ShellExecuteW", 0, "open", sLink, 0, 0, 1);
			}
			break;
	}

	switch (sFileExt) {

		case "css":
		case "htm":
		case "html":
			switch (idx_item) { //сравнение ==
				case 4:
					sSelText += ' site:htmlbook.ru'
					sLink = 'https://www.google.com/search?source=hp&q=' + sSelText + '&oq=' + sSelText
					oSys.Call("Shell32::ShellExecuteW", 0, "open", sLink, 0, 0, 1);
					break;
			}
			break;

		case "pb":
			switch (idx_item) { //сравнение ==
				case 4:
					sSelText += ' site:purebasic.info'
					sLink = 'https://www.google.com/search?source=hp&q=' + sSelText + '&oq=' + sSelText
					oSys.Call("Shell32::ShellExecuteW", 0, "open", sLink, 0, 0, 1);
					break;
				case 5:
					sSelText += ' site:purebasic.fr'
					sLink = 'https://www.google.com/search?source=hp&q=' + sSelText + '&oq=' + sSelText
					oSys.Call("Shell32::ShellExecuteW", 0, "open", sLink, 0, 0, 1);
					break;
			}
			break;

		case "au3":
			switch (idx_item) { //сравнение ==
				case 4:
					sSelText += ' site:autoitscript.com/forum'
					sLink = 'https://www.google.com/search?source=hp&q=' + sSelText + '&oq=' + sSelText
					oSys.Call("Shell32::ShellExecuteW", 0, "open", sLink, 0, 0, 1);
					break;
				case 5:
					sSelText += ' site:autoit-script.ru'
					sLink = 'https://www.google.com/search?source=hp&q=' + sSelText + '&oq=' + sSelText
					oSys.Call("Shell32::ShellExecuteW", 0, "open", sLink, 0, 0, 1);
					break;
			}
			break;

		case "lst":
			switch (idx_item) { //сравнение ==
				case 4:
					sSelText += ' site:greenflash.su/forum'
					sLink = 'https://www.google.com/search?source=hp&q=' + sSelText + '&oq=' + sSelText
					oSys.Call("Shell32::ShellExecuteW", 0, "open", sLink, 0, 0, 1);
					break;
			}
			break;

	}
}

// CaretSelect.js
function getWordCaretInfo(hWndEdit) {
	if (hWndEdit) {
		var nCaretPos = AkelPad.GetSelStart();
		var crInfo = [];
		crInfo.min = AkelPad.SendMessage(hWndEdit, 1100 /*EM_FINDWORDBREAK */, 0/*WB_LEFT*/, nCaretPos);
		crInfo.max = AkelPad.SendMessage(hWndEdit, 1100 /*EM_FINDWORDBREAK */, 7/*WB_RIGHTBREAK*/, crInfo.min);
		//! For case when caret located on word start position i.e. "prev-word |word-to-copy"
		if (crInfo.max < nCaretPos) {
			crInfo.min = AkelPad.SendMessage(hWndEdit, 1100/*EM_FINDWORDBREAK*/, 0/*WB_LEFT*/, nCaretPos + 1);
			crInfo.max = AkelPad.SendMessage(hWndEdit, 1100/*EM_FINDWORDBREAK*/, 7/*WB_RIGHTBREAK*/, crInfo.min);
		}
		if (crInfo.max >= nCaretPos)
			return crInfo;
	}
}

// Возвращает текст слова, на котором установлена каретка
function getWordCaret() {
	var sResult = "";
	var hWndEdit = AkelPad.GetEditWnd();
	var crInfo = getWordCaretInfo(hWndEdit);
	if (crInfo) sResult = AkelPad.GetTextRange(crInfo.min, crInfo.max);
	return sResult;
}

//Arguments
var pFontName = AkelPad.GetArgValue("FontName", "");
var nFontStyle = AkelPad.GetArgValue("FontStyle", 0);
var nFontSize = AkelPad.GetArgValue("FontSize", 0);
var nLineGap = AkelPad.GetArgValue("LineGap", 1);
var bSingleClick = AkelPad.GetArgValue("SingleClick", true);
var nWindowLeft = AkelPad.GetArgValue("WindowLeft", -1);
var nWindowTop = AkelPad.GetArgValue("WindowTop", -1);
var nWindowMaxHeight = AkelPad.GetArgValue("WindowMaxHeight", -1);
var nWindowMaxWidth = AkelPad.GetArgValue("WindowMaxWidth", -1);

//Variables
var sEditFile = AkelPad.GetEditFile(0);
var sFileExt = AkelPad.GetFilePath(sEditFile, 4 /*CPF_FILEEXT*/ );
// var sSelText = AkelPad.GetSelText();
var pPath = AkelPad.GetAkelDir();
sFileExt = sFileExt.toLowerCase()

var hMainWnd = AkelPad.GetMainWnd();

// чтобы не создавать меню на других файлах
// switch (sFileExt) {
// 	case "css":
// 	case "htm":
// 	case "html":
// 	case "pb":
// 	case "au3":
// 		break;
// 	default:
// 		AkelPad.MessageBox(hMainWnd, "Этот тип файлов не поддерживается. \n Поддерживаемые: js, reg, html, au3, pb.", 'Скрипт "Поиск в интернете"', 64 /*MB_ICONINFORMATION*/ );
// 		WScript.Quit();
// 		break;
// };
var hWndEdit = AkelPad.GetEditWnd();
var oSys = AkelPad.SystemFunction();
var hInstanceDLL = AkelPad.GetInstanceDll();
var pClassName = "AkelPad::Scripts::" + WScript.ScriptName + "::" + oSys.Call("kernel32::GetCurrentProcessId");
var hWndContainer = 0;
var hWndListBox = 0;
var hHookPost;
var hHookSend;
var dwMainThreadID = oSys.Call("user32::GetWindowThreadProcessId", hMainWnd, 0);
var hSubClass;
var hDC;
var hBrushHollow;
var hFontEdit;
var lpFrameList = [];
var rcMain = [];
var ptPoint = [];
var nItemHeight;
var nScreenWidth;
var nControlWidth;
var nControlHeight;
var nMaxControlHeight;
var nCharWidth;
var nCharHeight;
var nMaxCharWidth = 0;
var nMaxCharHeight = 0;
var nIconSize = 16;
var nIconGap = 2;
var bNoSwitch = false;
var i;

// Получить список документов
nCurSel = GetFrameList(lpFrameList);

// Получить шрифт
if (pFontName || nFontStyle || nFontSize)
	hFontEdit = CreateFont(pFontName, nFontStyle, nFontSize);
else
	hFontEdit = AkelPad.SendMessage(hWndEdit, 0x31 /*WM_GETFONT*/ , 0, 0);
if (!hFontEdit) WScript.Quit();

// Получить максимальный размер символа
if (lpSize = AkelPad.MemAlloc(8 /*sizeof(SIZE)*/ )) {
	if (hDC = oSys.Call("user32::GetDC", hWndEdit)) {
		oSys.Call("gdi32::SelectObject", hDC, hFontEdit);

		for (i = 0; i < lpFrameList.length; ++i) {
			if (oSys.Call("gdi32::GetTextExtentPoint32" + _TCHAR, hDC, lpFrameList[i][0], lpFrameList[i][0].length, lpSize)) {
				nCharWidth = AkelPad.MemRead(_PtrAdd(lpSize, 0) /*offsetof(SIZE, cx)*/ , 3 /*DT_DWORD*/ );
				nCharHeight = AkelPad.MemRead(_PtrAdd(lpSize, 4) /*offsetof(SIZE, cy)*/ , 3 /*DT_DWORD*/ );
				if (nCharWidth > nMaxCharWidth) nMaxCharWidth = nCharWidth;
				if (nCharHeight > nMaxCharHeight) nMaxCharHeight = nCharHeight;
			}
		}
		oSys.Call("user32::ReleaseDC", hWndEdit, hDC);
	}
	nMaxCharWidth += nIconSize + nIconGap + 16;

	AkelPad.MemFree(lpSize);
}

// Создаёт диалог
if (AkelPad.WindowRegisterClass(pClassName, 0x21 /*WM_MOUSEACTIVATE*/ ,
		0x2B /*WM_DRAWITEM*/ )) {
	if (hWndContainer = oSys.Call("user32::CreateWindowEx" + _TCHAR, 0, pClassName, 0, 0x80000000 /*WS_POPUP*/ , 0, 0, 0, 0, hMainWnd, 0, hInstanceDLL, DialogCallback)) {
		if (hWndListBox = oSys.Call("user32::CreateWindowEx" + _TCHAR, 0, "LISTBOX", 0, 0x50700010 /*WS_VISIBLE|WS_CHILD|WS_HSCROLL|WS_VSCROLL|WS_DLGFRAME|LBS_OWNERDRAWFIXED*/ , 0, 0, 0, 0, hWndContainer, 0, hInstanceDLL, 0)) {
			//Make hWndContainer invisible
			hBrushHollow = oSys.Call("gdi32::GetStockObject", 5 /*HOLLOW_BRUSH*/ );
			oSys.Call("user32::SetClassLong" + _TCHAR, hWndContainer, -10 /*GCL_HBRBACKGROUND*/ , hBrushHollow);

			AkelPad.SendMessage(hWndListBox, 48 /*WM_SETFONT*/ , hFontEdit, 1);
			nItemHeight = nMaxCharHeight + nLineGap;
			i = AkelPad.SendMessage(hWndListBox, 0x1A1 /*LB_GETITEMHEIGHT*/ , 0, 0);
			if (nItemHeight < i)
				nItemHeight = i;
			else
				AkelPad.SendMessage(hWndListBox, 0x1A0 /*LB_SETITEMHEIGHT*/ , 0, nItemHeight);
			nMaxControlHeight = lpFrameList.length * nItemHeight + oSys.Call("user32::GetSystemMetrics", 8 /*SM_CYDLGFRAME*/ ) * 2;
			if (nWindowMaxHeight > 0)
				nControlHeight = Math.min(nWindowMaxHeight, nMaxControlHeight);
			else
				nControlHeight = nMaxControlHeight;
			nControlHeight = Math.min(oSys.Call("user32::GetSystemMetrics", 62 /*SM_CYMAXIMIZED*/ ) - 8, nControlHeight);
			if (nWindowMaxWidth > 0)
				nControlWidth = Math.min(nWindowMaxWidth, nMaxCharWidth);
			else
				nControlWidth = nMaxCharWidth;
			nControlWidth = Math.min(oSys.Call("user32::GetSystemMetrics", 61 /*SM_CXMAXIMIZED*/ ) - 8, nControlWidth);

			if (nMaxCharWidth > nControlWidth) {
				AkelPad.SendMessage(hWndListBox, 0x194 /*LB_SETHORIZONTALEXTENT*/ , nMaxCharWidth, 0);
				if (nMaxControlHeight == nControlHeight)
					nControlHeight += oSys.Call("user32::GetSystemMetrics", 21 /*SM_CXHSCROLL*/ );
			}

			//Fill listbox
			for (i = 0; i < lpFrameList.length; ++i)
				oSys.Call("user32::SendMessage" + _TCHAR, hWndListBox, 0x180 /*LB_ADDSTRING*/ , 0, lpFrameList[i][0]);

			GetWindowSize(hMainWnd, 0, rcMain);
			if (nWindowLeft >= 0)
				rcMain.left = nWindowLeft;
			else if (nWindowLeft == -2) {
				GetCursorPos(ptPoint);
				rcMain.left = ptPoint.x;
			} else
				rcMain.left += rcMain.right / 2 - nControlWidth / 2;
			if (!(nScreenWidth = oSys.Call("user32::GetSystemMetrics", 78 /*SM_CXVIRTUALSCREEN*/ )))
				nScreenWidth = oSys.Call("user32::GetSystemMetrics", 61 /*SM_CXMAXIMIZED*/ );
			rcMain.left = Math.min(rcMain.left, Math.max((nScreenWidth - 8) - nControlWidth, 0));
			if (rcMain.left < 0) rcMain.left = 0;

			if (nWindowTop >= 0)
				rcMain.top = nWindowTop;
			else if (nWindowTop == -2) {
				GetCursorPos(ptPoint);
				rcMain.top = ptPoint.y;
			} else
				rcMain.top += rcMain.bottom / 2 - nControlHeight / 2;
			rcMain.top = Math.min(rcMain.top, Math.max((oSys.Call("user32::GetSystemMetrics", 62 /*SM_CYMAXIMIZED*/ ) - 8) - nControlHeight, 0));
			if (rcMain.top < 0) rcMain.top = 0;

			oSys.Call("user32::SetWindowPos", hWndContainer, 0, rcMain.left, rcMain.top, nControlWidth, nControlHeight, 0x14 /*SWP_NOZORDER|SWP_NOACTIVATE*/ );
			oSys.Call("user32::SetWindowPos", hWndListBox, 0, 0, 0, nControlWidth, nControlHeight, 0x16 /*SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE*/ );
			AkelPad.SendMessage(hWndListBox, 0x186 /*LB_SETCURSEL*/ , nCurSel, 0);
			oSys.Call("user32::ShowWindow", hWndContainer, 4 /*SW_SHOWNOACTIVATE*/ );
			//oSys.Call("user32::SetFocus", hWndListBox);
			//oSys.Call("user32::ShowWindow", hWndContainer, 5 /*SW_SHOW*/);
			//oSys.Call("user32::UpdateWindow", hMainWnd);

			//Cause listbox is non-active, hook and send to listbox keyboard and mouse actions.
			// потому что ListBox является неактивным, хук и отправка действия клавиатуры и мыши в ListBox.
			if (hHookPost = AkelPad.ThreadHook(3 /*WH_GETMESSAGE*/ , HookPostCallback, dwMainThreadID, 0x201 /*WM_LBUTTONDOWN*/ ,
					0x0A1 /*WM_NCLBUTTONDOWN*/ ,
					0x204 /*WM_RBUTTONDOWN*/ ,
					0x0A4 /*WM_NCRBUTTONDOWN*/ ,
					0x207 /*WM_MBUTTONDOWN*/ ,
					0x0A7 /*WM_NCMBUTTONDOWN*/ ,
					0x100 /*WM_KEYDOWN*/ ,
					0x101 /*WM_KEYUP*/ ,
					0x104 /*WM_SYSKEYDOWN*/ ,
					0x105 /*WM_SYSKEYUP*/ ,
					0x20A /*WM_MOUSEWHEEL*/ )) {
				if (hHookSend = AkelPad.ThreadHook(4 /*WH_CALLWNDPROC*/ , HookSendCallback, dwMainThreadID, 0x6 /*WM_SETFOCUS*/ )) {
					if (hSubClass = AkelPad.WindowSubClass(hWndListBox, ListBoxCallback, 0x021 /*WM_MOUSEACTIVATE*/ ,
							0x087 /*WM_GETDLGCODE*/ ,
							0x100 /*WM_KEYDOWN*/ ,
							0x101 /*WM_KEYUP*/ ,
							0x201 /*WM_LBUTTONDOWN*/ ,
							0x202 /*WM_LBUTTONUP*/ ,
							0x203 /*WM_LBUTTONDBLCLK*/ )) {
						// Разрешить запуск других сценариев
						AkelPad.ScriptNoMutex();

						// Цикл сообщений
						AkelPad.WindowGetMessage();

						AkelPad.WindowUnsubClass(hWndListBox);
					}
					AkelPad.ThreadUnhook(hHookSend);
				}
				AkelPad.ThreadUnhook(hHookPost);
			}

			if (!bNoSwitch) {
				Execute(AkelPad.SendMessage(hWndListBox, 0x188 /*LB_GETCURSEL*/ , 0, 0))
				// oSys.Call("user32::PostMessage" + _TCHAR, hMainWnd, 1285 /*AKD_FRAMEACTIVATE*/ , 0, lpFrameList[i][1]);
			}
			//oSys.Call("user32::DestroyWindow", hWndListBox);
		}
		oSys.Call("user32::DestroyWindow", hWndContainer);
		Del(lpFrameList); // удаляем иконки
	}
	AkelPad.WindowUnregisterClass(pClassName);
}

// высвободить ресурсы шрифта
if (pFontName || nFontStyle || nFontSize) {
	if (hFontEdit)
		oSys.Call("gdi32::DeleteObject", hFontEdit);
}

function DialogCallback(hWnd, uMsg, wParam, lParam) {
	if (uMsg == 0x021 /*WM_MOUSEACTIVATE*/ ) {
		return 3 /*MA_NOACTIVATE*/ ;
	} else if (uMsg == 0x2B /*WM_DRAWITEM*/ ) {
		var hDC;
		var hIcon;
		var nItemID;
		var nItemState;
		var lpItem;
		var rcItem = [];
		var crText;
		var crBk;
		var hBrushBk;
		var nModeBkOld;

		hDC = AkelPad.MemRead(_PtrAdd(lParam, _X64 ? 32 : 24) /*offsetof(DRAWITEMSTRUCT, hDC)*/ , 2 /*DT_QWORD*/ );
		nItemID = AkelPad.MemRead(_PtrAdd(lParam, _X64 ? 8 : 8) /*offsetof(DRAWITEMSTRUCT, itemID)*/ , 3 /*DT_DWORD*/ );
		nItemState = AkelPad.MemRead(_PtrAdd(lParam, _X64 ? 16 : 16) /*offsetof(DRAWITEMSTRUCT, itemState)*/ , 3 /*DT_DWORD*/ );
		lpItem = _PtrAdd(lParam, _X64 ? 40 : 28) /*offsetof(DRAWITEMSTRUCT, rcItem)*/ ;
		RectToArray(lpItem, rcItem);

		// Установить фон
		if (nItemState & 0x1 /*ODS_SELECTED*/ ) {
			crText = oSys.Call("user32::GetSysColor", 14 /*COLOR_HIGHLIGHTTEXT*/ );
			crBk = oSys.Call("user32::GetSysColor", 13 /*COLOR_HIGHLIGHT*/ );
			hBrushBk = oSys.Call("user32::GetSysColorBrush", 13 /*COLOR_HIGHLIGHT*/ );
		} else {
			crText = oSys.Call("user32::GetSysColor", 8 /*COLOR_WINDOWTEXT*/ );
			crBk = oSys.Call("user32::GetSysColor", 5 /*COLOR_WINDOW*/ );
			hBrushBk = oSys.Call("user32::GetSysColorBrush", 5 /*COLOR_WINDOW*/ );
		}
		oSys.Call("user32::FillRect", hDC, lpItem, hBrushBk);
		nModeBkOld = oSys.Call("gdi32::SetBkMode", hDC, 1 /*TRANSPARENT*/ );

		// Нарисовать иконку
		if (lpFrameList[nItemID][1]) // если есть иконка, то рисуем её
			oSys.Call("user32::DrawIconEx", hDC, rcItem.left, rcItem.top + (rcItem.bottom - rcItem.top) / 2 - nIconSize / 2, lpFrameList[nItemID][1], nIconSize, nIconSize, 0, 0, 0x3 /*DI_NORMAL*/ );

		// Нарисовать текст
		oSys.Call("gdi32::SetTextColor", hDC, crText);
		oSys.Call("gdi32::SetBkColor", hDC, crBk);
		oSys.Call("gdi32::TextOut" + _TCHAR, hDC, rcItem.left + nIconSize + nIconGap, rcItem.top + (rcItem.bottom - rcItem.top) / 2 - nMaxCharHeight / 2, lpFrameList[nItemID][0], lpFrameList[nItemID][0].length);

		oSys.Call("gdi32::SetBkMode", hDC, nModeBkOld);
	}
	return 0;
}

function HookPostCallback(nCode, wParam, lParam) {
	var uMsg = AkelPad.MemRead(_PtrAdd(lParam, _X64 ? 8 : 4) /*offsetof(MSG, message)*/ , 3 /*DT_DWORD*/ );
	var nParamW;
	var nParamL;

	if (uMsg == 0x201 /*WM_LBUTTONDOWN*/ ||
		uMsg == 0x0A1 /*WM_NCLBUTTONDOWN*/ ||
		uMsg == 0x204 /*WM_RBUTTONDOWN*/ ||
		uMsg == 0x0A4 /*WM_NCRBUTTONDOWN*/ ||
		uMsg == 0x207 /*WM_MBUTTONDOWN*/ ||
		uMsg == 0x0A7 /*WM_NCMBUTTONDOWN*/ ) {
		var hWnd = AkelPad.MemRead(_PtrAdd(lParam, 0) /*offsetof(MSG, hwnd)*/ , 2 /*DT_QWORD*/ );

		if (hWnd != hWndListBox) {
			// Не в прямоугольнике
			bNoSwitch = true;

			// Выход из цикла сообщений
			oSys.Call("user32::PostQuitMessage", 0);
		}
	} else if (uMsg == 0x100 /*WM_KEYDOWN*/ ||
		uMsg == 0x101 /*WM_KEYUP*/ ||
		uMsg == 0x104 /*WM_SYSKEYDOWN*/ ||
		uMsg == 0x105 /*WM_SYSKEYUP*/ ||
		uMsg == 0x20A /*WM_MOUSEWHEEL*/ ) {
		nParamW = AkelPad.MemRead(_PtrAdd(lParam, _X64 ? 16 : 8) /*offsetof(MSG, nParamW)*/ , 2 /*DT_QWORD*/ );
		nParamL = AkelPad.MemRead(_PtrAdd(lParam, _X64 ? 24 : 12) /*offsetof(MSG, lParam)*/ , 2 /*DT_QWORD*/ );
		AkelPad.SendMessage(hWndListBox, uMsg, nParamW, nParamL);
		AkelPad.MemCopy(_PtrAdd(lParam, _X64 ? 8 : 4) /*offsetof(MSG, message)*/ , 0 /*WM_NULL*/ , 3 /*DT_DWORD*/ );
	}
}

function HookSendCallback(nCode, wParam, lParam) {
	var uMsg = AkelPad.MemRead(_PtrAdd(lParam, _X64 ? 16 : 8) /*offsetof(CWPSTRUCT, message)*/ , 3 /*DT_DWORD*/ );
	var nParamW;
	var nParamL;

	if (uMsg == 0x6 /*WM_SETFOCUS*/ ) {
		bNoSwitch = true;

		// Выход из цикла сообщений
		oSys.Call("user32::PostQuitMessage", 0);
	}
}

function ListBoxCallback(hWnd, uMsg, wParam, lParam) {
	if (uMsg == 0x021 /*WM_MOUSEACTIVATE*/ ) {
		return 3 /*MA_NOACTIVATE*/ ;
	} else if (uMsg == 0x087 /*WM_GETDLGCODE*/ ) {
		AkelPad.WindowNoNextProc(hSubClass);
		return 0x4 /*DLGC_WANTALLKEYS*/ ;
	} else if (uMsg == 0x100 /*WM_KEYDOWN*/ ) {
		if (wParam == 0x43 /*c*/ ) { // если Ctrl+C на списке то копируем пункт
			if (oSys.Call("user32::GetKeyState", 0x11 /*VK_CONTROL*/ ) & 0x8000) { // если нажат Ctrl при нажатии С
				i = AkelPad.SendMessage(hWndListBox, 0x188 /*LB_GETCURSEL*/ , 0, 0);
				AkelPad.SetClipboardText(lpFrameList[i][0]);
			}
		} else if (wParam == 0x9 /*VK_TAB*/ ) { // если нажат TAB то двигаем курсор по списку, если ещё и SHIFT, то в обратном порядке
			var nCount;

			nCount = AkelPad.SendMessage(hWndListBox, 0x18B /*LB_GETCOUNT*/ , 0, 0);
			i = AkelPad.SendMessage(hWndListBox, 0x188 /*LB_GETCURSEL*/ , 0, 0);

			if (!(oSys.Call("user32::GetKeyState", 0x10 /*VK_SHIFT*/ ) & 0x8000)) {
				if (++i >= nCount)
					i = 0;
			} else {
				if (--i < 0)
					i = nCount - 1;
			}
			AkelPad.SendMessage(hWndListBox, 0x186 /*LB_SETCURSEL*/ , i, 0);
		} else if (wParam == 0xD /*VK_RETURN*/ ) { // клавиша ENTER
			// Выход из цикла сообщений
			oSys.Call("user32::PostQuitMessage", 0);
		} else if (wParam == 0x1B /*VK_ESCAPE*/ ) {
			bNoSwitch = true;

			// Выход из цикла сообщений
			oSys.Call("user32::PostQuitMessage", 0);
		}
	} else if (uMsg == 0x101 /*WM_KEYUP*/ ) {} else if (uMsg == 0x201 /*WM_LBUTTONDOWN*/ ) {
		var lResult = AkelPad.SendMessage(hWndListBox, 0x01A9 /*LB_ITEMFROMPOINT*/ , 0, lParam);

		if (HIWORD(lResult) == 0)
			AkelPad.SendMessage(hWndListBox, 0x186 /*LB_SETCURSEL*/ , LOWORD(lResult), 0);
		AkelPad.WindowNoNextProc(hSubClass);
	} else if (uMsg == 0x202 /*WM_LBUTTONUP*/ ||
		uMsg == 0x203 /*WM_LBUTTONDBLCLK*/ ) {
		if (uMsg == 0x203 /*WM_LBUTTONDBLCLK*/ || bSingleClick) {
			// Выход из цикла сообщений
			oSys.Call("user32::PostQuitMessage", 0);
		}
	}
}

function CreateFont(pFaceName, nFontStyle, nPointSize) {
	// Высвобождение командой: oSys.Call("gdi32::DeleteObject", hFont);
	var lpLogFontSrc;
	var lpLogFontDst;
	var hDC;
	var hFont = 0;
	var nHeight;
	var nWeight;
	var nItalic;

	if (lpLogFontDst = AkelPad.MemAlloc(92 /*sizeof(LOGFONTW)*/ )) {
		lpLogFontSrc = AkelPad.SendMessage(hMainWnd, 1223 /*AKD_GETFRAMEINFO*/ , 48 /*FI_EDITFONTW*/ , 0);
		oSys.Call("kernel32::RtlMoveMemory", lpLogFontDst, lpLogFontSrc, 92 /*sizeof(LOGFONTW)*/ );

		if (nPointSize) {
			if (hDC = oSys.Call("user32::GetDC", hMainWnd)) {
				nHeight = -oSys.Call("kernel32::MulDiv", nPointSize, oSys.Call("gdi32::GetDeviceCaps", hDC, 90 /*LOGPIXELSY*/ ), 72);
				AkelPad.MemCopy(_PtrAdd(lpLogFontDst, 0) /*offsetof(LOGFONTW, lfHeight)*/ , nHeight, 3 /*DT_DWORD*/ );
				oSys.Call("user32::ReleaseDC", hMainWnd, hDC);
			}
		}
		if (nFontStyle != 0 /*FS_NONE*/ ) {
			nWeight = (nFontStyle == 2 /*FS_FONTBOLD*/ || nFontStyle == 4 /*FS_FONTBOLDITALIC*/ ) ? 700 /*FW_BOLD*/ : 400 /*FW_NORMAL*/ ;
			AkelPad.MemCopy(_PtrAdd(lpLogFontDst, 16) /*offsetof(LOGFONTW, lfWeight)*/ , nWeight, 3 /*DT_DWORD*/ );
			nItalic = (nFontStyle == 3 /*FS_FONTITALIC*/ || nFontStyle == 4 /*FS_FONTBOLDITALIC*/ ) ? 1 : 0;
			AkelPad.MemCopy(_PtrAdd(lpLogFontDst, 20) /*offsetof(LOGFONTW, lfItalic)*/ , nItalic, 5 /*DT_BYTE*/ );
		}
		if (_TSTR == 0 /*DT_ANSI*/ && !pFaceName)
			pFaceName = AkelPad.MemRead(_PtrAdd(lpLogFontDst, 28) /*offsetof(LOGFONTW, lfFaceName)*/ , 1 /*DT_UNICODE*/ );
		if (pFaceName)
			AkelPad.MemCopy(_PtrAdd(lpLogFontDst, 28) /*offsetof(LOGFONTW, lfFaceName)*/ , pFaceName.substr(0, 32 /*LF_FACESIZE*/ ), _TSTR);

		hFont = oSys.Call("gdi32::CreateFontIndirect" + _TCHAR, lpLogFontDst);
		AkelPad.MemFree(lpLogFontDst);
	}
	return hFont;
}

function GetCursorPos(ptPoint) {
	var lpPoint;

	ptPoint.x = 0;
	ptPoint.y = 0;

	if (lpPoint = AkelPad.MemAlloc(8 /*sizeof(POINT)*/ )) {
		if (oSys.Call("user32::GetCursorPos", lpPoint)) {
			ptPoint.x = AkelPad.MemRead(_PtrAdd(lpPoint, 0) /*offsetof(POINT, x)*/ , 3 /*DT_DWORD*/ );
			ptPoint.y = AkelPad.MemRead(_PtrAdd(lpPoint, 4) /*offsetof(POINT, y)*/ , 3 /*DT_DWORD*/ );
		}
		AkelPad.MemFree(lpPoint);
	}
}

function RectToArray(lpRect, rcRect) {
	rcRect.left = AkelPad.MemRead(_PtrAdd(lpRect, 0) /*offsetof(RECT, left)*/ , 3 /*DT_DWORD*/ );
	rcRect.top = AkelPad.MemRead(_PtrAdd(lpRect, 4) /*offsetof(RECT, top)*/ , 3 /*DT_DWORD*/ );
	rcRect.right = AkelPad.MemRead(_PtrAdd(lpRect, 8) /*offsetof(RECT, right)*/ , 3 /*DT_DWORD*/ );
	rcRect.bottom = AkelPad.MemRead(_PtrAdd(lpRect, 12) /*offsetof(RECT, bottom)*/ , 3 /*DT_DWORD*/ );
	return rcRect;
}

function GetWindowSize(hWnd, hWndOwner, rcRect) {
	var lpRect;
	var bResult = false;

	if (lpRect = AkelPad.MemAlloc(16 /*sizeof(RECT)*/ )) {
		if (oSys.Call("user32::GetWindowRect", hWnd, lpRect)) {
			RectToArray(lpRect, rcRect);
			rcRect.right -= rcRect.left;
			rcRect.bottom -= rcRect.top;

			if (hWndOwner)
				bResult = oSys.Call("user32::ScreenToClient", hWndOwner, lpRect);
			else
				bResult = true;
			rcRect.left = AkelPad.MemRead(_PtrAdd(lpRect, 0) /*offsetof(RECT, left)*/ , 3 /*DT_DWORD*/ );
			rcRect.top = AkelPad.MemRead(_PtrAdd(lpRect, 4) /*offsetof(RECT, top)*/ , 3 /*DT_DWORD*/ );
		}
		AkelPad.MemFree(lpRect);
	}
	return bResult;
}

function LOWORD(dwNumber) {
	return (dwNumber & 0xffff);
}

function HIWORD(dwNumber) {
	return (dwNumber >> 16);
}

function MAKELONG(a, b) {
	return (a & 0xffff) | ((b & 0xffff) << 16);
}

function GetIcon(sFile, IndexIcon) {
	if (sFile == '')
		return 0
	var fso = new ActiveXObject("Scripting.FileSystemObject");
	if (!fso.FileExists(sFile))
		return 0
	var phIcon = AkelPad.MemAlloc(_X64 ? 8 : 4 /*sizeof(HWND)*/ ) // указатель на декскриптор иконки
	var lpFile = AkelPad.MemAlloc(260 * 2); // Выделяем память и получаем указатель
	AkelPad.MemCopy(lpFile, sFile, 0 /*DT_ANSI*/ ); // Копируем путь в указатель
	oSys.Call("Shell32::ExtractIconEx", lpFile, IndexIcon /* IndexIcon */ , 0, phIcon, 1); // Получает иконку из файла 16x16
	hIcon = AkelPad.MemRead(phIcon, 2 /*DT_QWORD*/ );
	AkelPad.MemFree(lpFile);
	AkelPad.MemFree(phIcon);
	return hIcon
}

function Del(lpFrameList) {
	var i;
	for (i = 0; i < lpFrameList.length; ++i) {
		if (lpFrameList[i][1])
			oSys.Call("User32::DestroyIcon", lpFrameList[i][1]);
	}
}
