Sådan ændres kommandoprompt (konsol) vinduetitel fra kommandolinjens Java-app?

Indlæg af Hanne Mølgaard Plasc

Problem



Sådan ændres og opdateres titel på kommandopromptvinduet fra java kommandolinjeprogrammet? Hver gang jeg kører min ansøgning, viser kommandopromptvinduets titel:
C:WINDOWSsystem32cmd.exe - java MyApp.


Jeg vil gerne ændre og opdatere vinduetitel som java-programmet kører, for eksempel som wget (win32) opdateringer, der downloader status i titlen: Wget [12\%].

Bedste reference


Selv om jeg ikke har prøvet det selv, kan man i Windows bruge API'en til Win32 API til SetConsoleTitle for at ændre titel på konsollen. [24]


Men da dette er et opkald til et indbygget bibliotek, vil det kræve brug af noget som Java Native Interface (JNI) for at foretage opkaldet, og dette vil kun fungere på Windows 2000 og senere. [25]


Rediger - En løsning ved hjælp af JNI


Følgende er et eksempel på at bruge JNI for at ændre titel på konsolvinduet fra Java i Windows. For at gennemføre dette er prerequisten en vis viden i C og bruger kompilatoren/linkeren.


Først, her er resultatet:


Ændring af konsoltitel fra en Java-applikation http://coobird.net/img/jni-change-console-title.png[26]


Ansvarsfraskrivelse: Dette er min første Java-applikation ved hjælp af JNI, så det vil nok ikke være et godt eksempel på, hvordan man bruger det - jeg udfører slet ingen fejlkontrol, og jeg mangler muligvis nogle detaljer.


Java-programmet var følgende:


class ChangeTitle {

    private static native void setTitle(String s);

    static {
        System.loadLibrary("ChangeTitle");
    }

    public static void main(String[] args) throws Exception {

        for (int i = 0; i < 5; i++) {
            String title = "Hello! " + i;
            System.out.println("Setting title to: " + title);
            setTitle(title);
            Thread.sleep(1000);
        }
    }
}


I princippet ændres titlen hvert 5. sekund ved at kalde setTitle native metode i et eksternt indfødt bibliotek kaldet ChangeTitle.


Når den ovenstående kode er udarbejdet for at lave en ChangeTitle.class fil, bruges kommandoen javah til at oprette en C-header, der bruges til oprettelse af C-biblioteket. [27]


Skrivning af det oprindelige bibliotek


At skrive biblioteket involverer at skrive C-kildekoden mod C-headerfilen genereret af javah.


ChangeTitle.h overskriften var følgende:


/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class ChangeTitle */

#ifndef \_Included\_ChangeTitle
#define \_Included\_ChangeTitle
#ifdef \_\_cplusplus
extern "C" {
#endif
/*
 * Class:     ChangeTitle
 * Method:    setTitle
 * Signature: (Ljava/lang/String;)V
 */
JNIEXPORT void JNICALL Java\_ChangeTitle\_setTitle
  (JNIEnv *, jclass, jstring);

#ifdef \_\_cplusplus
}
#endif
#endif


Nu, implementeringen, ChangeTitle.c:


#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <jni.h>
#include "ChangeTitle.h"

JNIEXPORT void JNICALL
Java\_ChangeTitle\_setTitle(JNIEnv* env, jclass c, jstring s) {
    const jbyte *str;
    str = (*env)->GetStringUTFChars(env, s, NULL);

    SetConsoleTitle(str);

    (*env)->ReleaseStringUTFChars(env, s, str);
};


A String, der overføres til den native funktion, ændres til en UTF-8 kodet C-streng, som sendes til funktionen SetConsoleTitle, som, som funktionsnavnet antyder, ændrer konsolets titel . [28]


(Bemærk: Der kan være nogle problemer med at bare passere i strengen i funktionen SetConsoleTitle, men ifølge dokumentationen accepterer den også Unicode. Jeg er ikke sikker på, hvor godt koden ovenfor vil fungere, når afsendelse af forskellige strenge.)


Ovennævnte er i grunden en kombination af prøvekode opnået fra afsnit 3.2: Adgang til strenge af Java Native Interface Programmerings vejledning og specifikation og SetConsoleTitle Funktionsside fra MSDN. [29] [30] [31]


For en mere involveret prøvekode med fejlkontroll, se venligst afsnit 3.2: Adgang til strings og SetConsoleTitle Funktionssider. [32] [33]


Opbygning af DLL


Den del, der viste sig for at tage mest tid til at finde ud af, var at få C-filer til at kompilere til en DLL, der rent faktisk kunne læses uden at forårsage en UnsatisfiedLinkError. [34]


Efter en masse søgning og prøvede ting kunne jeg få C-kilden til at kompilere til en DLL, der kunne kaldes fra Java. Siden jeg bruger MinGW, fandt jeg en sideformular mingw.org, som beskrev nøjagtigt, hvordan man bygger en DLL til JNI. [35]


Kilder:



  • Vejledning og specifikation for Java Native Interface Programmerer


    • Kapitel 2: Kom godt i gang - Detaljer processen med JNI.


  • JNI-MinGW-DLL - Opbygning af JNI DLL på MinGW med gcc.


Andre referencer 1


Dette afhænger af din terminalemulator, men i det væsentlige er det bare at udskrive kontrol sekvenser til konsollen. [36] [37] [38]


Nu er jeg ikke klar over, hvilke kontrolsekvenser CMD.EXE reagerer på (jeg har ikke adgang til dette), men jeg hører der 'sa kommando kaldet TITLE, der angiver vinduets titel. Jeg forsøgte at røre TITLE s output til en fil, men tilsyneladende sætter den faktisk ikke titlen på ved at udstyre kontroltegn. START-kommandoen kan tage en parameter som er titel på vinduet efterfulgt af kommandoen til at løbe i vinduet. Så noget som [39]


cmd TITLE "lovely Application that is in a command window." && "java" MyApp
REM or
start "lovely Application that is java based." java MyApp


Personligt vil jeg bare sammenlægge hele sagen med en genvej, hvor du kan redigere egenskaberne som den aktuelle mappe, kommandoen, dens parametre og vinduets størrelse, stil og titel (hvis jeg husker rigtigt). Giv det en dejlig ikon og folk vil bruge det.

Andre referencer 2


Her er min løsning ved hjælp af JNA:


import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;

public class SetTitle {

    public interface CLibrary extends Library {
        CLibrary INSTANCE = (CLibrary)
            Native.loadLibrary((Platform.isWindows() ? "kernel32" : "c"),
                               CLibrary.class);

        boolean SetConsoleTitleA(String title);
    }

    public static void main(String[] args) {
        CLibrary.INSTANCE.SetConsoleTitleA("Testing 123");
        System.exit(0);
    }
}

Andre referencer 3


efter dlamblin s åbenbaring ;-)
her er en python kode.
Bemærk at der er 2 forskellige kommandoer på de fleste programmeringssprog:



  • System

  • exec



systemet vil udstede en systemkommando, exec springer faktisk en ny proces. dermed:


C:>python
>>> import os
>>> os.system("title berry tsakala")


som arbejder inden for et løbende program. Bare find java-ækvivalenten.