Beispiel #1
0
bool isConsoleWindow(HWND hWnd)
{
	wchar_t szClass[64] = L"";

	if (!hWnd)
		return false;
	if (!GetClassName(hWnd, szClass, countof(szClass)))
		return false;
	if (!isConsoleClass(szClass))
		return false;

	// But when process is hooked, GetConsoleClass will return "proper" name
	// even if hWnd points to our VirtualConsole

	// RealConsole handle is stored in the Window DATA
	wchar_t szClassPtr[64] = L"";
	HWND h = (HWND)GetWindowLongPtr(hWnd, 0);
	if (h && (h != hWnd) && IsWindow(h))
	{
		if (GetClassName(h, szClassPtr, countof(szClassPtr)))
		{
			if (isConsoleClass(szClassPtr))
			{
				_ASSERTE(FALSE && "RealConsole handle was not retrieved properly!");
				return false;
			}
		}
	}

	// Well, it's a RealConsole
	return true;
}
Beispiel #2
0
void OnConWndChanged(HWND ahNewConWnd)
{
	//BOOL lbForceReopen = FALSE;

	if (ahNewConWnd)
	{
		#ifdef _DEBUG
		if (user)
		{
			wchar_t sClass[64]; user->getClassNameW(ahNewConWnd, sClass, countof(sClass));
			_ASSERTEX(isConsoleClass(sClass));
		}
		#endif

		if (ghConWnd != ahNewConWnd)
		{
			ghConWnd = ahNewConWnd;
			//lbForceReopen = TRUE;
		}
	}
	else
	{
		//lbForceReopen = TRUE;
	}

	GetConMap(TRUE);
}
Beispiel #3
0
// GetConsoleWindow хукается, поэтому, для получения реального консольного окна
// можно дергать эту экспортируемую функцию
HWND WINAPI GetRealConsoleWindow()
{
	_ASSERTE(gfGetRealConsoleWindow);
	HWND hConWnd = gfGetRealConsoleWindow ? gfGetRealConsoleWindow() : NULL; //GetConsoleWindow();
#ifdef _DEBUG
	wchar_t sClass[64]; user->getClassNameW(hConWnd, sClass, countof(sClass));
	_ASSERTEX(hConWnd==NULL || isConsoleClass(sClass));
#endif
	return hConWnd;
}
Beispiel #4
0
bool CAttachDlg::CanAttachWindow(HWND hFind, DWORD nSkipPID, CProcessData* apProcessData, CAttachDlg::AttachWndInfo& Info)
{
	static bool bIsWin64 = IsWindows64();

	ZeroStruct(Info);

	DWORD_PTR nStyle = GetWindowLongPtr(hFind, GWL_STYLE);
	DWORD_PTR nStyleEx = GetWindowLongPtr(hFind, GWL_EXSTYLE);
	if (!GetWindowThreadProcessId(hFind, &Info.nPID))
		Info.nPID = 0;

	if (!Info.nPID)
		return false;

	bool lbCan = ((nStyle & (WS_VISIBLE/*|WS_CAPTION|WS_MAXIMIZEBOX*/)) == (WS_VISIBLE/*|WS_CAPTION|WS_MAXIMIZEBOX*/));
	if (lbCan)
	{
		// Более тщательно стили проверить
		lbCan = ((nStyle & WS_MAXIMIZEBOX) == WS_MAXIMIZEBOX) || ((nStyle & WS_THICKFRAME) == WS_THICKFRAME);
	}
	if (lbCan && Info.nPID == GetCurrentProcessId())
		lbCan = false;
	if (lbCan && Info.nPID == nSkipPID)
		lbCan = false;
	if (lbCan && (nStyle & WS_CHILD))
		lbCan = false;
	if (lbCan && (nStyleEx & WS_EX_TOOLWINDOW))
		lbCan = false;
	if (lbCan && gpConEmu->isOurConsoleWindow(hFind))
		lbCan = false;
	if (lbCan && gpConEmu->mp_Inside && (hFind == gpConEmu->mp_Inside->mh_InsideParentRoot))
		lbCan = false;

	GetClassName(hFind, Info.szClass, countof(Info.szClass));
	GetWindowText(hFind, Info.szTitle, countof(Info.szTitle));

	if (gpSetCls->isAdvLogging)
	{
		wchar_t szLogInfo[MAX_PATH*3];
		_wsprintf(szLogInfo, SKIPLEN(countof(szLogInfo)) L"Attach:%s x%08X/x%08X/x%08X {%s} \"%s\"", Info.szExeName, LODWORD(hFind), nStyle, nStyleEx, Info.szClass, Info.szTitle);
		CVConGroup::LogString(szLogInfo);
	}

	if (!lbCan)
		return false;

	_wsprintf(Info.szPid, SKIPLEN(countof(Info.szPid)) L"%u", Info.nPID);
	const wchar_t sz32bit[] = L" [32]";
	const wchar_t sz64bit[] = L" [64]";

	HANDLE h;
	DEBUGTEST(DWORD nErr);
	bool lbExeFound = false;

	if (apProcessData)
	{
		lbExeFound = apProcessData->GetProcessName(Info.nPID, Info.szExeName, countof(Info.szExeName), Info.szExePathName, countof(Info.szExePathName), &Info.nImageBits);
		if (lbExeFound)
		{
			//ListView_SetItemText(hList, nItem, alc_File, szExeName);
			//ListView_SetItemText(hList, nItem, alc_Path, szExePathName);
			if (bIsWin64 && Info.nImageBits)
			{
				wcscat_c(Info.szPid, (Info.nImageBits == 64) ? sz64bit : sz32bit);
			}
		}
	}

	if (!lbExeFound)
	{
		Info.nImageBits = GetProcessBits(Info.nPID);
		if (bIsWin64 && Info.nImageBits)
		{
			wcscat_c(Info.szPid, (Info.nImageBits == 64) ? sz64bit : sz32bit);
		}

		h = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, Info.nPID);
		if (h && h != INVALID_HANDLE_VALUE)
		{
			MODULEENTRY32 mi = {sizeof(mi)};
			if (Module32First(h, &mi))
			{
				lstrcpyn(Info.szExeName, *mi.szModule ? mi.szModule : (wchar_t*)PointToName(mi.szExePath), countof(Info.szExeName));
				lstrcpyn(Info.szExePathName, mi.szExePath, countof(Info.szExePathName));
				lbExeFound = true;
			}
			else
			{
				if (bIsWin64)
				{
					wcscat_c(Info.szPid, sz64bit);
				}
			}
			CloseHandle(h);
		}
		else
		{
			#ifdef _DEBUG
			nErr = GetLastError();
			_ASSERTE(nErr == 5 || (nErr == 299 && Info.nImageBits == 64));
			#endif
			wcscpy_c(Info.szExeName, L"???");
		}

		#if 0 //#ifdef _WIN64 -- no need to call TH32CS_SNAPMODULE32, simple TH32CS_SNAPMODULE will handle both if it can
		if (!lbExeFound)
		{
			h = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE|TH32CS_SNAPMODULE32, Info.nPID);
			if (h && h != INVALID_HANDLE_VALUE)
			{
				MODULEENTRY32 mi = {sizeof(mi)};
				if (Module32First(h, &mi))
				{
					//ListView_SetItemText(hList, nItem, alc_File, *mi.szModule ? mi.szModule : (wchar_t*)PointToName(mi.szExePath));
					lstrcpyn(Info.szExeName, *mi.szModule ? mi.szModule : (wchar_t*)PointToName(mi.szExePath), countof(Info.szExeName));
					//ListView_SetItemText(hList, nItem, alc_Path, mi.szExePath);
					lstrcpyn(Info.szExePathName, mi.szExePath, countof(Info.szExePathName));
				}
				CloseHandle(h);
			}
		}
		#endif
	}

	if (!lbExeFound)
	{
		// Так можно получить только имя файла процесса
		PROCESSENTRY32 pi = {sizeof(pi)};
		h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
		if (h && h != INVALID_HANDLE_VALUE)
		{
			if (Process32First(h, &pi))
			{
				do
				{
					if (pi.th32ProcessID == Info.nPID)
					{
						lstrcpyn(Info.szExeName, pi.szExeFile, countof(Info.szExeName));
						break;
					}
				} while (Process32Next(h, &pi));
			}
		}
	}

	wcscpy_c(Info.szType, isConsoleClass(Info.szClass) ? szTypeCon : szTypeGui);
	return true;
}
Beispiel #5
0
// Проверка окна переднего плана. Если оно принадлежит к хукаемым процесса - вставить хук.
bool CDefaultTerminal::CheckForeground(HWND hFore, DWORD nForePID, bool bRunInThread /*= true*/)
{
	if (!isDefaultTerminalAllowed())
		return false;

	bool lbRc = false;
	bool lbLocked = false;
	bool lbConHostLocked;
	DWORD nResult = 0;
	wchar_t szClass[MAX_PATH]; szClass[0] = 0;
	PROCESSENTRY32 prc;
	bool bMonitored = false;
	const wchar_t* pszMonitored = NULL;
	HANDLE hProcess = NULL;
	//int nBits = 0;
	//wchar_t szCmdLine[MAX_PATH*3];
	//wchar_t szName[64];
	//PROCESS_INFORMATION pi = {};
	//STARTUPINFO si = {sizeof(si)};
	//BOOL bStarted = FALSE;
	DWORD nErrCode = 0;
	int iHookerRc = -1;

	// Если главное окно еще не создано
	if (!mb_ReadyToHook)
	{
		// Сразу выходим
		goto wrap;
	}

	//_ASSERTE(gpConEmu->isMainThread());
	if (!hFore || !nForePID)
	{
		_ASSERTE(hFore && nForePID);
		goto wrap;
	}

	if (hFore == mh_LastWnd || hFore == mh_LastIgnoredWnd)
	{
		// Это окно уже проверялось
		lbRc = (hFore == mh_LastWnd);
		goto wrap;
	}

	if (bRunInThread && (hFore == mh_LastCall))
	{
		// Просто выйти. Это проверка на частые фоновые вызовы.
		goto wrap;
	}
	mh_LastCall = hFore;

	if (bRunInThread)
	{
		if (gpConEmu->isMainThread())
		{
			// Clear finished threads
			ClearThreads(false);
		}

		HANDLE hPostThread = NULL; DWORD nThreadId = 0;
		ThreadArg* pArg = (ThreadArg*)malloc(sizeof(ThreadArg));
		if (!pArg)
		{
			_ASSERTE(pArg);
			goto wrap;
		}
		pArg->pTerm = this;
		pArg->hFore = hFore;
		pArg->nForePID = nForePID;

		hPostThread = CreateThread(NULL, 0, PostCheckThread, pArg, 0, &nThreadId);
		_ASSERTE(hPostThread!=NULL);
		if (hPostThread)
		{
			m_Threads.push_back(hPostThread);
		}

		lbRc = (hPostThread != NULL); // вернуть OK?
		goto wrap;
	}

	EnterCriticalSection(&mcs);
	lbLocked = true;

	// Clear dead processes and windows
	ClearProcessed(false);

	// Check window class
	if (GetClassName(hFore, szClass, countof(szClass)))
	{
		if ((lstrcmp(szClass, VirtualConsoleClass) == 0)
			//|| (lstrcmp(szClass, L"#32770") == 0) // Ignore dialogs // -- Process dialogs too (Application may be dialog-based)
			|| isConsoleClass(szClass))
		{
			mh_LastIgnoredWnd = hFore;
			goto wrap;
		}
	}

	// Go and check
	if (!GetProcessInfo(nForePID, &prc))
	{
		mh_LastIgnoredWnd = hFore;
		goto wrap;
	}

	CharLowerBuff(prc.szExeFile, lstrlen(prc.szExeFile));

	if (lstrcmp(prc.szExeFile, L"csrss.exe") == 0)
	{
		// This is "System" process and may not be hooked
		mh_LastIgnoredWnd = hFore;
		goto wrap;
	}

	// Is it in monitored applications?
	pszMonitored = gpSet->GetDefaultTerminalAppsMSZ();
	if (pszMonitored)
	{
		// All strings are lower case
		const wchar_t* psz = pszMonitored;
		while (*psz)
		{
			if (_tcscmp(psz, prc.szExeFile) == 0)
			{
				bMonitored = true;
				break;
			}
			psz += _tcslen(psz)+1;
		}
	}

	// And how it is?
	if (!bMonitored)
	{
		mh_LastIgnoredWnd = hFore;
		goto wrap;
	}

	// Need to process
	for (INT_PTR i = m_Processed.size(); i--;)
	{
		if (m_Processed[i].nPID == nForePID)
		{
			bMonitored = false;
			break; // already hooked
		}
	}

	// May be hooked already?
	if (!bMonitored)
	{
		mh_LastWnd = hFore;
		lbRc = true;
		goto wrap;
	}

	_ASSERTE(isDefaultTerminalAllowed());

	TODO("Show status in status line?");

	lbConHostLocked = gpConEmu->LockConhostStart();
	iHookerRc = StartDefTermHooker(nForePID, hProcess, nResult, gpConEmu->ms_ConEmuBaseDir, nErrCode);
	if (lbConHostLocked) gpConEmu->UnlockConhostStart();
	if (iHookerRc != 0)
	{
		mh_LastIgnoredWnd = hFore;
		if (iHookerRc == -3)
			DisplayLastError(L"Failed to start hooking application!\nDefault terminal feature will not be available!", nErrCode);
		goto wrap;
	}

	//hProcess = OpenProcess(PROCESS_QUERY_INFORMATION|SYNCHRONIZE, FALSE, nForePID);
	//if (!hProcess)
	//{
	//	// Failed to hook
	//	mh_LastIgnoredWnd = hFore;
	//	goto wrap;
	//}

	//// Need to be hooked
	//nBits = GetProcessBits(nForePID, hProcess);
	//switch (nBits)
	//{
	//case 32:
	//	_wsprintf(szCmdLine, SKIPLEN(countof(szCmdLine)) L"\"%s\\%s\" /DEFTRM=%u",
	//		gpConEmu->ms_ConEmuBaseDir, L"ConEmuC.exe", nForePID);
	//	break;
	//case 64:
	//	_wsprintf(szCmdLine, SKIPLEN(countof(szCmdLine)) L"\"%s\\%s\" /DEFTRM=%u",
	//		gpConEmu->ms_ConEmuBaseDir, L"ConEmuC64.exe", nForePID);
	//	break;
	//}
	//if (!*szCmdLine)
	//{
	//	// Unsupported bitness?
	//	CloseHandle(hProcess);
	//	mh_LastIgnoredWnd = hFore;
	//	goto wrap;
	//}

	//// Prepare event
	//_wsprintf(szName, SKIPLEN(countof(szName)) CEDEFAULTTERMHOOK, nForePID);
	//SafeCloseHandle(mh_SignEvent);
	//mh_SignEvent = CreateEvent(LocalSecurity(), FALSE, FALSE, szName);
	//if (mh_SignEvent) SetEvent(mh_SignEvent); // May be excess, but if event already exists...

	//// Run hooker
	//si.dwFlags = STARTF_USESHOWWINDOW;
	//bStarted = CreateProcess(NULL, szCmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
	//if (!bStarted)
	//{
	//	DisplayLastError(L"Failed to start hooking application!\nDefault terminal feature will not be available!");
	//	CloseHandle(hProcess);
	//	mh_LastIgnoredWnd = hFore;
	//	goto wrap;
	//}
	//CloseHandle(pi.hThread);
	//// Waiting for result
	//WaitForSingleObject(pi.hProcess, INFINITE);
	//GetExitCodeProcess(pi.hProcess, &nResult);
	//CloseHandle(pi.hProcess);

	// And what?
	if ((nResult == (UINT)CERR_HOOKS_WAS_SET) || (nResult == (UINT)CERR_HOOKS_WAS_ALREADY_SET))
	{
		mh_LastWnd = hFore;
		ProcessInfo inf = {};
		inf.hProcess = hProcess;
		hProcess = NULL; // его закрывать НЕ нужно, сохранен в массиве
		inf.nPID = nForePID;
		//inf.bHooksSucceeded = (nResult == (UINT)CERR_HOOKS_WAS_ALREADY_SET);
		inf.nHookTick = GetTickCount();
		m_Processed.push_back(inf);
		lbRc = true;
		goto wrap;
	}
	// Failed, remember this
	CloseHandle(hProcess);
	mh_LastIgnoredWnd = hFore;
	_ASSERTE(lbRc == false);
wrap:
	if (lbLocked)
	{
		LeaveCriticalSection(&mcs);
	}
	return lbRc;
}
Beispiel #6
0
HWND myGetConsoleWindow()
{
	HWND hConWnd = NULL;
	static HMODULE hHookLib = NULL;
	if (!hHookLib)
		hHookLib = GetModuleHandle(WIN3264TEST(L"ConEmuHk.dll",L"ConEmuHk64.dll"));
	if (hHookLib)
	{
		typedef HWND (WINAPI* GetRealConsoleWindow_t)();
		static GetRealConsoleWindow_t GetRealConsoleWindow_f = NULL;
		if (!GetRealConsoleWindow_f)
			GetRealConsoleWindow_f = (GetRealConsoleWindow_t)GetProcAddress(hHookLib, "GetRealConsoleWindow");
		if (GetRealConsoleWindow_f)
		{
			hConWnd = GetRealConsoleWindow_f();
		}
		else
		{
			_ASSERTE(GetRealConsoleWindow_f!=NULL);
		}
	}

	if (!hConWnd)
	{
		hConWnd = GetConsoleWindow();
		// Это может быть GUI приложение
		if (!hConWnd)
			return NULL;
	}

#ifdef _DEBUG
	// Избежать статической линковки для user32.dll
	HMODULE hUser32 = GetModuleHandle(L"user32.dll");
	if (!hUser32)
	{
		// Скорее всего, user32 уже должен быть загружен, но если вдруг - сильно
		// плохо, если он будет вызываться из DllMain
		_ASSERTE(hUser32!=NULL);
		hUser32 = LoadLibrary(L"user32.dll");
	}
	typedef LONG_PTR (WINAPI* GetWindowLongPtr_t)(HWND,int);
	GetWindowLongPtr_t GetWindowLongPtr_f = (GetWindowLongPtr_t)GetProcAddress(hUser32,WIN3264TEST("GetWindowLongW","GetWindowLongPtrW"));
	typedef int (WINAPI* GetClassName_t)(HWND hWnd,LPWSTR lpClassName,int nMaxCount);
	GetClassName_t GetClassName_f = (GetClassName_t)GetProcAddress(hUser32,"GetClassNameW");
	typedef LONG_PTR (WINAPI* IsWindow_t)(HWND);
	IsWindow_t IsWindow_f = (IsWindow_t)GetProcAddress(hUser32,"IsWindow");

	if (!(GetClassName_f && GetWindowLongPtr_f && IsWindow_f))
	{
		_ASSERTE(GetClassName_f && GetWindowLongPtr_f);
	}
	else
	{
		wchar_t sClass[64];
		if (hConWnd)
			GetClassName_f(hConWnd, sClass, countof(sClass));
		_ASSERTE(hConWnd==NULL || isConsoleClass(sClass));
		#if 0
		if (lstrcmp(sClass, VirtualConsoleClass) == 0)
		{
			// в данных окна DC - хранится хэндл окна консоли
			HWND h = (HWND)GetWindowLongPtr_f(hConWnd, 0);
			if (h && IsWindow_f(h))
			{
				hConWnd = h;
			}
			else
			{
				_ASSERTE(h && IsWindow_f(h));
			}
		}
		#endif
	}
#endif

	return hConWnd;

#if 0
	// Смысла звать GetProcAddress для "GetConsoleWindow" мало, все равно хукается
	typedef HWND (APIENTRY *FGetConsoleWindow)();
	static FGetConsoleWindow fGetConsoleWindow = NULL;

	if (!fGetConsoleWindow)
	{
		HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");

		if (hKernel32)
		{
			fGetConsoleWindow = (FGetConsoleWindow)GetProcAddress(hKernel32, "GetConsoleWindow");
		}
	}

	if (fGetConsoleWindow)
		hConWnd = fGetConsoleWindow();

	return hConWnd;
#endif
}
Beispiel #7
0
BOOL CAttachDlg::AttachDlgEnumWin(HWND hFind, LPARAM lParam)
{
	if (IsWindowVisible(hFind))
	{
		CAttachDlg* pDlg = (CAttachDlg*)lParam;

		// Условия?
		DWORD_PTR nStyle = GetWindowLongPtr(hFind, GWL_STYLE);
		DWORD_PTR nStyleEx = GetWindowLongPtr(hFind, GWL_EXSTYLE);
		DWORD nPID;
		if (!GetWindowThreadProcessId(hFind, &nPID))
			nPID = 0;

		bool lbCan = ((nStyle & (WS_VISIBLE/*|WS_CAPTION|WS_MAXIMIZEBOX*/)) == (WS_VISIBLE/*|WS_CAPTION|WS_MAXIMIZEBOX*/));
		if (lbCan)
		{
			// Более тщательно стили проверить
			lbCan = ((nStyle & WS_MAXIMIZEBOX) == WS_MAXIMIZEBOX) || ((nStyle & WS_THICKFRAME) == WS_THICKFRAME);
		}
		if (lbCan && nPID == GetCurrentProcessId())
			lbCan = false;
		if (lbCan && nPID == pDlg->mn_ExplorerPID)
			lbCan = false;
		if (lbCan && (nStyle & WS_CHILD))
			lbCan = false;
		if (lbCan && (nStyleEx & WS_EX_TOOLWINDOW))
			lbCan = false;
		if (lbCan && gpConEmu->isOurConsoleWindow(hFind))
			lbCan = false;
		if (lbCan && gpConEmu->mp_Inside && (hFind == gpConEmu->mp_Inside->mh_InsideParentRoot))
			lbCan = false;

		wchar_t szClass[MAX_PATH], szTitle[MAX_PATH];
		GetClassName(hFind, szClass, countof(szClass));
		GetWindowText(hFind, szTitle, countof(szTitle));

		if (gpSetCls->isAdvLogging)
		{
			wchar_t szLogInfo[MAX_PATH*3];
			_wsprintf(szLogInfo, SKIPLEN(countof(szLogInfo)) L"Attach:%s x%08X/x%08X/x%08X {%s} \"%s\"", (DWORD)hFind, nStyle, nStyleEx, szClass, szTitle);
			CVConGroup::LogString(szLogInfo);
		}

		if (lbCan)
		{
			wchar_t szPid[32], szHwnd[32], szType[16]; szPid[0] = szHwnd[0] = szType[0] = 0;
			wchar_t szExeName[MAX_PATH], szExePathName[MAX_PATH*4]; szExeName[0] = szExePathName[0] = 0;

			#ifndef ALLOW_GUI_ATTACH
			if (!isConsoleClass(szClass))
				return TRUE;
			#endif

			HWND hList = pDlg->mh_List;
			if (nPID)
			{
				_wsprintf(szPid, SKIPLEN(countof(szPid)) L"%u", nPID);
			}
			else
			{
				#ifdef _DEBUG
					wcscpy_c(szPid, L"????");
				#else
					return TRUE;
				#endif
			}

			HANDLE h;
			bool lbExeFound = false;
			int nImageBits = 32;

			#if 0
			// Так можно получить только имя файла процесса, а интересен еще и путь
			PROCESSENTRY32 pi = {sizeof(pi)};
			h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
			if (h && h != INVALID_HANDLE_VALUE)
			{
				if (Process32First(h, &pi))
				{
					while (pi.th32ProcessID != nPID)
					{
						if (!Process32Next(h, &pi))
							pi.th32ProcessID = 0;
					}
				}
			}
			#endif

			if (pDlg->mp_ProcessData)
			{
				lbExeFound = pDlg->mp_ProcessData->GetProcessName(nPID, szExeName, countof(szExeName), szExePathName, countof(szExePathName), &nImageBits);
				if (lbExeFound)
				{
					//ListView_SetItemText(hList, nItem, alc_File, szExeName);
					//ListView_SetItemText(hList, nItem, alc_Path, szExePathName);
					if (pDlg->mb_IsWin64)
					{
						wcscat_c(szPid, (nImageBits == 64) ? L" *64" : L" *32");
					}
				}
			}

			if (!lbExeFound)
			{
				h = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, nPID);
				if (h && h != INVALID_HANDLE_VALUE)
				{
					MODULEENTRY32 mi = {sizeof(mi)};
					if (Module32First(h, &mi))
					{
						//ListView_SetItemText(hList, nItem, alc_File, *mi.szModule ? mi.szModule : (wchar_t*)PointToName(mi.szExePath));
						lstrcpyn(szExeName, *mi.szModule ? mi.szModule : (wchar_t*)PointToName(mi.szExePath), countof(szExeName));
						//ListView_SetItemText(hList, nItem, alc_Path, mi.szExePath);
						lstrcpyn(szExePathName, mi.szExePath, countof(szExePathName));
						if (pDlg->mb_IsWin64)
						{
							wcscat_c(szPid, WIN3264TEST(L" *32",L" *64"));
						}
						lbExeFound = true;
					}
					else
					{
						if (pDlg->mb_IsWin64)
						{
							wcscat_c(szPid, L" *64");
						}
					}
					CloseHandle(h);
				}
				
				#ifdef _WIN64
				if (!lbExeFound)
				{
					h = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE|TH32CS_SNAPMODULE32, nPID);
					if (h && h != INVALID_HANDLE_VALUE)
					{
						MODULEENTRY32 mi = {sizeof(mi)};
						if (Module32First(h, &mi))
						{
							//ListView_SetItemText(hList, nItem, alc_File, *mi.szModule ? mi.szModule : (wchar_t*)PointToName(mi.szExePath));
							lstrcpyn(szExeName, *mi.szModule ? mi.szModule : (wchar_t*)PointToName(mi.szExePath), countof(szExeName));
							//ListView_SetItemText(hList, nItem, alc_Path, mi.szExePath);
							lstrcpyn(szExePathName, mi.szExePath, countof(szExePathName));
							wcscat_c(szPid, L" *32");
						}
						CloseHandle(h);
					}
				}
				#endif
			}

			LVITEM lvi = {LVIF_TEXT|LVIF_STATE};
			lvi.state = 0;
			lvi.stateMask = LVIS_SELECTED|LVIS_FOCUSED;
			lvi.pszText = szPid;
			lvi.iItem = ListView_GetItemCount(hList); // в конец
			int nItem = ListView_InsertItem(hList, &lvi);
			ListView_SetItemState(hList, nItem, 0, LVIS_SELECTED|LVIS_FOCUSED);

			ListView_SetItemText(hList, nItem, alc_Title, szTitle);
			ListView_SetItemText(hList, nItem, alc_Class, szClass);
			
			_wsprintf(szHwnd, SKIPLEN(countof(szHwnd)) L"0x%08X", (DWORD)(((DWORD_PTR)hFind) & (DWORD)-1));
			ListView_SetItemText(hList, nItem, alc_HWND, szHwnd);

			wcscpy_c(szType, isConsoleClass(szClass) ? szTypeCon : szTypeGui);
			ListView_SetItemText(hList, nItem, alc_File, szExeName);
			ListView_SetItemText(hList, nItem, alc_Path, szExePathName);
			ListView_SetItemText(hList, nItem, alc_Type, szType);
		}
	}
	return TRUE; // Продолжить
}