Forum: PC-Programmierung Shell ersetzen in Windows 2000/XP


von Minetti (Gast)


Lesenswert?

Moin.

Man kann mit Hilfe der Registry in Windows 2000/XP bestimmen, mit 
welcher Shell Windows starten soll. Normalerweise ist das der Explorer, 
es lassen sich aber auch andere Programme angeben.

Der Schlüssel ist unter
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows 
NT\CurrentVersion\Winlogon]
und heisst Shell.

Trägt man dort zB cmd.exe ein, startet Windows nach dem Login nur die 
Kommandozeile und zeigt lediglich ein eventuell eingestelltes 
Hintergrundbild auf dem Desktop an. Die Taskleiste und alle 
Desktopsymbole sind verschwunden. Für meine Anwendung als Kiosksystem 
ist das ideal.

Nun möchte ich 2 Java Programme starten und habe mir dafür eine kleine 
Launcher exe geschrieben, die so aussieht:
1
#include <stdlib.h>
2
#include <stdio.h>
3
#include <windows.h>
4
#include "Shlwapi.h"
5
6
int main(int argc, char *argv[])
7
{
8
  FILE * fp;
9
  char fullpath[1024];
10
  char path[1024];
11
  
12
  int pos = 0;
13
  
14
  fp = fopen("programs.ini", "r");
15
  
16
  if (fp)
17
  {
18
    while (fgets(fullpath, sizeof(fullpath), fp))
19
    {
20
        STARTUPINFO si;
21
        PROCESS_INFORMATION pi;
22
        
23
      ZeroMemory( &si, sizeof(si) );
24
      si.cb = sizeof(si);
25
        ZeroMemory( &pi, sizeof(pi) );
26
              
27
        printf("*******************************************************************************\n");
28
      printf("Launching:  %s\n", fullpath);
29
        printf("*******************************************************************************\n");
30
      // Pfad ausführen
31
      
32
      if( !CreateProcess( NULL,   // No module name (use command line)
33
              fullpath,        // Command line
34
              NULL,           // Process handle not inheritable
35
              NULL,           // Thread handle not inheritable
36
              FALSE,          // Set handle inheritance to FALSE
37
              0,              // No creation flags
38
              NULL,           // Use parent's environment block
39
              NULL,           // Use parent's starting directory 
40
              &si,            // Pointer to STARTUPINFO structure
41
              &pi )           // Pointer to PROCESS_INFORMATION structure
42
          ) 
43
        {
44
            printf( "CreateProcess failed (%d)\n", GetLastError() );
45
            return 0;
46
        }
47
    }
48
49
    fclose(fp);
50
  }
51
  
52
    system("PAUSE");
53
    return 0;
54
}

In der Datei programs.ini steht
java -classpath hsqldb.jar org.hsqldb.Server -database.0 
file:hsqldb/fabu/fabu -dbname.0 fabu

und in weiteren Zeilen noch mehr, aber zum Testen reicht es. Starte ich 
nun das Programm per Kommandozeile oder Doppelklick, wird das Java 
Programm con CreateProcess gestartet und ich sehe die 
Kommandozeilenausgabe.

Trage ich meine Exe als Shell ein, wird sie auch gestartet, es steht 
aber nur "Drücken Sie eine beliebige Taste . . ." (die Wirkung von 
system("PAUSE");) und java startet nicht und man sieht demzufolge auch 
keine Ausgaben. Ich kann aber sofort im Anschluss die Exe nochmal per 
Taskmanager ausführen lassen, dann startet java ganz normal.

Hat jemand ne Idee, was ich machen muss, damit die java Prozesse richtig 
erzeugt werden? Die exe liegt auch in demselben Verzeichnis wie die java 
Klassen.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Du könntest den "PAUSE"-Murks auch hinter der Zeile mit der 
Fehlerausgabe einbauen, dann würdest Du sehen, ob und wenn welche 
Fehlermeldung ausgegeben wird.

von Jorge (Gast)


Lesenswert?

Wer hsqldb bentuzen muss tut mir leid. Das ist ein schlechtes System von 
Bugfaces entwickelt. Wie wärs mit "derby.jar". Das ist performant und es 
hält was es verspricht (konform, kleine jar, grosse Datenbestände).

Du könntest dein Java-Programm als Systemdienst starten, dafür gibt es 
mehrere fertige Lösungen (Tomcat hat sowas). In diesem Zusammenhang wird 
dein Problem auch beschrieben und gelöst.

In Visual C++ einen Systemdienst zu generieren geht einfach via Wizard 
("ATL Com Anwendungsassistent... Dienst..."). Natürlich kann man auch 
alles zu Fuss machen und ist auch kein grosser Aufwand (s.a. 
www.codeguru.com). Dein Problem wird dadurch aber nicht gelöst.

Der Vorteil von Systemdiensten ist, dass sie fensterlos sind und damit 
wirst du dann deinen "Hänger" los. Alles dies ist mir noch so ungefähr 
in Erinnerung geblieben, liegt aber leider schon zu lange zurück.


Hilfreich in diesem Zusammenhang:
http://netez.com/2xExplorer/shellFAQ/bg_shell.html#idsb_lonts

Gruss



von Simon K. (simon) Benutzerseite


Lesenswert?

Kann man keine Batch-Datei als Shell angeben? ;)

von Minetti (Gast)


Lesenswert?

Batch Datei hab ich versucht, funktionierte aber nicht. Es gab zwar 
irgendwelche Aktionen, aber das Kommandofenster war schneller weg als 
ich schauen konnte.

Das Problem mit dem Code oben ist der Dateizugriff. Der scheint nicht zu 
klappen, wenn das Programm von Windows gestartet wird. Vielleicht könnte 
man mal schauen, in welchem Verzeichnis man wirklich gestartet wird, für 
mein konkretes Problem hab ich es jetzt so gebaut:
1
#include <stdlib.h>
2
#include <stdio.h>
3
#include <windows.h>
4
#include <string>
5
#include "Shlwapi.h"
6
7
using std::string;
8
9
int main(int argc, char *argv[])
10
{
11
  char cpath[1024];
12
13
  int count = 2;
14
  string paths[count];
15
  string pathenv = "D:\\Eigene Dateien\\FB\\Demo"; // no tailing backslash
16
  paths[0] = "java -classpath hsqldb.jar org.hsqldb.Server -database.0 file:hsqldb/fabu/fabu -dbname.0 fabu";
17
  paths[1] = "java -classpath looks-2.0.4.jar;jsuntimes-0.3.jar;hsqldb.jar;. Start";
18
    
19
  for (int i=0; i<count; i++)
20
  {
21
      STARTUPINFO si;
22
    PROCESS_INFORMATION pi;
23
          
24
    ZeroMemory( &si, sizeof(si) );
25
    si.cb = sizeof(si);
26
    ZeroMemory( &pi, sizeof(pi) );
27
          
28
       strncpy(cpath, paths[i].c_str(), sizeof(cpath));
29
       
30
    printf("*******************************************************************************\n");
31
    printf("Launching:  %s\n", cpath);
32
    printf("*******************************************************************************\n");
33
       
34
    if( !CreateProcess( NULL,   // No module name (use command line)
35
            cpath,        // Command line
36
            NULL,           // Process handle not inheritable
37
            NULL,           // Thread handle not inheritable
38
            FALSE,          // Set handle inheritance to FALSE
39
            0,              // No creation flags
40
            NULL,           // Use parent's environment block
41
            pathenv.c_str(),           // starting directory 
42
            &si,            // Pointer to STARTUPINFO structure
43
            &pi )           // Pointer to PROCESS_INFORMATION structure
44
        ) 
45
      {
46
      printf( "CreateProcess failed (%d)\n", GetLastError() );
47
      }
48
    
49
    Sleep(100);    
50
  }  
51
52
//    system("PAUSE");
53
    return 0;
54
}

Ist zwar schleifentechnisch äusserst hässlich, tut aber. Muss nochmal 
schauen, ob ich es irgendwie doch so bauen kann, dass die zu startenden 
Pfade aus einer externen Textdatei gelesen werden können.

von Schrumpfschlauch (Gast)


Lesenswert?

Warum benutzt du nicht das JNI, um die Java-Programme aus C heraus zu 
starten? Beispiele gibts da genug im Weltnetz!

von Minetti (Gast)


Lesenswert?

So, und nun hab ich auch noch rausgefunden, warum das fopen nicht 
funktionierte: Ganz einfach, wenn Windows die Exe startet, führt sie die 
in der Umgebung von c:\ aus. So geht ein fopen ohne komplette Pfadangabe 
in die Hose. Man bekommt den kompletten Pfad jedoch an main übergeben, 
kann den dann da rausfummeln und zum öffnen der Datei benutzen.

Sieht jetzt also so aus:
1
#include <stdlib.h>
2
#include <stdio.h>
3
#include <windows.h>
4
#include <string>
5
#include "Shlwapi.h"
6
7
using std::string;
8
9
int main(int argc, char *argv[])
10
{
11
  printf("EXE: %s\n", argv[0]);
12
13
  char command[1024] = {0};
14
  char envpath[1024] = {0};  
15
  strncpy(envpath, argv[0], sizeof(envpath)-1);  
16
  int pos = strlen(envpath);
17
    
18
  while (pos > 0 && envpath[pos] != '\\')
19
  {
20
    envpath[pos--] = '\0';
21
  }
22
  
23
  printf("PATH: %s\n", envpath);
24
  SetCurrentDirectory (envpath);
25
  
26
  FILE * fp = fopen("programs.ini", "r");
27
  
28
  if (fp)
29
  {
30
    while (fgets(command, sizeof(command), fp))
31
    {
32
      StrTrim(command, "\r\n ");
33
      
34
      if (strlen(command) == 0)
35
      {
36
        continue;
37
      }
38
      
39
        STARTUPINFO si;
40
      PROCESS_INFORMATION pi;
41
          
42
      ZeroMemory( &si, sizeof(si) );
43
      si.cb = sizeof(si);
44
      ZeroMemory( &pi, sizeof(pi) );
45
       
46
      printf("*******************************************************************************\n");
47
      printf("Launching:  %s\n", command);
48
      printf("*******************************************************************************\n");
49
       
50
      if( !CreateProcess( NULL,   // No module name (use command line)
51
              command,        // Command line
52
              NULL,           // Process handle not inheritable
53
              NULL,           // Thread handle not inheritable
54
              FALSE,          // Set handle inheritance to FALSE
55
              0,              // No creation flags
56
              NULL,           // Use parent's environment block
57
          envpath,        // Use parent's starting directory 
58
              &si,            // Pointer to STARTUPINFO structure
59
              &pi )           // Pointer to PROCESS_INFORMATION structure
60
          ) 
61
        {
62
        printf( "CreateProcess failed (%d)\n", GetLastError() );
63
        }
64
    
65
      Sleep(100);          
66
    }
67
    
68
    fclose(fp);
69
  }
70
//    system("PAUSE");
71
    return 0;
72
}

War JNI nicht der Weg, um von Java auf nativen Code zugreifen zu können? 
Das ist ja dann die falsche Richtung.

So wie oben tut es jetzt genau wie es soll und ist auch noch für andere 
Anwendungsfälle geeignet, in denen die zu startenden Programme nicht 
Java sind. Als Erweiterung könnte man noch die Umgebungspfade für jedes 
Programm explizit setzen.

von Schrumpfschlauch (Gast)


Lesenswert?

>War JNI nicht der Weg, um von Java auf nativen Code zugreifen zu können?
>Das ist ja dann die falsche Richtung.

JNI ist für beide Richtungen. Man kann damit auch problemlos deine 
Richtung beschreiten. Aber wenn jetzt funktioniert => umso besser für 
dich!

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.