# Notebook-Batterie-Status auslesen?



## joe210 (19. Jul 2006)

Will ein kleines Programm schreiben, dass den Akku-Stand meines Notebooks anzeigt und dann entsprechend nach bisherigem Verbrauch die vorraussichtliche verbleibende Laufzeit anzeigt.

Unter *Linux *ist das jetzt nicht das große Problem, da ich den aktuellen Zustand des Akkus im /proc-Filesystem auslesen kann.

Nur hat jemand eine Idee, wie ich das unter *Windows *lösen kann? (Dafür würde es mich primär interessieren)


----------



## foobar (19. Jul 2006)

Gibt es bei Sourceforge/Freshmeat noch keine Lib(C, C++, Java) die das kann? Würde mich wundern.


----------



## joe210 (22. Jul 2006)

Hab mich jetzt mal ausführlicher bei Sourceforge und Freshmeat umgesehen, aber leider keine passende Lib gefunden. Alles was ich gefunden hab, sind welche für Linux - nicht aber für Windows.

Jetzt aber mal eine andere Idee: ist es möglich, ohne zusätzliches C-Programm (nur als Beispiel, über JNI halt), Befehle der Windows-API auszuführen? Dann hätte ich nämlich evtl. eine Chance....


----------



## foobar (22. Jul 2006)

Wenn du auf die Windows-API zugreifen willst, brauchst du nativen Code. Was spricht gegen C und JNI?


----------



## joe210 (23. Jul 2006)

> Was spricht gegen C und JNI?



Ich kann mit beidem nicht umgehen :cry: 

Kann ich deiner Antwort außerdem entnehmen, dass es nur über das JNI zu lösen ist? Wenn dem so ist, werd ich mich wohl doch einlesen müssen...  :###


----------



## Der_Unwissende (23. Jul 2006)

Hi, du wirst die Methode GetSystemPowerStatusEx (einfach mal bei MSDN reinschauen) verwenden müssen. 
dazu gehörige MSDN Seite
Die sollte das erfüllen, was du machen möchtest. Du bekommst ein Struct zurück, dass alle Infos enthält (näheres auf der Seite)

Gruß Der Unwissende

[EDIT]Sorry, Link korrigiert[/EDIT]


----------



## Guest (23. Jul 2006)

Hi, ich war mal so frei, dir etwas Code zu erstellen. Wie ich gearde sehe gibt es hier keine direkt Methode ein Attachment anzuhängen.  Deshalb poste ich hier einfach mal den Code, müsstest den dann selbst mit dem C-Compiler deiner Wahl in eine Dll umwandeln, kann dir natürlich auch was zu schicken.

```
// Kapselung der Windows-Struktur und nativer Methoden aufruf

public class SystemPowerStatus {

	public static final short AC_LINE_STATUS_OFFLINE = 0;
	public static final short AC_LINE_STATUS_ONLINE = 1;
	public static final short AC_LINE_STATUS_UNKNOWN_STATUS = 255;	
	
	public static final short BATTERY_FLAG_HIGH = 1; // the battery capacity is at more than 66 percent
	public static final short BATTERY_FLAG_LOW = 2; // the battery capacity is at less than 33 percent	
	public static final short BATTERY_FLAG_CRITICAL = 4; // the battery capacity is at less than five percent
	public static final short BATTERY_FLAG_CHARGING = 8; 
	public static final short BATTERY_FLAG_NO_SYSTEM_BATTERY = 128;
	public static final short BATTERY_FLAG_UNKNONW_STATUS = 255; // unable to read the battery flag information	
	
	private short acLineStatus; // see AC_LINE_STATUS_xxx
	private short batteryFlag; // see BATTERY_FLAG_xxx
	private short batteryLifePercent; // 0 .. 100
	private short reserved1; // must be 0
	private int batteryLifeTime; // lifetime in seconds, -1 if unknown
	private int batteryFullLifeTime; // lifetime in seconds if the battery is fullcharged, -1 if unknown
	
  protected void setAcLineStatus(final short acLineStatus) {
    this.acLineStatus = acLineStatus;
  }
	
	public short getAcLineStatus() {
    return this.acLineStatus;
  }
	
	protected void setBatteryFlag(final short batteryFlag) {
    this.batteryFlag = batteryFlag;
  }
  
  public short getBatteryFlag() {
    return this.batteryFlag;
  }
  
  protected void setBatteryLifePercent(final short batteryLifePercent) {
    this.batteryLifePercent = batteryLifePercent;
  }
  
  public short getBatteryLifePercent() {
    return this.batteryLifePercent;
  }
  
  protected void setReserved1(final short reserved1) {
    this.reserved1 = reserved1;
  }
  
  public short getReserved1() {
    return this.reserved1;
  }
  
  protected void setBatteryLifeTime(final int batteryLifeTime) {
    this.batteryLifeTime = batteryLifeTime;
  }
  
  public int getBatteryLifeTime() {
    return this.batteryLifeTime;
  }
  
  protected void setBatteryFullLifeTime(final int setBatteryFullLifeTime) {
    this.batteryFullLifeTime = setBatteryFullLifeTime;
  }
	
	public int getBatteryFullLifeTime() {
	 return this.batteryFullLifeTime;
  }
	
	public native void getSystemPowerStatus(); 	
	
	static {
		System.loadLibrary("batteryStatus");
	}
	
}
```


```
// der dazu gehörige C Code (geht bestimmt schöner, aber bin halt kein C Programmierer)

#include "batteryStatus_SystemPowerStatus.h"
#include <windows.h>
#include <stdio.h>

JNIEXPORT void JNICALL Java_batteryStatus_SystemPowerStatus_getSystemPowerStatus(JNIEnv *env, jobject obj) {

  SYSTEM_POWER_STATUS status;

  jclass jcls;
  jmethodID jmid;
  BOOL valid;
  
  jcls = (*env)->GetObjectClass(env, obj);

  valid = GetSystemPowerStatus(&status);
  
  if (valid) {     

    jmid = (*env)->GetMethodID(env, jcls, "setAcLineStatus", "(S)V");
    
    if (jmid != 0) {
      (*env)->CallVoidMethod(env, obj, jmid, status.ACLineStatus);
    }
    
    jmid = (*env)->GetMethodID(env, jcls, "setBatteryFlag", "(S)V");
    
    if (jmid != 0) {
      (*env)->CallVoidMethod(env, obj, jmid, status.BatteryFlag);
    }    
    
    jmid = (*env)->GetMethodID(env, jcls, "setBatteryLifePercent", "(S)V");
    
    if (jmid != 0) {
      (*env)->CallVoidMethod(env, obj, jmid, status.BatteryLifePercent);
    }

    jmid = (*env)->GetMethodID(env, jcls, "setReserved1", "(S)V");
    
    if (jmid != 0) {
      (*env)->CallVoidMethod(env, obj, jmid, status.Reserved1);
    }
    
    jmid = (*env)->GetMethodID(env, jcls, "setBatteryLifeTime", "(I)V");
    
    if (jmid != 0) {
      (*env)->CallVoidMethod(env, obj, jmid, status.BatteryLifeTime);
    }
    
    jmid = (*env)->GetMethodID(env, jcls, "setBatteryFullLifeTime", "(I)V");
    
    if (jmid != 0) {
      (*env)->CallVoidMethod(env, obj, jmid, status.BatteryFullLifeTime);
    }    
  }
}
```

Die eingebundene batteryStatus_SystemPowerStatus.h ist dabei mittels "javah -jni" Klassenname erstellen. Das C-Programm musst du dann mit einer Option übersetzen, die es in eine Dll umwandelt. Wie man das macht hängt stark vom Compiler ab. Die erzeugte Dll muss dann im Suchpfad deines Programmes liegen. Ich denke mit der Kapselung kannst du dann gut weiter arbeiten. Änderungen der Methodennamen müsstest du dann im C File anpassen.

Gruß Der Unwissende


----------



## joe210 (24. Jul 2006)

Erstmal danke für die mehr als ausführliche Antwort! Ich bin echt beeindruckt  :shock: 

Ich setz mich dann mal in mein stilles dunkles Kämmerlein und komm erst wieder raus, wenn ich alles verstanden und begriffen hab  :wink: 

(Ich werd's mal ausprobieren und bei Fragen meld ich mich wieder)


----------



## thE_29 (25. Jul 2006)

Dein C Code sieht sehr danach aus, als hättest du packages Verwendet!

Die muss der andere Benutzer auch haben, sonst gehts nicht!


----------



## Der_Unwissende (25. Jul 2006)

Als hätte ich in C Packages verwendet? Da wusste ich gar nicht dass das geht. 
Wie gesagt, bin nicht wirklich ein C-Crack (oder hab auch nur mehr als geringe Grundkenntnisse). Der Import der stdio.h ist hier übrigens unnötig (sollte eigentlich nicht mehr verwendet werden). 
Die Windows.h ist aus dem Microsoft PSDK (wenn ich mich nicht ganz irre). Jedenfalls wird dieses imho gerne von den Herstellern der Compiler mitgeliefert. Ich habe hier den BCC (Borland C Compiler) verwendet, der ist frei verfügbar und liefert es definitiv mit. Es müssen halt nur Bibliotheks und Include Verzeichnisse dem Compiler entsprechend angepasst werden (bei Borland kann man das dann per Schalter wie bei anderen auch oder per cfg Datei, die dann automatisch mit eingebunden wird).

Klar, für den Aufruf eines WIN-API Befehls braucht man halt die Windows.h (hier ist auch BOOL definiert), aber das ist sicherlich klar.
Was die oberste etwas längere Header-Datei angeht, die ist natürlich die von Javah erzeugte. Wie gesagt, ich weiß ja gar nicht genau ob du das mit Package meinst oder nicht. 

Was das Verstehen angeht, es ist garnicht so kompliziert. Microsoft bietet per API an, dass du den SystemPowerStatus abrufen kannst. Dies ist die Methode GetSystemPowerStatus aus der windows.h 
Dieser übergibt man einen Zeiger auf ein Struct (ein Verbundsdatentyp in C), der die Felder enthält, die du per getter/setter auch in der Java Klasse findest. Ja, ich meine die Java-Klasse dürfte sich relativ leicht von selbst erklären. Hier habe ich eigentlich nur diese Struktur nachgebildet (als Klasse). Die Konstanten entsprechen dem was Microsoft zurückliefert (Zuordnung über das Präfix).

Der eigentliche Teil, der vom "reinen" Java abweicht ist ja dann der native Teil. Hier wird nur die Signatur einer nativen Methode angegeben. Das native entspricht dabei dann einem externen Verweis. Damit Java auch eine Bibliothek hat, auf die sich dieser Verweis bezieht, muss du die entsprechende Bibliothek bekannt machen. Das passiert dann per System.LoadLibrary. Der hier übergebene Name muss natürlich dem der dll entsprechen.
Hast du diese Java-Klasse fertig, so kannst du per Javah -jni dir die dazugehörige Header-Datei von Java erstellen lassen. In dieser wird dann auch die jni.h oder so eingebunden. Das heißt, auch das Verzeichnis von Java, in dem du diese Dateien findest musst du deinem C-Compiler/Linker bekannt machen.

Eine C Headerdatei entspricht weitgehend einem Interface in Java (mal aus der Sicht eines nicht C-Programmierers gesprochen!). Hier stehen vorallem mal die Signaturen der Methoden (ich denke aber, hier kannst du auch Definitionen / Konstanten /... vornehmen).
Jedenfalls steht hier schon der Name der Methode drin, die wie die Native Methode in deinem Java-Code heißt (plus ein Präfix um die Klasse zuzuordnen). 
Auch der Typ und die Anzahl der Parameter stehen hier schon (werden automatisch korrekt angelegt). Was fehlt ist nun so zu sagen die Implementierung dieser Header-Datei. Dazu legst du einfach einen neue .c Datei an (die so heißt wie die dll später heißen soll). 
In dieser kommt dann natürlich das include der von Java erzeugten Header-Datei. Die windows.h brauchst du noch zusätztlich, da hier der Befehl getSytemPowerStatus drin steht (und die Struktur). Der Rest ist eigentlich nur noch die Implementierung der Methode. 
Hättest du ein reines C-Programm, würdest du einfach nur eine SYSTEM_POWER_STATUS Struktur nehmen (wahrscheinlich sogar nur einen Zeiger und ein Alloc oder so) und dann die Funktion GetSystemStatus aufrufen. Sie liefert dir einen Wahrheitswert, ob alles gut ging. Bei Fehlern kann man dann mit getLastError sich den Fehlercode des letzten Befehls holen (aber wird hier nicht gemacht).
Nun hast du also eine C-Struktur, in der alle Werte stehen, die du gerne hättest. Da du in Java mit diesen Werten weiterarbeiten möchtest, musst du sie also in eine Java-Struktur packen. Hier gibt es natürlich mehrere Möglichkeiten. Du könntest eine eigene Klasse schreiben und eine neue Instanz von ihr zurück geben oder eine Instanz an diese Methode als Parameter übergeben oder halt (so wie hier), etwas unsauber die Daten mit der Methode des Abrufs mischen. 
Jedenfalls ist der Rest in den JNI Docs von Java nachzulesen. Grob gesagt hat holt man sich die Infos was für eine Klasse genau übergeben wird. Die zwei Argumente der C-Funktion sind übrigens in jedem JNI Aufruf zu finden. Die zweite ist dabei immer der this Zeiger des Aufrufers. Du holst dir als die Infos, von welcher Klasse dieses this eine Instanz ist.
Der Rest ist nun auch gar nicht mehr kompliziert. jmid ist immer eine MethodID. Man könnte auch einfacher sagen (weiß gar nicht ob es hier wirklich stimmt), du holst dir einen Funktionszeiger. Aus deiner Klasse (jcls) holst du dir die Methode "xyz" mit den Argumenten "(...)"  und dem Rückgabetyp ".." Argumente und Rückgabetyp werden dabei in einen String geschrieben, die Argumente (deren Typ) stehen dabei in der Klammer. Die Abkürzungen der Typen findest du wieder auf den JNI Seiten von Sun.
S steht hier für short, V für Void,...
Wenn du einen Zeiger hast, dann weißt du nur vom Null Zeiger, dass der gar nicht gültig ist. Hier prüfst du jetzt also, ob der Funktionszeiger != 0 ist.
Wenn ja, rufst du die Methode (hier die setter bzw. halt die Methode auf die jmid zeigt) der Instanz (obj) auf und übergibst die Parameter. status.XXX ist dabei halt die Windows SYSTEM_POWER_STATUS Struktur.

Ist eigentlich einfacher als ich es hier wohl ausdrücke. 

Viel Erfolg jedenfalls!

Gruß Der Unwissende


----------



## thE_29 (25. Jul 2006)

Du hast in Java Packages verwendet und die bei deinem Code nicht mitangegeben!

In C gibts keine packages!

Wenn mich nicht alles täuscht ist das dein package gewesen:

batteryStatus.SystemPowerStatus;


Und wenn der user das bei seinem java Code nicht angibt, kann er mit der dll nix anfangen!


----------

