|
Antwort |
MathiasSimmack
(Gast)
n/a Beiträge |
#1
Ich habe mal wieder eine kleine Spielerei inkl. Frage für die Interessierten unter euch. Ein Beitrag im DF hat mich wieder daran erinnert, dass ich auf der Platte noch eine HTML-Seite mit ein paar so genannten undokumentierten Funktionen von Windows habe. Darunter auch die "ShellMessageBox", s. hier:
Delphi-Quellcode:
Das Interessante an der Box ist nun, das man gleich Stringressourcen angeben kann, ohne diese vorher laden zu müssen, etwa
type
TShellMessageBoxA = function(Module: THandle; Owner: HWND; Text: pchar; Caption: pchar; Style: UINT; Parameters: array of pointer): integer; cdecl; TShellMessageBoxW = function(Module: THandle; Owner: HWND; Text: PWideChar; Caption: PWideChar; Style: UINT; Parameters: array of pointer): integer; cdecl; // Die "cdecl"-Deklaration ist kein Fehler. var ShellMessageBoxA : TShellMessageBoxA; ShellMessageBoxW : TShellMessageBoxW; dll : dword = 0; begin dll := LoadLibrary('shell32.dll'); if(dll <> 0) then begin @ShellMessageBoxA := GetProcAddress(dll,pointer(183)); @ShellMessageBoxW := GetProcAddress(dll,pointer(182)); if(@ShellMessageBoxA = nil) or (@ShellMessageBoxW = nil) then begin MessageBox(0,'Funktionen wohl nicht vorhanden',nil,0); FreeLibrary(dll); exit; end; { ... } FreeLibrary(dll); end; end.
Delphi-Quellcode:
(Klappt übrigens beim Titel auch!) Oder man kann mit der Escape-Sequenz %n (s. auch PSDK -> FormatMessage @Daniel: ) einen Zeilenumbruch erzeugen:
ShellMessageBoxA(hInstance,self.Handle,
MAKEINTRESOURCE(1000), // <-- Verweis auf Stringressource nil,MB_OK,[nil]);
Delphi-Quellcode:
Aber eigentlich interessiert mich der letzte Parameter (das Pointer-Array). Wie bei "FormatMessage" soll man nämlich (ähnlich wie bei "wvsprintf" oder "Format") Strings ersetzen können. Dazu soll man eigentlich eine Sequenz wie #n nutzen, wobei das N eine Zahl von 1 bis 99 sein kann. Nur irgendwie bekomme ich keinen Fuß in die Tür (mal so gesprochen). Es wird alles angezeigt, nur nicht das was ich will:
ShellMessageBoxA(hInstance,self.Handle,
'Hallo, Echo!%nHallo, Otto! :o)', nil,0,[nil]);
Delphi-Quellcode:
Ich mache irgendwas falsch.
szString := 'Hallo, Welt!';
ShellMessageBoxA(hInstance,self.Handle, '%1',nil,0,[pointer(szString)]); Aber was? |
Zitat |
NicoDE
(Gast)
n/a Beiträge |
#2
Zitat von MathiasSimmack:
Ich mache irgendwas falsch. Aber was?
Delphi-Quellcode:
Gruss Nico
program ShMsgBox;
uses Windows, ShellAPI; type {$IFDEF UNICODE} LPCTSTR = PWideChar; {$ELSE} LPCTSTR = PAnsiChar; {$ENDIF} //////////////////////////////////////////////////////////////////////////////// // // ShellMessageBox // // ( [url]http://search.microsoft.com/?View=msdn&qu=ShellMessageBox[/url] ) // // Notes: // Maximum used ressource string length is 80 chars // ShellMessageBox adds MB_SETFOREGROUND to fuStyle // function ShellMessageBox(Inst: HINST; Wnd: HWND; Msg, Title: LPCTSTR; Style: UINT; const Arguments: array of LPCTSTR): Integer; stdcall; type TFNShellMessageBoxA = function(hInst: HINST; hWnd: HWND; pszMsg: LPCSTR; pszTitle: LPCSTR; fuStyle: UINT {...}): Integer; cdecl; TFNShellMessageBoxW = function(hInst: HINST; hWnd: HWND; pszMsg: LPCWSTR; pszTitle: LPCWSTR; fuStyle: UINT {...}): Integer; cdecl; TFNShellMessageBox = function(hInst: HINST; hWnd: HWND; pszMsg: LPCTSTR; pszTitle: LPCTSTR; fuStyle: UINT {...}): Integer; cdecl; const ShellMessageBoxProcNameA = 'ShellMessageBoxA'; ShellMessageBoxProcNameW = 'ShellMessageBoxW'; ShellMessageBoxProcOrdA = PAnsiChar(183); ShellMessageBoxProcOrdW = PAnsiChar(182); {$IFDEF UNICODE} ShellMessageBoxProcName = ShellMessageBoxProcNameW; ShellMessageBoxProcOrd = ShellMessageBoxProcOrdW; {$ELSE} ShellMessageBoxProcName = ShellMessageBoxProcNameA; ShellMessageBoxProcOrd = ShellMessageBoxProcOrdA; {$ENDIF} var ShellModule: HMODULE; FNShellMessageBox: TFNShellMessageBox; begin Result := 0; ShellModule := LoadLibrary(shell32); if (ShellModule <> 0) then try FNShellMessageBox := TFNShellMessageBox( GetProcAddress(ShellModule, ShellMessageBoxProcName)); if not Assigned(FNShellMessageBox) then FNShellMessageBox := TFNShellMessageBox( GetProcAddress(ShellModule, ShellMessageBoxProcOrd)); if Assigned(FNShellMessageBox) then begin asm push ebx // save EBX mov ecx,[Arguments-$04] // High(Arguments) mov ebx,ecx // offset to last argument shl ebx,$02 // (High * SizeOf) inc ecx // Length(Arguments) jz @@call // no arguments? mov edx,[Arguments] // first argument add edx,ebx // last argument @@loop: push dword ptr [edx] // push argument sub edx,$04 // next argument loop @@loop // until ecx = 0 @@call: push dword ptr [Style] // push params push dword ptr [Title] // ... push dword ptr [Msg] push dword ptr [Wnd] push dword ptr [Inst] call FNShellMessageBox // call function add esp,$18 // cleanup stack (params) add esp,ebx // cleanup stack (arguments) mov [Result],eax // return value into Result pop ebx // restore EBX end; end; finally FreeLibrary(ShellModule); end; end; //////////////////////////////////////////////////////////////////////////////// // Sample begin ShellMessageBox(0, 0, 'function %2(%4: %3; %6: %5; %8, %10: %7; %12: %11 {...}): %1;', 'ShellMessageBox', MB_OK or MB_DEFBUTTON1 or MB_ICONINFORMATION, ['Integer', 'ShellMessageBox', 'HINST', 'hInst', 'HWND', 'hWnd', 'LPCTSTR', 'pszMsg', 'LPCTSTR', 'pszTitle', 'UINT', 'fuStyle']); end. [edit] BASM Optimierungen [/edit] [edit] Anpassungen D2-D6 [/edit] [edit] Unicode-Anpassung [/edit] |
Zitat |
MathiasSimmack
(Gast)
n/a Beiträge |
#3
Hallo Nico.
Dankeschön kann ich da nur sagen.
Zitat von NicoDE:
Delphi-Quellcode:
////////////////////////////////////////////////////////////////////////////////
// // ShellMessageBox // // ( [url]http://search.microsoft.com/?View=msdn&qu=ShellMessageBox[/url] ) Als kleine Frage, just for the sake of completeness, , was genau passiert im Assemberteil?
Zitat:
Delphi-Quellcode:
asm
push ebx mov ecx, [Arguments-04h] // High(Arguments) mov ebx, ecx shl ebx, 02h inc ecx jz @@call mov edx, [Arguments] add edx, ebx @@loop: push dword ptr [edx] sub edx, 04h loop @@loop @@call: push dword ptr [Style] push dword ptr [Title] push dword ptr [Msg] push dword ptr [Wnd] push dword ptr [Inst] call FNShellMessageBox add esp, 18h add esp, ebx mov [Result], eax pop ebx end; Gruß. PS: Ich setze trotzdem mal den Erledigt-Haken, denn das Grundproblem ist ja gelöst. Alles, was jetzt noch an Fragen und Antworten kommt, wäre nur Bonus. |
Zitat |
NicoDE
(Gast)
n/a Beiträge |
#4
Zitat von MathiasSimmack:
Dankeschön kann ich da nur sagen.
Zitat von MathiasSimmack:
was genau passiert im Assemberteil?
Code:
[color=blue] { EBX muss gesichert werden (wird auf dem Stack abgelegt) }[/color]
[color=gray] push ebx[/color] [color=blue] { Bei 'array of' befindet sich vor dem ersten Element der Wert von High }[/color] [color=gray] mov ecx,[Arguments-$04][/color] [color=blue] { Hier wird der Offset zum letzten Element zusammengebaut (High*4) }[/color] [color=gray] mov ebx,ecx[/color] [color=gray] shl ebx,$02[/color] [color=blue] { Aus dem High(Arguments) wird nun Length(Arguments) (+1) }[/color] [color=gray] inc ecx[/color] [color=blue] { Prüfen ob es gar keine zusätzlichen Argumente gibt (ecx ist 0) }[/color] [color=blue] { Wenn dann geht es sofort zur Übergabe der benötigten Parameter }[/color] [color=gray] jz @@call[/color] [color=blue] { Erste Element holen und dann zum letzten Element wechseln }[/color] [color=blue] { cdecl erwartet die Parameter in 'umgekehrter' Reihenfolge }[/color] [color=gray] mov edx,[Arguments][/color] [color=gray] add edx,ebx[/color] [color=blue] { Aktuelles Element auf dem Stack ablegen }[/color] [color=gray]@@loop: push dword ptr [edx][/color] [color=blue] { Zum nächsten Element wechseln (rückwärts) }[/color] [color=gray] sub edx,$04[/color] [color=blue] { ECX um 1 verringern und auf 0 prüfen }[/color] [color=blue] { solange ECX <> 0 weiter mit Schleife }[/color] [color=gray] loop @@loop[/color] [color=blue] { Nun die benötigten Parameter auf dem Stack ablegen }[/color] [color=gray]@@call: push dword ptr [Style][/color] [color=gray] push dword ptr [Title][/color] [color=gray] push dword ptr [Msg][/color] [color=gray] push dword ptr [Wnd][/color] [color=gray] push dword ptr [Inst][/color] [color=blue] { Funktion aufrufen (Ergebnis ist dann in EAX) }[/color] [color=gray] call FNShellMessageBox[/color] [color=blue] { Stack mit benötigten Parametern abräumen }[/color] [color=blue] { ($14, aber ebx basiert nicht auf Length, sondern auf High) }[/color] [color=gray] add esp,$18[/color] [color=blue] { Stack mit zusätzlichen Argumenten abräumen }[/color] [color=gray] add esp,ebx[/color] [color=blue] { Ergebnis in Result speichern }[/color] [color=gray] mov [Result],eax[/color] [color=blue] { EBX wiederhergestellen (vom Stack holen) }[/color] [color=gray] pop ebx[/color]
Zitat von MathiasSimmack:
Gab´s nicht eine Lösung in ... äh ... normaler Delphi-Sprache
Delphi-Quellcode:
...wäre viel zu unsicher (da es von der Annahme ausgeht, dass der Compiler keine Anweisung zischen die asm-Bläcke und den Aufruf der Funktion packt).
asm
push ... end; ShellMessageBox(...) asm add esp,... end; Gruss Nico ps: kurz vor Deiner Antwort hab ich oben noch ne Kleinigkeit geändert [edit] elende Tippfehler, nicht mein Tag heute ... [/edit] |
Zitat |
MathiasSimmack
(Gast)
n/a Beiträge |
#5
Zitat von NicoDE:
ps: kurz vor Deiner Antwort hab ich oben noch ne Kleinigkeit geändert
Zitat:
Zuletzt bearbeitet von NicoDE am 23.03.2004, 08:47, insgesamt 22-mal bearbeitet.
@all: Ich hänge mal das Ergebnis ran. Ein kleines Programm zum Rumspielen mit noch ein paar anderen Funktionen. Inkl. Hilfedatei (undok.chm) und gepatchter "base.chm" für die CHM-Version der Win32-API-Tutorials (@Luckie: )), wodurch der Inhalt der "undok.chm" unter den Systemfunktionen erscheint. Die Erklärung für den Assemblerteil habe ich 1:1 von Nico übernommen. Das einzige, das ich dazu beigetragen habe, ist, dass man´s ein- und ausblenden kann ... Ach ja, das Programm verursacht absichtlich zwei Compilerfehler, damit ihr lest was an der Stelle im Quellcode steht. Nochmals Danke, @Nico. Grüße. |
Zitat |
NicoDE
(Gast)
n/a Beiträge |
#6
Zitat von MathiasSimmack:
Na ja.
Edit 23 erweiterte es - dank Deines Hinweises - um Kommentare im BASM-Code... (habe unbewußt versucht einen neuen Tippfehler/Edit-Record aufzugestellen *g*) |
Zitat |
MathiasSimmack
(Gast)
n/a Beiträge |
#7
Auf Einwand bzw. Hinweis von Nico wollte ich noch was zum Anhang sagen:
Das Beispielprogramm ist ein Beispiel wie man lieber nicht programmieren sollte. Das liegt an dem Mischmasch von Ansi- und Unicode. Die einzige Sache, die richtig funktioniert, ist Nicos "ShellMessageBox". Aber das liegt daran, dass diese Funktion sowohl als Ansi- als auch als Unicode-Version exportiert wird. Beim "Anderes Symbol"-Dialog (PickIconDlg) sieht das schon anders aus. Den Dialog gibt es auch unter 9x, dort allerdings undokumentiert und nur als Ansi-Version. Den PSDK-Deklarationen zufolge benutzt der Dialog ab und unter Windows 2000 aber Widestrings (also Unicode, salopp gesagt). Wenn ich unter XP die AnsiChar-Version nutze, dann erhalte ich die Fehlermeldung, weil der Dateiname nicht erkannt wird (s. Bild im Anhang). Das gleiche mit umgekehrten Vorzeichen passiert unter 98, wenn ich dort die Unicode-Version ausprobiere. Wer die Funktionen also tatsächlich in einem Programm verwenden will, der sollte den Weg gehen, den Nico vorgemacht hat, bzw. der sollte beide Varianten laden und OS-abhängig nutzen. Betrachtet die Demo von mir bitte daher als das was sie ist: als Programm, das unter bestimmten Bedingungen funktioniert aber keinesfalls als produktives Beispiel dienen sollte. Nico wird´s mir sicher nicht übelnehmen, wenn ich aus seiner PM zitiere:
Zitat:
Es ist für den Standard-User eher besser, den UNICODE-Schalter zu vermeiden, da er sonst die ANSI-RTL mit seinem Unicode-Code mischt (und zudem fälschlicherweise der Meinung sein könnte, dass es noch auf Win9x läuft...).
|
Zitat |
Ansicht |
Linear-Darstellung |
Zur Hybrid-Darstellung wechseln |
Zur Baum-Darstellung wechseln |
ForumregelnEs ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.
BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus. Trackbacks are an
Pingbacks are an
Refbacks are aus
|
|
Nützliche Links |
Heutige Beiträge |
Sitemap |
Suchen |
Code-Library |
Wer ist online |
Alle Foren als gelesen markieren |
Gehe zu... |
LinkBack |
LinkBack URL |
About LinkBacks |