c++实现局域网内远程开关机

注:转载自其他博客

修改以作备忘。

把远程开、关机写成了一个类的两个静态函数。

这两个功能的实现都需要事先对目标主机进行一些设置。其中远程开机需要目标主机主板支持,并且插上网线。部分主机的设置已经写明。

远程开关机工具,需要对目标主机作如下设置

  • 远程开机:
    1、BIOS设置
    (DELL):
        system setup->BIOS设置->Power Management->设置Deep Sleep Control为Disable Wake on Lan为LAN only
    (ASUS):
        Advance->APM->开启【Power On By PCIE】(PCIE: PCI-Ethernet)
    2、系统设置
        step one:设备管理器->网络适配器->选择对应网卡设备, 属性->高级->开启【Wake on Magic Packet】->开启【Wake on Pattern match】->开启【关机 网络唤醒】->关闭【环保节能】

step two:设备管理器->网络适配器->选择对应网卡设备, 属性->电源管理->关闭【允许计算机关闭此设备以节约电源】

  • 远程关机:
  1. 启动Guest账户
    我的电脑->管理->计算机管理->本地用户和组->用户->选择Guest进入属性->关闭【账户已停用】

  2. 允许Guest用户从网络访问此计算机
    win+r->gpedit.msc->本地计算机策略->Windows设置安全属性->安全设置->本地策略->用户权限分配->从【拒绝从网络访问这台计算机】中删除Guest

  3. 允许Guest用户从远端系统强制关机

    win+r->gpedit.msc->本地计算机策略->Windows设置安全属性->安全设置->本地策略->用户权限分配->将Guest加入【从远程系统强制关机】

CRemoteControl.h实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#pragma once

#include <Windows.h>
#include <stdio.h>

#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "advapi32.lib")

class CRemoteControl
{
public:
CRemoteControl(void);
~CRemoteControl(void);
public:
static int Startup(char *chMac);
static int Shutdown(char *chIP, int iTimeOut, bool bForceAppsClosed, bool bRebootAfterShutDown);
}

//CRemoteControl.cpp实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#include "RemoteControl.h"


CRemoteControl::CRemoteControl(void)
{
}

CRemoteControl::~CRemoteControl(void)
{
}

int CRemoteControl::Startup(char *chMac)
{
//判断Mac地址格式
for (char *a=chMac; *a; a++)
{
if (*a != '-' && !isxdigit(*a))
{
OutputDebugStringA("Mac address must be like this: 00-d0-4c-bf-52-ba");
return -1;
}
}

//字符串转数组
int dstaddr[6];
int i = sscanf(chMac, "%2x-%2x-%2x-%2x-%2x-%2x", &dstaddr[0], &dstaddr[1], &dstaddr[2], &dstaddr[3]
, &dstaddr[4], &dstaddr[5]);

if (i != 6)
{
OutputDebugStringA("Invalid mac address!");
return -1;
}

//构造Magic Packet (包格式: "FFFFFFFFFFFF" + 重复16编mac地址)
unsigned char ether_addr[6];
for (i=0; i<6; i++)
{
ether_addr[i] = dstaddr[i];
}

u_char magicpacket[200];
memset(magicpacket, 0xff, 6);
int packetsize = 6;
for (i=0; i<16; i++)
{
memcpy(magicpacket+packetsize, ether_addr, 6);
packetsize += 6;
}

//创建广播套接字
WSADATA WSAData;
if (WSAStartup(MAKEWORD(2, 0), &WSAData) != 0)
{
OutputDebugStringA("WSAStartup failed");
return -1;
}

SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock == INVALID_SOCKET)
{
OutputDebugStringA("Socket Create error");
return -1;
}

BOOL bOptval = TRUE;
int iOptLen = sizeof(BOOL);
if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char*)&bOptval, iOptLen) == SOCKET_ERROR)
{
OutputDebugStringA("setsocketopt error!");
closesocket(sock);
WSACleanup();
return -1;
}

sockaddr_in to;
to.sin_family = AF_INET;
to.sin_port = htonl(0);
to.sin_addr.S_un.S_addr = htonl(INADDR_BROADCAST);

//发送魔法包
if (sendto(sock, (const char*)magicpacket, packetsize, 0, (const struct sockaddr*)&to, sizeof(to)) == SOCKET_ERROR)
{
OutputDebugStringA("Send error!");
}
else
{
OutputDebugStringA("Send success!");
}

closesocket(sock);
WSACleanup();
return 0;
}
//参数
//chIP 需要关闭的电脑IP
//iTimeOut 多少秒后关机
//bForceAppsClosed 是否强制关闭所有程序
//bRebootAfterShutDown 是否重启
int CRemoteControl::Shutdown(char *chIP, int iTimeOut, bool bForceAppsClosed, bool bRebootAfterShutDown)
{
HANDLE hToken;
TOKEN_PRIVILEGES tkp;

BOOL fResult;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
return false;

LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid);
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES) NULL, 0);
if (GetLastError() != ERROR_SUCCESS)
return false;

WCHAR wszIP[20];
memset(wszIP, 0, sizeof(wszIP));
MultiByteToWideChar(CP_ACP, 0, chIP, strlen(chIP)+1, wszIP, sizeof(wszIP)/sizeof(wszIP[0]));

//发送指令,iTimeOut如果小于60,则对方机器关机前会显示“一分钟内关机”
fResult = ::InitiateSystemShutdown(wszIP, NULL, iTimeOut, bForceAppsClosed, bRebootAfterShutDown);
if (!fResult)
return false;

tkp.Privileges[0].Attributes = 0;
AdjustTokenPrivileges(hToken, false, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0);
if(GetLastError() != ERROR_SUCCESS)
return false;

return true;
}

调用Startup和Shutdown实现远程开关机。