Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Delphi RunAs unter Win7 (ohne UAC) (https://www.delphipraxis.net/167163-runas-unter-win7-ohne-uac.html)

Dalai 15. Mär 2012 21:11

RunAs unter Win7 (ohne UAC)
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hey,

ich benutze in einem meiner Programme die Funktion ShellExecuteEx mit dem Verb runas, um den Dialog "Ausführen als" zu öffnen. Das funktioniert unter Win2k und XP einwandfrei. Unter Win7 wird dieser offensichtlich an die UAC weitergegeben. Das kann ich natürlich nicht gebrauchen, denn der Nutzer soll in der Lage sein, den Nutzer selbst zu wählen. Außerdem kommt hinzu, dass der Aufruf ins Leere läuft, wenn die UAC abgeschaltet ist.

Kurz: Ich suche eine Möglichkeit, den gewohnten "Ausführen als"-Dialog auch unter Win7 zu zeigen. Ich weiß, dass es ihn noch* gibt (siehe Bild), aber es war mir bisher nicht möglich, herauszufinden, welche API-Funktion dafür zuständig ist. Alle Suchergebnisse drehen sich nur um UAC und "elevated execution" und so Kram.

Kann mich jemand erhellen?

MfG Dalai

* oder evtl. auch wieder, denn irgendwo habe ich gelesen, dass Vista die Möglichkeit "Ausführen als" komplett fehlt.

jaenicke 15. Mär 2012 22:32

AW: RunAs unter Win7 (ohne UAC)
 
Wie wäre es mit runasuser als Verb? :zwinker:
(Wusste ich auch nicht, habs grad kurz ausprobiert und ging. :mrgreen:)

Popov 15. Mär 2012 22:49

AW: RunAs unter Win7 (ohne UAC)
 
Ich hab mal vor einiger Zeit darüber in About.com Delphi gelesen. Habe mal kurz deren Suche bemüht, vielleicht hilft es:

http://delphi.about.com/od/delphitip...on-startup.htm

Dalai 15. Mär 2012 23:14

AW: RunAs unter Win7 (ohne UAC)
 
Zitat:

Zitat von jaenicke (Beitrag 1156803)
Wie wäre es mit runasuser als Verb?

WTF? Darauf wäre ich nie gekommen! Liegt wohl daran, dass die Dokumentation von MS so überaus vollständig ist :roll: ... In der Doku Datenstruktur SHELLEXECUTEINFO ist selbst das seit Win2k funktionierende Verb runas nicht zu finden :roll:.

Zitat:

(Wusste ich auch nicht, habs grad kurz ausprobiert und ging. :mrgreen:)
In der Tat funktioniert das. Danke! Es hat aber einen dicken Nebeneffekt, der es für den Anwendungszweck unbrauchbar macht: die Funktion ShellExecuteEx kommt sofort zurück im Gegensatz zum Verb runas. Beendet man das Programm danach, ist natürlich auch der Dialog weg... Ich habe folgende Flags probiert: SEE_MASK_NOASYNC, SEE_MASK_WAITFORINPUTIDLE und SEE_MASK_NOCLOSEPROCESS. Keiner davon hilft, die Funktion am Rückkehren zu hindern. Ideen?

Zitat:

Zitat von Popov
Ich hab mal vor einiger Zeit darüber in About.com Delphi gelesen. Habe mal kurz deren Suche bemüht, vielleicht hilft es:

Ein Manifest hat mein Programm bereits mit einem requestedExecutionLevel von "asInvoker", weil es sonst immer die UAC auslöst, wie man in diesem Thema nachlesen kann. Ich möchte aber nur bei Bedarf umschalten und dazu den Nutzer vorher befragen (ohne selbst einen Dialog zu schreiben).

MfG Dalai

himitsu 15. Mär 2012 23:30

AW: RunAs unter Win7 (ohne UAC)
 
Es gibt nicht nur ShellExecute/ShellExecuteEx oder das uralte WinExec ( :lol: ), sondern auch noch CreateProcess.

Zu Letzerem würde ich mal empfehlen ganz genau im MSDN nachzulesen und vorallem auch den Links zu folgen.

Dalai 15. Mär 2012 23:53

AW: RunAs unter Win7 (ohne UAC)
 
Die Existenz der Funktion CreateProcessWithLogonW ist mir bekannt. Ich schrieb aber nicht ohne Grund, dass ich mir die Arbeit sparen will, den Nutzer selbst nach einem alternativen Logon zu fragen. Denn wozu das Rad mehrfach erfinden, wenn es die Funktionalität eh schon gibt? Von dem deutlichen Mehraufwand der Ermittlung eines Tokens (bei CreateProcessAsUser) usw. usf. mal abgesehen.

Falls du auf andere Funktionen anspielst, wäre ich dir dankbar, wenn du etwas konkreter wärst.

MfG Dalai

jaenicke 16. Mär 2012 07:25

AW: RunAs unter Win7 (ohne UAC)
 
Zitat:

Zitat von Dalai (Beitrag 1156811)
Keiner davon hilft, die Funktion am Rückkehren zu hindern. Ideen?

Hmm, das könnte daran liegen, dass du nur noch den Start anstößt und der eigentliche Start irgendwo anders im Benutzerkontext passiert, an den du nicht herankommst ohne Adminrechte. Aber das muss ich erst untersuchen. Dazu komme ich vielleicht am Wochenende.

Du könntest aber als Umgehung deine eigene Anwendung mit diesen Privilegien und einem passenden Parameter starten. Wenn die Anwendung beim Start diesen Parameter findet, startet sie das eigentliche Programm, wartet und sagt dir bei Beendigung Bescheid (Windows Message, Pipe, ...).

Dalai 16. Mär 2012 12:09

AW: RunAs unter Win7 (ohne UAC)
 
Zitat:

Zitat von jaenicke (Beitrag 1156830)
Hmm, das könnte daran liegen, dass du nur noch den Start anstößt und der eigentliche Start irgendwo anders im Benutzerkontext passiert, an den du nicht herankommst ohne Adminrechte.

Nein, so weit kommt es gar nicht. Nach Ende der Funktion ShellExecuteEx rufe ich die Funktion ShowMessage auf, um mir etwas anzeigen zu lassen. Die Meldung kommt schon, während der "Ausführen als"-Dialog noch lädt (ist n bissel langsamer wegen virtueller Maschine).

Zitat:

Du könntest aber als Umgehung deine eigene Anwendung mit diesen Privilegien und einem passenden Parameter starten.
Genau das ist das Ziel. Das eigene Programm mit anderem Nutzer starten. Es geht nicht um irgendein anderes Programm.

Ich werd mir das nachher mal in einer anderen Programmiersprache anschauen, um auszuschließen, dass es am Delphi 5 liegt.

MfG Dalai

jaenicke 16. Mär 2012 12:30

AW: RunAs unter Win7 (ohne UAC)
 
Und warum wartest du dann über das Handle anstatt schlicht via IPC der ersten Instanz Bescheid zu sagen?

Dalai 16. Mär 2012 13:32

AW: RunAs unter Win7 (ohne UAC)
 
Irgendwie reden wir aneinander vorbei. Ich mache es mal anhand von etwas Code - hier von einem Testprogramm - klar:
Delphi-Quellcode:
type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private-Deklarationen }
    function RunAs(const verb: string): Boolean;
  public
    { Public-Deklarationen }
  end;

const
    SEE_MASK_NOASYNC = $00000100;
    SEE_MASK_WAITFORINPUTIDLE = $02000000;

var
  Form1: TForm1;
  hnd: THandle;

implementation

function TForm1.RunAs(const verb: string): Boolean;
var sei: TShellExecuteInfo;
begin
    ShowMessage(verb);
    FillChar(sei, SizeOf(sei), 0);
    sei.cbSize:= SizeOf(sei);
    sei.Wnd:= 0;
    sei.fMask:= SEE_MASK_NOASYNC OR
                SEE_MASK_WAITFORINPUTIDLE (*OR
                SEE_MASK_FLAG_NO_UI*) OR
                SEE_MASK_NOCLOSEPROCESS;
    sei.lpVerb:= PChar(verb);
    sei.lpFile:= PChar(Application.ExeName);
    sei.lpParameters:= PChar('runas');
    sei.nShow:= SW_SHOWNORMAL;
    Result:= ShellExecuteEx(@sei);
    hnd:= sei.hProcess;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
    if RunAs('runas') then ShowMessage('OK');
    ShowMessage(IntToStr(hnd));
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
    if RunAs('runasuser') then ShowMessage('OK');
    ShowMessage(IntToStr(hnd));  
end;
Beim Klick auf Button1 bekomme ich die Meldung 'runas', gefolgt vom UAC-Dialog seitens Windows und nach Ende desselben dann die Meldung 'OK' (oder bei Abbruch der UAC eben gar keine) und zum Schluss das ermittelte Handle.

Beim Klick auf Button2 bekomme ich die Meldung 'runasuser', und danach kommen parallel die Dialoge "Ausführen als" (Windows) und 'OK' (von meinem Programm) und zum Schluss wieder das Handle. Es wird hier also noch gar kein Prozess gestartet, mit dem ich in irgendeiner Weise kommunizieren könnte - was davon abgesehen auch gar nicht geht, weil die "echte" Anwendung auf eine Instanz beschränkt ist via Mutex.

Das ermittelte Handle ist übrigens 0, wenn ich bei 'runas' die UAC abbreche und bei 'runasuser' ist es in jedem Fall 0. Ich kann also gar nicht auf ein Handle warten bei 'runasuser', weil die Funktion ShellExecuteEx gar keins zurückgibt.

MfG Dalai

Bummi 16. Mär 2012 13:51

AW: RunAs unter Win7 (ohne UAC)
 
Du könntest über Findwindow ein gegf. vorhandenes Programm ohne UAC, vor der Mutxprüfung suche und per Message einen Befehl zum beenden senden.

jaenicke 16. Mär 2012 14:10

AW: RunAs unter Win7 (ohne UAC)
 
Zitat:

Zitat von Dalai (Beitrag 1156919)
Beim Klick auf Button2 bekomme ich die Meldung 'runasuser', und danach kommen parallel die Dialoge "Ausführen als" (Windows) und 'OK' (von meinem Programm) und zum Schluss wieder das Handle.

Ok, das hatte ich nicht so verstanden. Ich dachte es ginge um das Warten auf den Prozess oder so.

Dennoch könntest du ein Handle (z.B. ein Fensterhandle) als Parameter mitgeben, über das das gestartete Programm z.B. eine Windows Message schicken kann als Antwort.

Ich schaue mir aber mal an was es sonst noch für Möglichkeiten geben könnte...

Dalai 16. Mär 2012 14:57

AW: RunAs unter Win7 (ohne UAC)
 
Zitat:

Zitat von jaenicke (Beitrag 1156931)
Dennoch könntest du ein Handle (z.B. ein Fensterhandle) als Parameter mitgeben, über das das gestartete Programm z.B. eine Windows Message schicken kann als Antwort.

Das bringt mir nichts. Das Programm benutzt ein Mutex, um mehrfache Instanzen zu verhindern. Ich muss also die laufende Instanz sofort nach (einem erfolgreichen) ShellExecuteEx schließen, damit die neue Instanz die Chance hat, zu starten. Da die Funktion ShellExecuteEx im Falle von 'runasuser' sofort die Kontrolle an das Programm zurückgibt, beendet sich das Programm und das war's; es wird keine neue Instanz gestartet und die laufende beendet sich.

Nebenbei bemerkt ist ShellExecuteEx bei 'runasuser' immer erfolgreich, auch wenn man im "Ausführen als"-Dialog gar nichts macht (ihn also stehenlässt). Man kann also gar nicht unterscheiden, wie der Nutzer den "Ausführen als"-Dialog verlässt. Ich hoffe, nun ist klar, wo das Problem liegt.

Ich habe mir die Sache mal mit AutoIt angeschaut und dort verhält sich Windows exakt genauso. Es liegt also wohl am Win7 selbst - ob von MS beabsichtigt oder nicht, bleibt offen.

MfG Dalai

jaenicke 16. Mär 2012 15:34

AW: RunAs unter Win7 (ohne UAC)
 
Zitat:

Zitat von Dalai (Beitrag 1156943)
Das Programm benutzt ein Mutex, um mehrfache Instanzen zu verhindern. Ich muss also die laufende Instanz sofort nach (einem erfolgreichen) ShellExecuteEx schließen, damit die neue Instanz die Chance hat, zu starten.

Ich mache das in meiner Updaterunit ähnlich, aber die macht die Synchronisation der Starts per IPC.

Ich starte, wenn ich noch keine Adminrechte habe, eine Instanz mit Adminrechten. Diese Instanz benennt die aktuellen Dateien um und kopiert die neuen Dateien ins Verzeichnis. Dann startet sie die ggf. neue Exe, die dann auch Adminrechte hat, sagt der ersten Instanz Bescheid und beendet sich selbst.
Die erste Instanz startet die neue Exe im selben Kontext wie die ursprüngliche Exe (also z.B. ohne Adminrechte) und beendet sich. Die neu gestartete Exe sagt der neuen Admin-Instanz Bescheid und wartet.
Die neue Admin-Instanz löscht nun die zuvor gesicherten Dateien, wenn das Update bis hierhin gekommen ist, meldet den Erfolg des Aufräumens an die neue Instanz im Benutzerkontext und beendet sich.
Die neue Instanz im Benutzerkontext lädt den Zustand der ersten Instanz wieder und sagt dann dem Benutzer Bescheid, dass das Update fertig ist.
Dazu kommt noch die Kommunikation für die Fortschrittsanzeige.

Das funktioniert so sehr gut und ich denke, dass das bei dir auch gehen würde. Deine neue Instanz merkt am Parameter, dass da noch eine alte Instanz beendet werden muss. Dann meldet diese der ersten Instanz, dass sie erfolgreich gestartet ist und wartet bis sich die erste Instanz beendet hat (der Mutex also reserviert werden konnte).
Die erste Instanz wartet nach dem Start bis die Antwort der neuen Instanz kommt und beendet sich dann.

Das sollte doch funktionieren, oder?

Dalai 16. Mär 2012 21:06

AW: RunAs unter Win7 (ohne UAC)
 
Zitat:

Zitat von jaenicke (Beitrag 1156957)
Deine neue Instanz merkt am Parameter, dass da noch eine alte Instanz beendet werden muss. Dann meldet diese der ersten Instanz, dass sie erfolgreich gestartet ist und wartet bis sich die erste Instanz beendet hat (der Mutex also reserviert werden konnte).
Die erste Instanz wartet nach dem Start bis die Antwort der neuen Instanz kommt und beendet sich dann.

Das sollte doch funktionieren, oder?

Ich werd mir das mal anschauen. Das Nervige an der Sache ist, dass ich mal wieder mehr Aufwand treiben muss, weil MS zu doof/faul/whatever ist, um auf allen Systemen ein konsistentes Verhalten hinzubekommen. Schließlich funktioniert es bei Win2k/XP problemlos, und ShellExecuteEx wartet auch dann, wenn fMask gar nicht gesetzt (und damit 0) ist.

MfG Dalai

Dalai 16. Mär 2012 22:14

AW: RunAs unter Win7 (ohne UAC)
 
Mmh, ich habe jetzt drei funktionierende Methoden ausmachen können, weiß aber nicht so recht, welche davon man benutzen sollte.
  • Fenster finden und Nachricht zum Schließen senden (falls der Parameter 'runas' übergeben wurde)
    Delphi-Quellcode:
    hWindow:= FindWindow('TMainForm', PChar(sApplicationTitle));
    if hWindow > 0 then
        SendMessage(hWindow, WM_CLOSE, 0, 0);
  • Bestimmte Nachricht registrieren und darauf reagieren
    Delphi-Quellcode:
    RunAsUserMsg:= RegisterWindowMessage('RunAsUser');
    und falls der Parameter 'runas' angegeben wurde, wird die Nachricht gesendet:
    Delphi-Quellcode:
    SendMessage(HWND_BROADCAST, RunAsUserMsg, 0, 0);
    Die Nachrichtenverarbeitungsroutine ist dann diese:
    Delphi-Quellcode:
    procedure TMainForm.WndProc(var Msg: TMessage);
    begin
        if Msg.Msg = RunAsUserMsg then
            Self.Close;
        inherited;
    end;
  • Ähnlich wie Variante 1: Handle der ersten Instanz an die zweite übergeben (statt es zu suchen) und Nachricht zum Schließen senden.
Es gibt sicher noch andere Varianten, aber ich denke, das sind die einfachsten. Aber welche ist zu bevorzugen bzw. von welcher/welchen sollte man besser Abstand nehmen?

MfG Dalai

himitsu 17. Mär 2012 01:57

AW: RunAs unter Win7 (ohne UAC)
 
Dieser Passwortdialog ist halt ein interner Teil des UAC, welcher sich von extern scheinbar nicht ansprechen läßt, vorallem dann nicht, wenn das UAC nicht läuft.

Ich glaube ich hatte vor sehr vielen Jahren auch mal hier nach sowas gefragt.

Der eigene Dialog ist ja nicht das Problem, aber diesen dann auch noch in einer sicheren Umgebung (eigener Desktop) anzuzeigen, so wie es das UAC macht, damit kein Programm da so einfach automatisch die Anmeldedaten eintragen kann.

Dalai 17. Mär 2012 20:53

AW: RunAs unter Win7 (ohne UAC)
 
Zitat:

Zitat von himitsu (Beitrag 1157018)
Dieser Passwortdialog ist halt ein interner Teil des UAC, welcher sich von extern scheinbar nicht ansprechen läßt, vorallem dann nicht, wenn das UAC nicht läuft.

Nein, er ist kein Teil der UAC. Das Ding lässt sich auch aufrufen, wenn die UAC komplett abgeschaltet ist. Teste es selbst, indem du - bei ausgeschalteter UAC - Shift+Rechtsklick auf eine Verknüpfung (oder eine EXE) auf deinem System machst und "Als anderer Benutzer ausführen" wählst. Eben deswegen bin ich ja so daran interessiert, den Dialog zu nutzen.

Ich habe mich vorerst für die o.g. Variante 3 entschieden, das Handle also via Parameter an die andere Instanz zu übergeben. Das hat den Vorteil, dass ich nicht mit beiden Instanzen dieselbe Message registriere (Variante 2), ich kein Fenster suchen muss (Variante 1; IMO potentiell fehlerträchtig) und nicht alle anderen Fenster mit einem Broadcast nerve (Variante 2).

MfG Dalai

jaenicke 17. Mär 2012 22:29

AW: RunAs unter Win7 (ohne UAC)
 
Liste der Anhänge anzeigen (Anzahl: 1)
Als weitere Möglichkeit blieben noch andere Möglichkeiten der Interprozesskommunikation wie z.B. Semaphore, siehe Anhang. ;-)

himitsu 17. Mär 2012 22:30

AW: RunAs unter Win7 (ohne UAC)
 
Zitat:

Das Ding lässt sich auch aufrufen
Hmm, dann müßte man nur noch die API dafür finden.

Das ding wird aber nicht in einem eigenem Desktop ausgeführt.
Es sieht auch irgendwie ein bissl so aus, wie der neue Vista-TaskDialog.

[add]
Die Fensterklasse von dem Ding ist Bei Google suchenDirectUIHWND.

jaenicke 17. Mär 2012 22:55

AW: RunAs unter Win7 (ohne UAC)
 
Zitat:

Zitat von himitsu (Beitrag 1157117)
Hmm, dann müßte man nur noch die API dafür finden.

Das ist kein Problem, einfach in der Doku durchklicken (Windows Development --> Security and Identity --> Authentication):
CredUIPromptForCredentials
bzw. ab Vista:
CredUIPromptForWindowsCredentials

Dalai 17. Mär 2012 23:10

AW: RunAs unter Win7 (ohne UAC)
 
Zitat:

Zitat von himitsu (Beitrag 1157117)
Zitat:

Das Ding lässt sich auch aufrufen
Hmm, dann müßte man nur noch die API dafür finden.

Wie meinst du das? Ein ShellExecuteEx mit dem Verb 'runasuser' funktioniert doch :gruebel:, wie jaenicke dankenswerterweise herausgefunden hat. Und ganz ehrlich: mehr Aufwand will ich auch gar nicht treiben; alles, was in Richtung eigener Überprüfung der Credentials geht, ist völliger Overkill - jedenfalls für diesen Zweck.

Zitat:

Das ding wird aber nicht in einem eigenem Desktop ausgeführt.
Juckt mich überhaupt nicht. Wird es bei Win2k/XP auch nicht. Und wenn irgendein Programm dort etwas eingeben kann (z.B. mit AutoIt geht das sehr einfach), hat man ein ganz anderes Problem als dass dieser Dialog nicht abgesichert ist ;).

Zitat:

Die Fensterklasse von dem Ding ist Bei Google suchenDirectUIHWND.
Jep, das hatte ich mit Au3Info aus dem AutoIt-Paket schon ermittelt und daran herumgedacht, mit entsprechenden Funktionen zu ermitteln, ob der Dialog noch offen ist (das Warten also nachzuholen, was Windows selbst versäumt). Aber der dafür erforderliche Aufwand ist wohl deutlich höher als die von mir momentan benutzte Variante.

Zitat:

Zitat von jaenicke
Als weitere Möglichkeit blieben noch andere Möglichkeiten der Interprozesskommunikation wie z.B. Semaphore, siehe Anhang.

Das schau ich mir mal an, aber die ebenfalls benutzten Mutexe betrachte ich nicht unbedingt als einfacher (und Semaphoren sind ja sehr ähnlich).

MfG Dalai


Alle Zeitangaben in WEZ +1. Es ist jetzt 22:34 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz