代码
#include <iostream>
#include "atlstr.h"
#include <stdio.h>
#include <stdlib.h>
#include <ctime>
#include <chrono>
#include <thread>
#include <Windows.h>
#include <WtsApi32.h>
#include <unordered_map>
#include <ntsecapi.h>
using namespace std;
unordered_map <char, int> record = { {'f',0x46},{'w' ,0x57},{'h',0x48},{'1',0x31},
{'9',0x39},{'7',0x37},{'0',0x30},{'6',0x36},{'1',0x31},{'5',0x35},{'2',0x32},{'3',0x33}};
void independentThread()
{
std::cout << "Starting concurrent thread.\n";
std::this_thread::sleep_for(std::chrono::seconds(2));
std::cout << "Exiting concurrent thread.\n";
}
void threadCaller(float time)
{
std::cout << "Starting thread caller.\n";
std::thread t(independentThread);
t.detach();
std::this_thread::sleep_for(std::chrono::seconds((int)time));
std::cout << "Exiting thread caller.\n";
}
string getTime()
{
time_t timep;
time(&timep);
char tmp[64];
strftime(tmp, sizeof(tmp), "%H:%M:%S %Y-%m-%d", localtime(&timep));
return tmp;
}
BOOL CALLBACK EnumChildProc(_In_ HWND hwnd, _In_ LPARAM lParam)
{
char szTitle[MAX_PATH] = { 0 };
char szClass[MAX_PATH] = { 0 };
int nMaxCount = MAX_PATH;
LPSTR lpClassName = szClass;
LPSTR lpWindowName = szTitle;
GetWindowTextA(hwnd, lpWindowName, nMaxCount);
GetClassNameA(hwnd, lpClassName, nMaxCount);
cout << "[Child window] window handle: " << hwnd << " window name: "
<< lpWindowName << " class name: " << lpClassName << endl;
return TRUE;
}
/*
** Function:EnumWindowsProc
** Using: 应用程序定义的函数,用于EnumWindows()或EnumDesktopWindos()函数。
接收顶层窗口句柄。WNDENUMPROC类型定义了指向这种回调函数的指针。
EnumWindowsProc是一个应用程序定义的函数名称的占位符。
*/
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
//除了少数具有 WS_CHILD 样式的系统的顶级窗口,EnumWindows函数不枚举子窗口。
char szTitle[MAX_PATH] = { 0 };//MAX_PATH 这个变量是windows自己宏定义的变量 #define MAX_PATH 260
char szClass[MAX_PATH] = { 0 };
int nMaxCount = MAX_PATH;
LPSTR lpClassName = szClass;//LPSTR相当于char*
LPSTR lpWindowName = szTitle;
//Function: GetWindowTextA
//Using : 该函数将指定窗口的标题条文本(如果存在)拷贝到一个缓存区内。如果指定的窗口是一个控件,则拷贝控件的文本。
//但是,GetWindowText可能无法获取外部应用程序中控件的文本,获取自绘的控件或者是外部的密码编辑框很有可能会失败。
//Return : 如果函数成功,返回值是拷贝的字符串的字符个数,不包括中断的空字符;
//如果窗口无标题栏或文本,或标题栏为空,或窗口或控制的句柄无效,则返回值为零。
GetWindowTextA(hwnd, lpWindowName, nMaxCount);
GetClassNameA(hwnd, lpClassName, nMaxCount);
cout << "[Parent window] window handle: " << hwnd << " window name: "
<< lpWindowName << " class name: " << lpClassName << endl;
EnumChildWindows(hwnd, EnumChildProc, lParam);
return TRUE;
}
BOOL CALLBACK EnumDesktopProc(LPTSTR lpszDesktop, LPARAM lParam) {
//关于LPTSTR 打印乱码
/*
1.首先 setlocale(LC_ALL, "chs");
2.LPTSTR lpDeskName = lpszDesktop;
3.printf("Desktop name:%s\n", lpDeskName);
*/
//setlocale(LC_ALL, "chs");
LPTSTR lpDeskName = lpszDesktop;
printf("Desktop name:%s\n", lpDeskName);
EnumWindows(EnumWindowsProc, lParam);
return TRUE;
}
//判断是否锁屏(0是没锁屏,1是锁屏)
bool IsSessionLocked()
{
typedef BOOL(PASCAL* WTSQuerySessionInformation)(HANDLE hServer, DWORD SessionId, WTS_INFO_CLASS WTSInfoClass, LPTSTR* ppBuffer, DWORD* pBytesReturned);
typedef void (PASCAL* WTSFreeMemory)(PVOID pMemory);
WTSINFOEXW* pInfo = NULL;
WTS_INFO_CLASS wtsic = WTSSessionInfoEx;
bool bRet = false;
LPTSTR ppBuffer = NULL;
DWORD dwBytesReturned = 0;
LONG dwFlags = 0;
WTSQuerySessionInformation pWTSQuerySessionInformation = NULL;
WTSFreeMemory pWTSFreeMemory = NULL;
HMODULE hLib = LoadLibrary(L"wtsapi32.dll");
if (!hLib)
{
return false;
}
pWTSQuerySessionInformation = (WTSQuerySessionInformation)GetProcAddress(hLib, "WTSQuerySessionInformationW");
if (pWTSQuerySessionInformation)
{
pWTSFreeMemory = (WTSFreeMemory)GetProcAddress(hLib, "WTSFreeMemory");
if (pWTSFreeMemory != NULL)
{
DWORD dwSessionID = WTSGetActiveConsoleSessionId();
if (pWTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, dwSessionID, wtsic, &ppBuffer, &dwBytesReturned))
{
if (dwBytesReturned > 0)
{
pInfo = (WTSINFOEXW*)ppBuffer;
if (pInfo->Level == 1)
{
dwFlags = pInfo->Data.WTSInfoExLevel1.SessionFlags;
}
if (dwFlags == WTS_SESSIONSTATE_LOCK)
{
bRet = true;
}
}
pWTSFreeMemory(ppBuffer);
ppBuffer = NULL;
}
}
}
if (hLib != NULL)
{
FreeLibrary(hLib);
}
return bRet;
}
//模拟键盘点击(不能用在登录界面,屏蔽其他进程)
//没有支持的机制来解锁工作站。你将不得不编写一个自定义的GINA模块,然后以某种方式与之通信。
//对于标准GINA,您可以得到最接近的是做自动登录(例如使用Autologon tool from SysInternals)。
//但是,自动登录只能在机器重新启动后或用户注销后启动,因此用户会话将会丢失。
void key_hit() {
keybd_event(VK_RETURN, 0, 0, 0);
keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
/*string temp = "123";
for (int i = 0; i < temp.size(); i++) {
keybd_event(record[temp[i]], 0, 0, 0);
keybd_event(record[temp[i]], 0, KEYEVENTF_KEYUP, 0);
cout << record[temp[i]] << endl;
}
keybd_event(VK_RETURN, 0, 0, 0);
keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);*/
}
//锁屏(模拟win+l不行)
void lock_screen() {
//cout << "请输入锁屏时间(秒)\n";
float time = 5;
//cin >> time;
clock_t delay;
delay = time * CLOCKS_PER_SEC;
clock_t start = clock();
cout << "计时开始时间:";
string v_s_start = getTime();
cout << v_s_start << endl;
threadCaller(time);
//while(clock()-start<delay);
system("rundll32.exe user32.dll,LockWorkStation");
}
//通过get Windows title,关闭Windows
void close_windows() {
HWND m_handle = 0;
int num = 0;
while (m_handle == 0 && num < 60) {
m_handle = ::FindWindowA(NULL, "Chat | Microsoft Teams");
++num;
Sleep(100);
}
if (m_handle != 0)
{
::SendMessageA(m_handle, WM_CLOSE, 0, 0);
}
}
void MouseMove(int x, int y)
{
double fScreenWidth = ::GetSystemMetrics(SM_CXSCREEN) - 1;
double fScreenHeight = ::GetSystemMetrics(SM_CYSCREEN) - 1;
double fx = x * (65535.0f / fScreenWidth);
double fy = y * (65535.0f / fScreenHeight);
INPUT Input = { 0 };
Input.type = INPUT_MOUSE;
Input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE;
Input.mi.dx = fx;
Input.mi.dy = fy;
SendInput(1, &Input, sizeof(INPUT));
}
void MouseLeftDown() //鼠标左键按下
{
INPUT Input = { 0 };
Input.type = INPUT_MOUSE;
Input.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
SendInput(1, &Input, sizeof(INPUT));
}
void MouseLeftUp() //鼠标左键放开
{
INPUT Input = { 0 };
Input.type = INPUT_MOUSE;
Input.mi.dwFlags = MOUSEEVENTF_LEFTUP;
SendInput(1, &Input, sizeof(INPUT));
}
void MouseRightDown() //鼠标右键按下
{
INPUT Input = { 0 };
Input.type = INPUT_MOUSE;
Input.mi.dwFlags = MOUSEEVENTF_RIGHTDOWN;
SendInput(1, &Input, sizeof(INPUT));
}
void MouseRightUp() //鼠标右键放开
{
INPUT Input = { 0 };
Input.type = INPUT_MOUSE;
Input.mi.dwFlags = MOUSEEVENTF_RIGHTUP;
SendInput(1, &Input, sizeof(INPUT));
}
int main(int argc, char* argv[])
{
/*
枚举屏幕上的所有的顶层窗口,轮流地将这些窗口的句柄传递给一个应用程序定义的回调函数。
EnumWindows会一直进行下去,直到枚举完所有的顶层窗口,或者回调函数返回了FALSE.
*/
Sleep(7 * 1000);
//HWINSTA hwinsta = GetProcessWindowStation();
//EnumDesktopsA(hwinsta,(DESKTOPENUMPROCA)EnumDesktopProc, 0);
//EnumWindows(EnumWindowsProc, 0);//EnumWindowsProc EnumChildProc
close_windows();
//cout<<IsSessionLocked()<<endl;
//MouseMove(0.1,0.1);
return 0;
}
API
EnumDesktopsA
EnumDesktopProc
EnumWindows
EnumWindowsProc
解释
EnumWindows有两个参数:
BOOL EnumWindows(
WNDENUMPROC lpEnumFunc,
LPARAM lParam
);
其中,WNDENUMPROC指向应用程序定义的回调函数的指针。也就是EnumWindowsProc。
EnumWindowsProc是回调函数:
BOOL CALLBACK EnumWindowsProc(
_In_ HWND hwnd,
_In_ LPARAM lParam
);
hwnd是窗口的句柄,lParam是在EnumWindows或EnumDesktopWindows中给定的应用程序定义的值。
根据代码,我在EnumWindowsProc的回调函数中,得到窗口的title后,再调用EnumDesktopsA函数。
BOOL EnumDesktopsA(
HWINSTA hwinsta,
DESKTOPENUMPROCA lpEnumFunc,
LPARAM lParam
);
它的lpEnumFunc为EnumDesktopProc,但是,实际操作中,我不能直接写入会报转换类型错误,而WNDENUMPROC lpEnumFunc则不会。(这里我强转了一下可以了,以后可以看看为什么:))
BOOL CALLBACK EnumDesktopProc(
_In_ LPTSTR lpszDesktop,
_In_ LPARAM lParam
);
这里打印LPTSTR,它的不能正常打印。查看定义后,发现wchar_t类型,打印会出现乱码。我找到以下解决方法:
关于LPTSTR 打印乱码
setlocale(LC_ALL, "chs");
LPTSTR lpDeskName = lpszDesktop;
printf("Desktop name:%s\n", lpDeskName);
具体可以看看代码:)