Entwickler-Ecke

Windows API - User-Bild anzeigen?


Insignificant - Mo 03.04.06 17:53
Titel: User-Bild anzeigen?
Hallo....ich versuche verzweifelt das User-Bild von dem Windows-Account richtig anzeigen zu lassen, was mir jedoch leider nicht gelingt.

Delphi-Quelltext
1:
2:
  Image1.Picture.Bitmap.LoadFromFile'C:\Dokumente und Einstellungen'
  + '\All Users\Anwendungsdaten\Microsoft\User Account Pictures\' + GetUser + '.bmp'); }


Aus irgendeinem Grund werden die Bilder vom User anstatt in den originalfarben, anders dargestellt. (Siehe Anhang) hat jemand eine Idee?

PS.: Wenn komischerweise die original bilder (nicht die User bilder) verwendet, funktioniert es einwandfrei!


nullplan001 - Mo 03.04.06 18:17

Hi all,
spontan fällt mir dazu jetzt nur ein, dass Delphi möglicherweise über eine falsche Palette verfügt. Hat den Nachteil: Wie korrigiere ich das jetzt? Die Standard-Tabelle kann ich dir ohne weiteres geben. Zumindest für 256-Farben-Bitmaps. Weiter geht mein Programm nicht. (Bei dir sind es wahrscheinlich 24-Bit-Bitmaps. Das könnte ein wenig in den Webspace gehen, wenn ich so was posten würde. Sind immerhin 2^24 Farben.)
Cya,
nullplan


Insignificant - Do 06.04.06 13:09

Hmmm....bist du sicher das es daran liegt? Weil komischerweise wird das original Bild davon ja auch in den richtigen Farben dargestellt. Das ist ja das *verwunderliche* an der Sache.


Lossy eX - Do 06.04.06 13:52

Nullplan. Du willst nicht allen erstes für RGB eine Farbtabelle anlegen, oder? Und wenn ja nach welchen Kriterien willst du da gehen? Willst du dir jede Farbe schnappen und dir dazu das passende Gegenstück raus suchen?

Also wenn ich das auf den kleinen Bildern richtig sehen kann, dann würde ich spontan behaupten, dass Blau zu Grün geworden ist. Grün zu Rot. Und Rot müsste dann eigentlich Blau sein. Ich würde einfach mal das Bild nach dem Laden Pixel für Pixel durchgehen (mittels Scanlines) und dann die Kanäle tauschen.

PS: Zeigt denn ein Windowsbetrachter die Bilder richtig an. Also so etwas wie IrfanView?


F34r0fTh3D4rk - Do 06.04.06 15:15


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
procedure TForm1.Button1Click(Sender: TObject);
var
  x, y: integer;
  myrgb, r, g, b: integer;
begin
  image1.Picture.LoadFromFile('C:\Dokumente und Einstellungen\All Users\Anwendungsdaten\Microsoft\User Account Pictures\' + getuser + '.bmp');
  for x := 0 to image1.Width do
    for y := 0 to image1.Height do
    begin
      myrgb := colortorgb(image1.canvas.pixels[x, y]);
      r := GetBValue(myrgb);
      g := GetRValue(myrgb);
      b := GetGValue(myrgb);
      image1.canvas.pixels[x, y] := rgb(r, g, b);
    end;
end;

mit scanlines gehts natürlich schneller ;)

falls du das für jeden user machen willst, solltest du den pfad dynamisch laden, kann ja sein, dass jemand kein deutsches win hat, bzw windows auf I:\ so wie ich ;)


Insignificant - Do 06.04.06 15:40

Ja, mein Bildbetrachter zeigt die Bilder richtig an.

Ich habs nun nach deinem Beispiel gemacht F34r0fTh3D4rk und ich muss sagen es sieht schon wesentlich besser aus.
Aber naja *perfekt* isses noch immer nicht...

PS.: In meiner Anwendung ist der Pfad schon dynamisch, ich dachte mir aber es sei sinnvoller fürs Forum den pfad so auszulesen damit auch jeder weiss wo was ist und so ^^


nullplan001 - Do 06.04.06 17:03

Hmmm... sieht so aus, als würde er die Farben zu grell kriegen. Lade mal die Grafiken in Paint und vergrößere beide sehr stark. Delphi macht den Stängel rosa und blau, anstatt grau und weiß. Falsche Sättigung und Helligkeit? Och nö... Wie du das verbessern kannst, weis ich leider nicht (siehe Rand: Ich hab kein Delphi, daraus folgt: keine Delphi-Hilfe, keine Beschreibung von TImage1). Aber könnte sein, oder?
Tschö,
nullplan


Lossy eX - Fr 07.04.06 09:40

Zu Not poste mal das BMP was du versucht darzustellen. Dann können wir uns das mal anschauen. Das dürfte wohl mehr bringen als hier jetzt so rumzuraten.


Insignificant - Fr 07.04.06 15:54

Das Bild kann man >hier [http://www.cn4u.org/jt.bmp]< finden.


Lossy eX - Mo 10.04.06 09:25

Sorry, dass es ein bisschen länger gedauert hat.

Okay. Ich habe eine Gute und eine schlechte Nachricht. Die Gute. Das Bitmap scheint augenscheinlich in Ordnung zu sein und ich weiß warum es Delphi da aushebt. Die Schlechte ist allerdings die, dass ich nicht genau weiß wie man es umgehen soll. ;-)

Also einmal mit IrfanView abgeseichert und dann mit einem Hexeditor die beiden Dateien vergleichen lassen. Und siehe da. Anscheinend ist in den Originalbildern ein Flag anders gesetzt. Dieses ist eine Größenangabe für den Bitmapheader und das ist anders als es eigentlich üblich wäre. So wie es scheint interpretiert Delphi diese Infos nicht so ganz richtig. Er beginnt nämlich 10 Bytes früher mit dem Lesen als die Daten beginnen.

Das TBitmap ist aber leider nicht so berauschend was das einlesen der Bilder angeht. Der kommt unter anderem auch nicht mit größeren Größenangaben klar, falls diese angeben, dass am Ende der Datei zwei nullzeichen vorhanden sind. Hatte ich auch schon. Leider gibt es nicht wirklich viele Alternative.

Wie auch immer. Denke mal zu Darstellen dieser Bilder musst du die Dateien per Hand laden. Du kannst die Daten ja auch in einem TBitmap ablegen. Darfst sie aber nicht damit laden. Musste mal im Forum schauen. Da gibt es schon den ein oder anderen Code dazu.


F34r0fTh3D4rk - Mo 10.04.06 10:08

liegt der flag immer beim gleichen offset ?
wenn die position statisch ist, kann man da programmintern vielleicht ein wenig was drehen


Lossy eX - Mo 10.04.06 10:37

Eigentlich schon. Aber daraus resultierend musst du die Größe auch entsprechend ändern und die kompletten Daten verschieben. Ich denke mal es wäre wesentlich einfacher, wenn man den Header einliest und dann entsprechend auf das Offset reagiert und es überspringt. Und dann die Daten ganz normal in Scanlines einliest.


Insignificant - Mo 10.04.06 12:55

Und wie genau macht man sowas? Verstanden so in etwa was Sache ist und wie man das dann evt. umgehen kann habe ich schon. Nur keine Ahnung wie man sowas in irgendeiner Art und Weise in die Praxis umsetzt.


Darth Sitthiander - Sa 15.04.06 13:39

Ich glaube man muss nur den pfad direkt eingeben, dann gehts bei mir. Jetzt hab ich da ein problem. Wie kann ich herausfinden wo der user diese bilder gespeichert hat? Muss ich das per registry machen oder gibt es da eine function für? Danke im Vorraus.


nullplan001 - So 16.04.06 10:38

Hi all,
hab ich dich richtig verstanden, die Bilder liegen in %systemdrive%\Dokumente und Einstellungen\%username%\Anwendungsdaten\blabla ? Das kann man rauskriegen. Kurz geschrieben heist der Pfad nämlich eingentlich %userprofile%\Anwendungsdaten\blabla. %userprofile% kriegst du mit getenv raus (Wer die Variable verändert, ist selbst schuld, Windows stützt sich nämlich beim Laden des Profils auf diese Variable -> Veränderung = Tod von Windows.) Wenn du bei getenv nur einen leeren String rauskriegst, ist die Variable nicht gesetzt, oder enthält einen leeren String. In dem Fall ist Windows ziemlich schlecht dran. Aber hier die Funktion:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
(*Annahme: System hat NT-Kernel (NT/2kx/XP). Wenn nicht, gibt es die Variable nicht. 
 * Heist dann anders. Funktion wird erweiterbar gemacht, sollte jemand Win9x/ME haben, bitte posten.
 *)

function getPictureDir:string;
var
  isNT : boolean;
  tmp : string;
begin
  isNT := (getenv('OS') <> ''); {%OS% ist bei WinDOS nicht definiert}
  if isNT then begin
      tmp := getenv('userprofile');
      if tmp = '' 
        then tmp := 'C:\Dokumente und Einstellungen\All Users\Anwendungsdaten\blabla' 
        else tmp := tmp + '\Anwendungsdaten\blabla';
    end else (*WinDOS. Macht, was ihr wollt. *)
  Result := tmp;
end;

HTH und tschö,
nullplan


Darth Sitthiander - Mo 17.04.06 01:33

Das erscheint mir schon logisch, aber ich hätte es gern 100%tig richtig. Bei mir heisst der ordner nämlich seit derwindowsinstallation all users.windows. Hoffentlich gibt es da eine lösung. Danke.


nullplan001 - Mo 17.04.06 17:42

Naja, das ist ja auch nur eine Notlösung. Hmm... für All Users heist die Umgebungsvariable %alluserprofile%. Aber auch die kann ungesetzt oder undefiniert sein. Kannst ja noch etwas in der Richtung einbauen. Sieht dann so aus:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
(*Annahme: System hat NT-Kernel (NT/2kx/XP). Wenn nicht, gibt es die Variable nicht. 
 * Heist dann anders. Funktion wird erweiterbar gemacht, sollte jemand Win9x/ME haben, bitte posten.
 *)

function getPictureDir:string;
var
  isNT : boolean;
  tmp : string;

begin
  isNT := (getenv('OS') <> ''); {%OS% ist bei WinDOS nicht definiert}
  if isNT then begin
      tmp := getenv('userprofile');
      if tmp = '' 
        then if getenv('alluserprofile') = ''
           then tmp := 'C:\Dokumente und Einstellungen\All Users\Anwendungsdaten\blabla'
           else tmp := getenv('alluserprofile') + '\Anwendungsdaten\blabla'
        else tmp := tmp + '\Anwendungsdaten\blabla';
    end else (*WinDOS. Macht, was ihr wollt. *)
  Result := tmp;
end;

Oh, verschachtelte if's. Kann sein, dass da eine LostSemicolonException auftritt. Ach, war ja jetzt gar nicht Java ;) :lol: Naja, ich denke, dass das deine bedenken beheben sollte: Wenn es keine %userprofile% gibt, nimm %alluserprofile%, wenns das nicht gibt, nimm Standardpfad. Should be it.
HTH und Tschö,
nullplan


Darth Sitthiander - Di 18.04.06 00:41

Ich hanbs jetzt mal mit nem label getestet, und bei mir steht der nach knopfdruck leer. code und so hab ich drin^^. Stimmt diese Funktion?


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
function GetEnv(Variable:string):string;
var buffer:array[1..1024of char;
begin
if GetEnvironmentVariable( pChar(variable) , @Buffer, Sizeof(buffer) )=0 then
result:=''
else
result:=buffer;
end;


nullplan001 - Di 18.04.06 17:08

Hi all,
Delphi kennt kein getenv()? Schwach, wie ich finde, aber ... solange sich dein Code kompilieren lässt, und du ihn an prominenten Beispielen wie PATH getestet hast, sollte nichts schief gehen (Unter TP und FP gibt es eine Funktion namens getenv, die einem alle Arbeit in die Richtung abnimmt: Wenns sie nicht gibt, gibts nen leeren String, sonst den Inhalt der Variablen)
Tschö,
nullplan
P.S.: solltest du je für ein UNIX-basiertes Betriebssystem schreiben: Dort sind die Umgebungsvariablen Case-Sensitiv. Aber Windows ist da zum Glück nicht so.


Darth Sitthiander - Di 18.04.06 17:23

:lol: :lol: :lol: :lol:
Also ich würde gerne für Windows und mit Delphi schreiben. Aber gibt es denn da gar keine Lösung? Weisst du wo alle Umgebungsvariablen sind? Also jeder Pfad, der bei der windowsinstallation dabei ist? Danke schonmal.


nullplan001 - Mi 19.04.06 14:10

Hi all,
also, ich rate dringend davon ab, die Umgebungsvariablen aus der Registry zu zaubern, weil die

  1. von Version zu Version woanders sein können
  2. GetEnv (oder wie das halt gerade heist) die Umgebungsvariablen immer rauskriegt
  3. nicht alle Umgebungsvariablen in HKLM\Environment oder HKCU\Environment zu finden sind (z.B. %cd%, die den aktuellen Pfad rausfindet (braucht man nur in Batches))

Aber wenn du nur die statischen Variablen haben willst: Öffne eine CMD und tippe ein: cmd /?. Der darauffolgende Hilfetext sollte irgendwo den Speicherort der Variablen anzeigen. Unter Win2k eben HKCU\Environment für die Benutzervariablen und die Systemvariablen in HKLM\Environment.
Und was GetEnv angeht: nimm mal DOS in die USES-Klausel auf. Das sollte dein problem beheben. Wenn er das nicht hat, nimm deinen Code.
Tschö,
nullplan


Darth Sitthiander - Do 20.04.06 13:25

ES gibt dort aber kein Dos.dcu. Kannst du mir ein Projekt machen mit dem man einen button hat und dann direkt wenn man darauf klickt das userbild in ein image geladen wird? Danke, das würde alles für mich leichter machen zu verstehen.


Lossy eX - Do 20.04.06 14:48

Schau dir mal die Methode SHGetFolderPath [http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/functions/shgetfolderpath.asp] an. Diese wird in der Unit SHFolder zur Verfügung gestellt. Damit ist man in jedem Fall auf der sicheren Seite. Und man muss so nicht über irgendwelche Umgebungsvariablen oder sonst etwas gehen.


nullplan001 - Do 20.04.06 18:03

@Dath Sittiander:Würde ich gerne, wenn ich Delphi hätte. Statt dessen schreibe ich dir ein Konsolen-Programm, was den Pfad der Bilder zurückliefert und hänge es samt Quelltext an. Bitte warten... So fertig. Weil du's bist, pack ich noch eine DLL oben drauf, die die Funktion getenv enthält. Bitte sehr.
Tschö,
nullplan


Darth Sitthiander - Fr 21.04.06 10:41

Danke für die Beiden Tipps. Habs jetzt irgendwie kombinieren können^^ Und bei meinem Bruder funktioniert es jetzt. Danke vielmals!


nullplan001 - Fr 21.04.06 18:38

Man hilft doch gern :D
Tschö,
nullplan


turboPASCAL - Do 24.08.06 21:38

Hi,

der Thread ist zwar schon alt, da ich das selbige Problemchen mit den Bitmaps hatte
will ich mal hier noch eine Lösung vorschlagen.
Delphi kommt mit den von Windows angelegten Bitmaps nicht zu recht, alsoeinfach die Bitmaps von Win. laden lassen und gut ist's. ;)


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
implementation

{$R *.dfm}

uses
  ShlObj;

function TForm1.CommonDataPath: string;
const
  CSIDL_COMMON_APPDATA  = $0023// All Users\Application Data
var
  Path: array [0..1024of char;
begin
  if SHGetSpecialFolderPath(Handle, Path, CSIDL_COMMON_APPDATA, TRUE)
    then Result := String(path)
    else Result := '';
end;

function TForm1.GetCurrentUserName: String;
var
  pcUserName : pChar; // temporary storage
  dwMaxChars : dWord; // length parameter
const
  MAXCHARS = 255;  // max length
begin
  dwMaxChars := MAXCHARS;
  GetMem(pcUserName, MAXCHARS + 1);
  if GetUserName(pcUserName, dwMaxChars)
    then Result := String(pcUserName)
    else Result := '';
  FreeMem(pcUserName);
end;

procedure TForm1.FormCreate(Sender: TObject);
var LgPath: String;
begin
  Label1.Caption := GetCurrentUserName;

  LgPath := CommonDataPath + '\Microsoft\User Account Pictures\' +
            Label1.Caption + '.bmp';

  if FileExists(LgPath) then
  begin
    Image1.Picture.Bitmap.Handle :=
      LoadImage(0, PChar(LgPath), IMAGE_BITMAP, 00, LR_LOADFROMFILE);
  end else
    ShowMessage(format('%s'#13#10'"%s"', ['Datei nicht gefunden:', LgPath]));
end;


http://www.delphipraxis.net/post599701.html#599701