Reputation: 1
I am having a GPS unit connected to com port. I wanted to make my system as a time server. How to do this?
I tried using settime()
, SetLocalTime()
, SetSystemTime()
, etc. None are working for me. By using system("cmd")
I tried, but again I am not getting administrator privileges. When using system("runas cmd")
the command prompt is opening and closing as blink. Unable to understand what is happening.
How I can make this work?
Upvotes: 0
Views: 1962
Reputation: 149155
Privilege management on Windows is always a tricky part. MSoft assumes that normal mortals should not care with that and documentation is often incomplete.
Here you problem is likely that normal processes (not running as administrator) have not the privilege to change the system time.
But what is possible is:
ShellExectute
, verb="runas"
Here is an example of code (the part to parse the time string and actually set the time is not implemented):
#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;
}
Things to still work on:
cmd /K
to allow user to see what as happened. If you prefere to be more silent, you should use cmd /C
instead and use SW_HIDE
is ShellExecute
.Upvotes: 3