uragus
Goto Top

Start MsgBox in User Session

Hallo,
Ich habe eine BAT Datei die mit Hilfe von VBS eine MsgBox aufruft.
Die BAT wird in Session 0 ausgeführt, somit sieht der User die MsgBox nicht.
Kann mir jemand helfen die Msf für den User sichtbar zu machen?

@echo off

call :MsgBox "KAV Installieren?"  "VBYesNo+VBQuestion" "KAV"  
if errorlevel 7 (
        echo NO
) else if errorlevel 6 (
        echo YES
        start "" "Setup.exe"  
)

exit /b

:MsgBox prompt type title
    setlocal enableextensions
    set "tempFile=%temp%\%~nx0.%random%%random%%random%vbs.tmp"  
    >"%tempFile%" echo(WScript.Quit msgBox("%~1",%~2,"%~3") & cscript //nologo //e:vbscript "%tempFile%"  
    set "exitCode=%errorlevel%" & del "%tempFile%" >nul 2>nul  
    endlocal & exit /b %exitCode%

Content-Key: 252834

Url: https://administrator.de/contentid/252834

Printed on: April 19, 2024 at 02:04 o'clock

Member: DerWoWusste
DerWoWusste Oct 23, 2014 at 08:45:00 (UTC)
Goto Top
Hi.

Fernab von vbs: Wenn Du als Admin oder Systemkonto
msg * Nachricht
aufrufst, geht das an alle Sessions.
Member: Friemler
Solution Friemler Oct 23, 2014 updated at 09:24:30 (UTC)
Goto Top
Hallo Uragus,

seit Windows Vista können Prozesse, die in Session 0 laufen, nicht mehr über die MessageBox-API mit der User-Session komunizieren. Es gibt dafür jedoch den speziellen Win32-API-Aufruf WTSSendMessage, den Du allerdings aus einem VBScript heraus nicht ansprechen kannst. Einzige Möglichkeit wäre demnach, ein kleines Programm (z.B. in C oder C++) zu schreiben, das WTSSendMessage benutzt, um die per Parameter übergebene Message anzuzeigen. Dieses Programm kannst Du aus Deinem Batchscript heraus starten.

Ein MSDN-Artikel, der sich mit der Problematik beschäftigt, findet sich hier.

Evtl. findet sich ja auch per Google ein fertiges Tool, was genau das benötigte macht. Das Problem hatten bestimmt schon andere vor Dir.

Gruß
Friemler


[EDIT]
Aha, DerWoWusste macht seinem Namen wieder mal alle Ehre. face-wink
[/EDIT]
Member: Uragus
Uragus Oct 23, 2014 at 09:26:08 (UTC)
Goto Top
Danke für die Aufklärung.
Member: Friemler
Solution Friemler Oct 24, 2014, updated at Nov 08, 2014 at 12:00:20 (UTC)
Goto Top
Ich habe dann doch noch das Hilfsprogramm zum Anzeigen von Messageboxen aus Session 0 heraus geschrieben. Ich habe es mit der Open Source IDE CodeBlocks in C für MinGW entwickelt.

Fertig compilierte Binaries von MinGW findet man hier.

User @rubberman hat außerdem hier eine sehr schöne Anleitung veröffentlicht, um die CodeBlocks IDE incl. MinGW mit Hilfe eines von ihm entwickelten VBScripts als portable Version zu betreiben.

Für den folgenden Code eine Datei namens main.c anlegen und ihn dort hinein kopieren. Aber ACHTUNG!! Die Datei bitte in der Codierung UTF-8 mit BOM (Byte Order Mark) abspeichern!
#define _WIN32_WINNT 0x0600   {{comment_single_line_double_slash:0}}
#include <sdkddkver.h>        {{comment_single_line_double_slash:1}}

#define WIN32_LEAN_AND_MEAN   {{comment_single_line_double_slash:2}}
#define STRICT 1              {{comment_single_line_double_slash:3}}

#define UNICODE               {{comment_single_line_double_slash:4}}
#define _UNICODE              {{comment_single_line_double_slash:5}}
#include <wchar.h>            {{comment_single_line_double_slash:6}}

#include <stddef.h>           {{comment_single_line_double_slash:7}}
#include <stdlib.h>

#include <windows.h>          {{comment_single_line_double_slash:8}}
#include <wtsapi32.h>




/* ******************* */
/* Function prototypes */
/* ******************* */
INT  wmain(INT argc, WCHAR *argv);
BOOL parseCmdLine(INT argc, WCHAR *argv, LPWSTR *message, LPWSTR *title, DWORD *buttons, WINBOOL *waitForClick, DWORD *timeout);




/* ************ */
/* Main program */
/* ************ */
INT wmain(INT argc, WCHAR *argv)
{
  WCHAR   exeName[_MAX_FNAME+1] = L"";  
  LPWSTR  title                 = L"";  
  LPWSTR  message               = NULL;
  DWORD   buttons               = MB_ICONINFORMATION | MB_OK;
  DWORD   titleLength           = 0;
  DWORD   messageLength         = 0;
  DWORD   timeout               = 0;
  WINBOOL waitForClick          = FALSE;
  DWORD   response              = -1;

  DWORD   physConSession = WTSGetActiveConsoleSessionId();

  if (physConSession != 0xFFFFFFFF)
  {
    if (parseCmdLine(argc, argv, &message, &title, &buttons, &waitForClick, &timeout))
    {
      // Die Stringlängen müssen auch bei Unicode-Strings
      // in Bytes angegeben werden!
      messageLength = wcslen(message) * sizeof(*message);
      titleLength   = wcslen(title)   * sizeof(*title);

      WTSSendMessage(WTS_CURRENT_SERVER_HANDLE,
                     physConSession,
                     title, titleLength,
                     message, messageLength,
                     buttons,
                     timeout,
                     &response,
                     waitForClick);
    }
    else
    {
      _wsplitpath(argv, NULL, NULL, exeName, NULL);

      _cwprintf(L"%ls \"Nachricht\" [-h:\"Titel\"] [-b:Buttons] [t:Wartezeit] [/w:true]\n" \  
                L"\n" \  
                L"Nachricht  Text der anzuzeigenden Nachricht.\n" \  
                L"Titel      Text, der in der Titelzeile der Message Box angezeigt wird.\n" \  
                L"Buttons    Eine Zahl, in der der Typ des anzuzeigenden Icons, die darzustellen-\n" \  
                L"           den Buttons und die Nummer des Default-Buttons codiert wird. Die\n" \  
                L"           möglichen Werte finden sich in der Dokumentation der MessageBox-\n" \  
                L"           Funktion auf MSDN.\n" \  
                L"Wartezeit  Wartezeit in Sekunden, nach der sich die Message Box von selbst\n" \  
                L"           schliesst. Ein Wert von 0 führt dazu, dass der Benutzer zuerst auf\n" \  
                L"           einen der Buttons klicken muss, bis die Box geschlossen wird.\n" \  
                L"/w:true    Wird dieser Parameter angegeben, wird erst nachdem die Message Box\n" \  
                L"           geschlossen wurde, die Kontrolle an den Aufrufer zurück gegeben.\n" \  
                L"\n" \  
                L"Das Programm setzt den ERRORLEVEL entsprechend dem Rückgabewert der Message\n" \  
                L"Box. Die möglichen Werte und ihre Bedeutung findet man ebenfalls in der\n" \  
                L"Dokumentation der MessageBox-Funktion auf MSDN."\  
                L"\n",  
                exeName);
    }
  }

  return response;
}



BOOL parseCmdLine(INT argc, WCHAR *argv, LPWSTR *message, LPWSTR *title, DWORD *buttons, WINBOOL *waitForClick, DWORD *timeout)
{
  INT   cnt;
  WCHAR paramName[4];

  for (cnt = 1; cnt < argc; cnt++)
  {
    wcsncpy(paramName, argv[cnt], 3);
    paramName[3] = 0;

    if      (wcsnicmp(paramName, L"/h:", 3) == 0)  
      *title = &argv[cnt][3];

    else if (wcsnicmp(paramName, L"/w:", 3) == 0)  
      *waitForClick = wcsnicmp(&argv[cnt][3], L"true", 4) == 0 ? TRUE : FALSE;  

    else if (wcsnicmp(paramName, L"/t:", 3) == 0)  
      *timeout = wcstoul(&argv[cnt][3], NULL, wcsnicmp(&argv[cnt][3], L"0x", 2) == 0 ? 16 : 10);  

    else if (wcsnicmp(paramName, L"/b:", 3) == 0)  
      *buttons = wcstoul(&argv[cnt][3], NULL, wcsnicmp(&argv[cnt][3], L"0x", 2) == 0 ? 16 : 10);  

    else
      *message = argv[cnt];
  }

  return(*message != NULL);
}

Im gleichen Verzeichnis dann eine Batchdatei namens build.cmd anlegen und folgenden Code hineinkopieren:
@echo off & setlocal

set "PrjName=ServiceMessage"  
set "SourceFile=main"  

set "PrjPath=%~dp0"  
set "GCCPath=E:\CodeBlocksPortable\CodeBlocks\mingw32\bin"  

cd /d "%GCCPath%"  

gcc.exe -finput-charset=UTF-8 -g -O2 -I..\mingw\include -c "%PrjPath%\%SourceFile%.c" -o "%PrjPath%\%SourceFile%.o"  
g++.exe -L..\mingw\lib -o "%PrjPath%\%PrjName%.exe" "%PrjPath%\%SourceFile%.o" -s -municode -static-libgcc -lkernel32 -lwtsapi32  
In Zeile 7 muss man den Pfad zu dem Verzeichnis eintragen, in dem die gcc.exe gespeichert ist. Durch Start der Batchdatei wird der obige C-Quelltext übersetzt. Die erstellte EXE-Datei wird im gleichen Verzeichnis wie die build.cmd abgelegt.

Gruß
Friemler


[EDIT]
Der Quellcode und das Build-Script erzeugen jetzt ein Unicode-fähiges Programm.
[/EDIT]
Member: Uragus
Uragus Oct 24, 2014 at 10:44:13 (UTC)
Goto Top
besten Dank