c++ - 在 C++ 中设置 Windows 系统时间

标签 c++ windows cmd shellexecute runas

我有一个 GPS 单元连接到 com 端口。我想让我的系统成为一个时间服务器。如何做到这一点?

我尝试使用 settime()SetLocalTime()SetSystemTime() 等。没有一个适合我。通过使用 system("cmd") 我试过了,但我还是没有获得管理员权限。使用 system("runas cmd") 时,命令提示符以闪烁方式打开和关闭。无法理解发生了什么。

我怎样才能让它发挥作用?

最佳答案

Windows 上的权限管理始终是一个棘手的部分。 MSoft 假定普通人不应该关心这一点,并且文档通常不完整。

这里的问题很可能是正常进程(不是以管理员身份运行)没有更改系统时间的权限。

但可能的是:

  • 检查是否将 SeSystemtimePrivilege 授予正在运行的进程
    • 如果只是设定时间
    • 如果没有通过 ShellExectute 以与管理员相同的参数重新启动进程,verb="runas"

下面是一个代码示例(解析时间字符串和实际设置时间的部分没有实现):

#include <iostream>
#include <windows.h>
#include <tchar.h>

#ifdef UNICODE
#define tcout std::wcout
#else
#define tcout std::cout
#endif

// utility used to display error messages
void errmsg() {
    DWORD err = ::GetLastError();
    LPTSTR msg;
    ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL,
        err, LANG_NEUTRAL, (LPTSTR) &msg, 0, NULL);
    tcout << _T("Error") << std::endl;
}

int _tmain(int argc, TCHAR *argv[]) {
    // syntax check
    if (argc != 2) {
        tcout << _T("Usage ") << argv[0] << " _time_" << std::endl;
        return 1;
    }
    LPCTSTR time = argv[1];
    // get access to the current process token
    HANDLE process = ::GetCurrentProcess();
    HANDLE token;
    if (! ::OpenProcessToken(process, TOKEN_ALL_ACCESS, &token)) {
        errmsg();
        return 1;
    }
    // get priviledges from current token
    DWORD sz = 0, sz2;
    TOKEN_PRIVILEGES *privs;
    ::GetTokenInformation(token, TokenPrivileges, NULL, 0, &sz); // first only size
    if (sz == 0) {
        errmsg();
        return 1;
    }
    privs = (TOKEN_PRIVILEGES *) malloc(sz);
    if (! ::GetTokenInformation(token, TokenPrivileges, privs, sz, &sz2)) {
        errmsg();
        return 1;
    }

    // display found priviledges and look if SE_SYSTEMTIME_NAME is present
    BOOL ok = FALSE;
    for (size_t i=0; i<privs->PrivilegeCount; i++) {
        sz = 0;
        ::LookupPrivilegeName(NULL, &(privs->Privileges[i].Luid), NULL, &sz);
        LPTSTR name = (LPTSTR) malloc(sz * sizeof(TCHAR));
        if (! ::LookupPrivilegeName(NULL, &(privs->Privileges[i].Luid), name, &sz)) {
            errmsg();
            return 1;
        }
        if (0 == ::lstrcmp(name, SE_SYSTEMTIME_NAME)) {
            ok = TRUE;
        }
        // tcout << name << std::endl;
        free(name);
    }
    free(privs); // done with it
    tcout << (ok ? _T("Can") : _T("Cannot")) << _T(" change time") << std::endl;

    if (ok) {
        tcout << _T("Setting time with ") << time << std::endl;
        // actually parse the time string and call SetSystemTime
        //...
    }
    else {
        tcout << _T("Restart self as admin...") << std::endl;
        // start as cmd /K "full path" to have a chance to see eventual errors
        LPTSTR params = (LPTSTR) malloc(MAX_PATH + 7 + lstrlen(time));
        lstrcpy(params, _T(" /K \""));
        sz = ::GetModuleFileName(NULL, params + 5, MAX_PATH);
        // tcout << params + 5 << std::endl;
        ::lstrcat(params,_T("\" "));  // do not forget the trailing "
        lstrcat(params, time);
        // Let's go, the UAC control should pop to allow the privilege elevation
        if (((int) ShellExecute(NULL, _T("runas"), _T("cmd.exe"), params,
                _T("."), SW_SHOW)) < 32) {
            tcout << _T("Could not start self with elevated privileges") << std::endl;
            return 1;
        }
        free(params);
    }
    // time to clean...
    ::CloseHandle(token);
    ::CloseHandle(process);
    return 0;
}

需要继续努力的事情:

  • 当命令在管理员模式下重新启动时,使用带有 cmd/K 的控制台来允许用户查看发生了什么。如果你更喜欢安静一点,你应该使用 cmd/C 而不是使用 SW_HIDE is ShellExecute
  • 这个程序假定新时间将作为一个简单的字符串给出,它可能与您的用例相关,也可能不相关
  • 应使用可选参数控制冗长
  • 系统应该防止多次尝试 runas admin(可能是第二个或可选参数)

关于c++ - 在 C++ 中设置 Windows 系统时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41609920/

相关文章:

c++ - 从 C++ 创建共享库

opencv - cmake 无法找到与 Unix Makefiles 对应的构建程序

windows - 用不同目录中的文件替换子目录中的多个文件

c++ - 二维 vector 的迭代器

c++ - 如何从 C++ 定义中获取编译日期?

windows - docker -无法计算缓存键: not found - runs fine in visual studio

windows - "Open With"使用CMD

python - 如何知道pip安装了哪些包

android - 通过 ADB 在设备中导航

C++返回引用实际上返回垃圾值