Entwickler-Ecke

Windows API - Uhrzeit umstellen bei Windows Vista


Sephiroth - Do 22.02.07 13:10
Titel: Uhrzeit umstellen bei Windows Vista
Hallo,

ich habe bisher folgende Routine verwendet um bei Windows die Uhrzeit umzustellen:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
function SetLocalTime(Value: TDateTime): boolean;
var
  SysTimeVar: TSystemTime;
begin
  DateTimeToSystemTime(Value, SysTimeVar);
  Result := Windows.SetLocalTime(SysTimeVar);
end;


beim suchen im Forum hab ich diese Routine gefunden:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
function SetLocalTime(Value: TDateTime): Boolean;
var
  SysDateTime: TSystemTime;
begin
  ZeroMemory(@SysDateTime, SizeOf(SysDateTime));
  with SysDateTime do
  begin
    DecodeDate(Value, wYear, wMonth, wDay);
    DecodeTime(Value, wHour, wMinute, wSecond, wMilliSeconds);
    Result := SetSystemTime(SysDateTime);
  end;
end;



leider funktionieren beide unter Vista nicht. Ich denke es hängt mit dem neuen Rechtemanagement zusammen.

Kann mir einer sagen, wie ich das bei Windows Vista hinbekomme?

Moderiert von user profile iconChristian S.: Code- durch Delphi-Tags ersetzt


Renegade - Do 22.02.07 18:20

Als Administrator bekommt man das hin!


jaenicke - Do 22.02.07 19:02

Das Problem ist ja, dass dir als normaler User das Token SeSystemtimePrivilege fehlt. Das kannst du dir aber AFAIK für einen laufenden Prozess nicht direkt holen. Du kannst aber einen neuen Prozess starten (oder ein OLE-Objekt), womit dann die Systemzeit gesetzt wird.

Eine andere Möglichkeit, bei der dann aber die Abfrage nach den Adminrechten gleich beim Start der Anwendung kommt, wäre ein Manifest zu erstellen, das Windows sagt, dass die Anwendung Adminrechte braucht. Ob man da auch bestimmte Token angeben kann, weiß ich nicht.
Grundsätzlich geht es mit requestedExecutionLevel.

Mehr zu diesen Sachen findet sich bei MS:
http://msdn2.microsoft.com/en-us/library/aa480150.aspx#accprotvista_topic8


Sephiroth - Fr 23.02.07 10:36

@ Renegade:

Leider funktionieren diese beide Routinen bei mir auch nicht mal unter dem Administrator. Wie würdest du das als Administrator hinbekommen?



@ jaenicke:

Danke für den Link. Werde ich mir heute Nachmittag mal genauer anschauen. Aber könntest du mir sagen, wie ich einen neuen Prozess staten kann, der auch die Rechte hat die Systemzeit setzen zu können? Das ist mir momentan leider absolut unklar.



Vielen Dank für eure Antworten!


jaenicke - Fr 23.02.07 11:19

1. Beide Routinen funktionieren als Admin (rechte Maustaste --> "Als Administrator ausführen" meine ich natürlich) bei mir...
2. Wenn für den neuen Prozess eine neue Exe nimmst, dann kannst du einfach eine Manifest-Resource darin einbinden, die dem System sagt, dass Adminrechte nötig sind:


Sephiroth - Fr 23.02.07 12:17

Danke jaenicke. Ich verstehe bisher dieses Manifest-Prinzip noch nicht so ganz, aber dazu werd ich mir einfach mal ein paar Artikel durchlesen.


Was mich aber noch verwundert ist der Punkt 1:

Wenn ich mich als Administrator anmelde und das Programm einfach starte und versuche die Routine auszuführen, wird die Uhrzeit nicht umgestellt.
Wenn ich aber, wie du beschrieben hast, rechts klicke und "Als Administrator ausführen" klicke, klappt es.
Das versteh ich beim besten Willen nicht. Kann mir das einer erklären?


UGrohne - Fr 23.02.07 12:46

Das ist die UAC. Wenn Du Dein Programm startest, wird untersucht, welche Rechte das Programm braucht. Findet es beispielsweise kein Manifest, das höhere Rechte anfordert, ist es wahrscheinlich, dass es im normalen Benutzerkontext gestartet wird und Systemzugriffe nicht erlaubt sind. Für diese Untersuchung spielt beispielsweise auch der Dateiname eine Rolle (Namen mit install, setup oder sowas werden als administrator-relevant eingestuft).

Mit dem Punkt "Als Administrator starten" kannst Du direkt den Administratorkontext erzwingen. Ein Wechsel des Kontextes im laufenden Prozess ist nicht möglich, sondern nur über die Erzeugung weiterer Prozesse oder über COM.


SatBL - Do 30.09.10 08:29

Hallo zusammen,

ich habe auch dieses Uhrzeit Problem.

Die Uhrzeit meiner Clients werden vom Server über eine Client/Server Verbindung regelmässig aktualiert. Bei XP hat das super funtioniert. Bei Windows 7 geht das leider nicht mehr, weil die Rechte fehlen. Mit einem Manifest kann ich auch nicht arbeiten, da die Funtion in einer DLL eingebetet ist und die Anwendung über einen Autostart gestartet wird.

Ich habe gelesen das man sich die fehlenden Admin rechte über ein OLE-Objekt realisieren könnte. Leider habe ich mit den OLE-Objekten keine Erfahrung. Hat jemand von euch so etwas schon mal realisiert oder könnte sogar ein Stück Code posten?


Gruß
Bernd


jaenicke - Do 30.09.10 10:27

Mit OLE:
http://blog.delphi-jedi.net/2008/03/18/elevate-application-on-vista-with-jwscl/
Dich interessiert Teil 2.


SatBL - Do 30.09.10 12:56

Hallo Jaenicke,

danke für die Info, ich habe mir ein Bsp. wie in Teil 2 beschrieben zusammen gebaut.
Wie bekomme ich jetzt meine Funtion SetLocalTime(...) darein, das habe ich noch nicht so ganz verstanden.

Hier mal der bisherige Code:


Delphi-Quelltext
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:
library Set_Time;

uses
  jwaWindows,
  ActiveX,
  Dialogs,
  Classes,
  ComObj,
  RunElCOM_TLB,
  StdVcl,
  ComServ,
  JwsclElevation,
  SysUtils;

{$R *.res}

type
 TJwRunElevated = class(TTypedComObject, IJwRunElevated)
                    protected
                      function RunAppElevated(AppName: PWideChar;
                                              Parameter: PWideChar; Dir: PWideChar;
                                              ClientProcessID: LongWord; out NewThreadHandle: LongWord;
                                              out NewProcessHandle: LongWord;
                                              out ResultValue: LongWord): HResult;  stdcall;
                     {IJwRunElevated-Methoden hier deklarieren}
                  end;

resourcestring
  ElevationDescription = 'Run Application Elevated';


function TJwRunElevated.RunAppElevated(AppName: PWideChar; Parameter: PWideChar; Dir: PWideChar;
                                       ClientProcessID: LongWord; out NewThreadHandle: LongWord;
                                       out NewProcessHandle: LongWord; out ResultValue: LongWord): HResult;
var ProcHandle : HANDLE;
    StartupInfo : TStartupInfoW;
    ProcessInfo : TProcessInformation;

    pDir : PWideChar;
    Para : WideString;
    ClientProc,
    ThisProc : HANDLE;

begin
  ZeroMemory(@StartupInfo, sizeof(StartupInfo));
  StartupInfo.cb := SizeOf(StartupInfo);


  if Length(Dir) <> 0 then
    pDir := PWideChar(Dir)
  else
    pDir := nil;

  Para := '"'+WideString(AppName)+'" '+WideString(Parameter);

  SetLastError(0);
  if CreateProcessW(
        nil,//__in_opt     LPCTSTR lpApplicationName,
        PWideChar(Para), //__inout_opt  LPTSTR lpCommandLine,
        nil,//__in_opt     LPSECURITY_ATTRIBUTES lpProcessAttributes,
        nil,//LPSECURITY_ATTRIBUTES(InVars.Parameters.lpThreadAttributes),//__in_opt     LPSECURITY_ATTRIBUTES lpThreadAttributes,
        true,//__in         BOOL bInheritHandles,
        0,//__in         DWORD dwCreationFlags,
        nil,//__in_opt     LPVOID lpEnvironment,
        pDir,//'',//TJwPChar(InVars.Parameters.lpCurrentDirectory),//__in_opt     LPCTSTR lpCurrentDirectory,
        StartupInfo,//__in         LPSTARTUPINFO lpStartupInfo,
        ProcessInfo //__out        LPPROCESS_INFORMATION lpProcessInformation
    ) then
  begin
    ResultValue := GetLastError;
    result := S_OK;

    if GetCurrentProcessId <> ClientProcessID then begin
      ClientProc := OpenProcess(MAXIMUM_ALLOWED, true, ClientProcessID);

      DuplicateHandle(GetCurrentProcess, ProcessInfo.hProcess, ClientProc, @NewProcessHandle,
         SYNCHRONIZE or READ_CONTROL or PROCESS_VM_READ, true, DUPLICATE_CLOSE_SOURCE);

      DuplicateHandle(GetCurrentProcess, ProcessInfo.hThread, ClientProc, @NewThreadHandle,
         SYNCHRONIZE or READ_CONTROL or THREAD_QUERY_INFORMATION, true, DUPLICATE_CLOSE_SOURCE);

      CloseHandle(ClientProc);
    end
    else begin
      NewProcessHandle := ProcessInfo.hProcess;
      NewThreadHandle  := ProcessInfo.hThread;
    end;

  end
  else begin
    ResultValue := GetLastError;
    if ResultValue = 0 then;
    result := E_FAIL;
  end;

end;

begin
  try
    TJwElevationClassFactory.Create(@ElevationDescription,
                                    true,
                                    ComServer,
                                    TJwRunElevated,
                                    CLASS_JwRunElevated,
                                    ciMultiInstance);
  except
  end;
end.


Moderiert von user profile iconmatze: Code- durch Delphi-Tags ersetzt