2012-04-10 7 views
1

Ich verwende JNA, um Methoden von user32.dll und kernel32.dll aufzurufen. Es funktioniert jetzt gut. Ich bin in einem Problem steckengeblieben, und ich habe erfahren, dass ich diese Methode nennen muss.Was wird der Java-Äquivalenzcode für den folgenden Code sein?

void SendCommandToConsole(char* Cmd) 
{ 
    DWORD dwCall = 0x004C1030; 
    __asm 
    { 
     push Cmd; 
     push 0; 
     call dwCall; 
    } 
} 

SendCommandToConsole ("rp 2000"); 

Aber ich bekomme es nicht einmal, was es ist? Was macht dieses __asm?

Bitte passende Tags hinzufügen, wenn die von mir verwendeten Tags nicht korrekt sind. :)

Bearbeiten Hinzugefügt .Net und C# -Tags wie vorgeschlagen. Obiger Code ist in C# oder .NET, vielleicht kann jemand mit dem Wissen dieser Sprache uns sagen, was er eigentlich ist und wie wir das in Java machen können.

+2

_asm ist Inline-Assembly-Code. Es drückt einen Zeiger auf das C-Äquivalent eines Strings auf dem Stapel, beendet es mit 0 und ruft dann die Prozedur an der dwCall-Adresse auf (denke ich). –

+3

und dies sieht wie das Äquivalent von 'System.out.println' aus. – Thilo

+0

@HovercraftFullOfEels Danke, können wir ähnlichen Code in Java schreiben? –

Antwort

5

Nur um zu zeigen, was unter der Haube passiert:

Ihr Anruf:

SendCommandToConsole ("rp 2000");

Ruft die Funktion (SendCommandToConsole) mit einem Parameter vom Typ (char * Cmd) auf.

Im obigen Fall entspricht (char * Cmd) der Zeichenkette (sic) von "rp 2000".

Nun, was unter den Abdeckungen passiert, ist, dass höhere Sprachen (Java in Ihrem Beispiel) den untergeordneten Sprachen mitteilen müssen, wie sie ihre Anweisungen in einer Sprache interpretieren, die sie verstehen.

So das Beispiel zu nehmen oberhalb von (SendCommandToConsole ‚mit dem String-Parameter von‚rp 2000‘" Ich habe die Funktion aufgerufen werden soll‘) bedeutet, dass wir auf der unteren Ebene Sprache kommunizieren müssen:

  • Die "uppity-ups wollen, dass wir einen Befehl auszuführen." "Oh ja, welche?"
  • "Sie sagen mir, 'SendCommandToConsole'"
  • „Oh, das Alter? Er wohnt hier unter der Adresse '0x004C1030'. "
  • " Oh, kennst du die Adresse des Kerls? Können Sie dieses Paket liefern, die die uppity-ups geliefert wollen ? „
  • ‚Klar doch, aber er nimmt nur Pakete in einer bestimmten Reihenfolge und nur eines bestimmten Typs.‘
  • “ Kein Problem, ich habe ihr Manifest hier ... mal sehen, ob es den Anforderungen des Kerls entspricht.„

“ First off, der Typ an dieser Adresse will nur zwei Dinge wissen, und sie haben, um sein:

  • Was wollen Sie mir tun,
  • und die melde ich die Ergebnisse zu“

‚Ok, das ist einfach‘

ich behaupten werde, was ich will ihn tun:

  • „Cmd“
  • Jetzt werde ich behaupten, die ich ihm die Ergebnisse zu melden: „Niemand (0)“

In Ordnung, ich werde ihn anrufen .. Sie können jetzt mit Ihrem Tag fortfahren.

(weil es eine „Lücke“ Rückkehr ist, was bedeutet, dass Sie nicht über das Ergebnis der Transaktion ist es egal)

2

Dies bedeutet, dass ein Assembly-Codeblock folgt.

dwCall ist der Zeiger auf eine Assembly-Prozedur, die ein Argument -> einen Zeiger auf ein Null abgeschlossenes Array von Bytes auf dem Stapel nimmt. Um es richtig aufzurufen, müssen Sie den Zeiger auf den Stack drücken und das können Sie nur über Assembler tun.

+0

Es werden zwei Argumente ausgegeben. – technomage

0

Warum rufen Sie nicht einfach die SendCommandToConsole() Funktion an? Diese Funktion macht einen Windows-Systemaufruf, und Sie sollten keine Funktion schreiben, die das tut. Sie sollten eine Funktion aufrufen, die das tut.

+0

tatsächlich gibt es keine Methode wie 'sendCommandToConsole', es ist genau so, wie es eine Methode bei gegebener Adresse gibt, und dann diese Methode aufzurufen, heißt sie arbitrary. Ich denke, das ist .Net oder C# -Code. –

+0

@RakeshJuyal, vielleicht sollten Sie bei einer C# oder .NET oder Windows-Tag auf die Frage, wie sobald Sie herausfinden, wie diese Funktion von normalen Windows-Programmen aufgerufen wird, sollten Sie in der Lage sein, JNA zu bekommen, um es sehr einfach zuzuordnen. Sie sind auf ein zu niedriges Niveau gestoßen und benötigen eine höhere Funktion, um portablen Zugriff darauf zu ermöglichen. –

+0

danke, ich habe C# und .NET-Tag hinzugefügt. –

0

Ich denke, die Frage ist, was „rp 2000“ zu tun hat? Wenn es rp.exe mit dem Argument 2000 ausführt, können Sie java.lang.Runtime verwenden, um dasselbe zu tun. Wenn wir wüssten, was es getan hat, könnte es etwas in Java geben, um es zu tun.

+0

Nein, anstelle von 'rp 2000' können Sie sogar' julian abc' sagen. Die wirkliche Frage ist, wie man eine in der Adresse '0x004C1030' in einer gegebenen ausführbaren Datei gespeicherte Methode aufruft. –

+0

Dann sollten Sie vielleicht Ihre ursprüngliche Frage neu formulieren, um "die eigentliche Frage" zu stellen. :) – technomage

1

Es gibt kein Java-Äquivalent, Java erlaubt keine Low-Level-Kontrolle. Sie müssen den C-Code als DLL kompilieren und mit JNA/JNI aufrufen.

Edit 1: Das obige gilt nur für Assembly-Code im Allgemeinen. Siehe die Antwort von techomage zum Aufruf einer stdcall- oder cdecl-Funktion an einer Adresse mit JNA.

Der __asm-Block ermöglicht die Verwendung von Assembly in einer C-Quelldatei. Der Assembly-Code ruft die Funktion unter der Adresse 0x004C1030 (welche Funktion auch immer sein mag) auf und übergibt den String als Zeiger und eine Null als Argumente.

Adressen direkt anzurufen ist keine gute Idee. Sie werden wahrscheinlich nicht bekommen, was Sie erwarten, es sei denn, Sie kennen die Low-Level-Interna Ihres Programms und Ihres Betriebssystems wirklich gut. Wenn Sie es aufrufen, wird Ihr Programm höchstwahrscheinlich zum Absturz gebracht.

+0

Sie konzentrieren sich auf die __asm-Anweisung selbst und nicht auf das Gesamtergebnis der vollständigen Operation. – technomage

+2

Wir wissen nicht viel über die Funktion namens. Wir könnten einfach stdcall verwenden, da es auf der Seite des Anrufers keine Aufräumarbeiten zu geben scheint, aber das hofft immer noch, dass es funktioniert, es könnte auch eine andere Konvention sein. Ich stimme zu, dass ich expliziter sein und mich auf das tatsächliche Beispiel konzentrieren sollte. Vielen Dank. – Kaito

2

In JNA können Sie Function.getFunction(Pointer) verwenden, um ein Objekt abzurufen, das Sie zum Steuern von Aufrufen für eine bestimmte Adresse verwenden können.

Function dwCall = Function.getFunction(new Pointer(0x12345678)); 
String CMD = "SomeCommand"; 
Integer ARG = new Integer(0); 
dwCall.invoke(void.class, new Object[CMD, ARG]); 

Angenommen, die Funktion verwendet die C-Aufrufkonvention, würde der obige Code funktionieren. Schließlich möchten Sie wahrscheinlich die Funktionsadresse dynamisch nachschlagen, anstatt sie hart zu codieren, und Sie würden wahrscheinlich einen JNA-Callback verwenden wollen, anstatt das Function-Objekt direkt aufzurufen, aber der obige Code bietet die nackten Funktionen, die Sie fordern for (Sie sollten Ihre ursprüngliche Frage neu formulieren; Sie möchten Assemblercode nicht ausführen, sondern eine Funktion an einer bestimmten Adresse aufrufen).

Mit einem JNA Callback Mapping können Sie die Funktion natürlicher aufrufen.

// Use StdCallCallback if the function called uses stdcall rather than cdecl 
public class MyCallback extends Callback { 
    void invoke(String cmd, int arg); 
} 

Pointer addr = new Pointer(0x1235678); 
MyCallback cb = (MyCallback)CallbackReference.getCallback(MyCallback.class, addr); 
cb.invoke("SomeCommand", 0); 

Beachten Sie, dass diese beiden Beispiele gehen davon aus, dass Sie bereits JNA verwendet haben, die DLL in Frage über Native.loadLibrary(), in der Regel zu laden.

Beachten Sie auch, dass die Signatur tatsächlich void dwCall(int arg, String cmd) sein könnte; Cdecl und Stdcall Konventionen drücken Parameter auf dem Stapel von rechts nach links, und mein Denken ist im Moment nicht klar genug, um das durch richtig zu ordnet.

+0

Dank @technomage, die vielversprechend aussieht :). Ich werde es versuchen. –

+0

Wie Kaito bemerkt, scheint die Anrufsequenz stdcall zu sein, da nach dem Anruf keine Stapelbereinigung stattfindet. Wenn es cdecl wäre, dann würden Sie sehen, dass der Stack nach dem Aufruf angepasst wurde (das Äquivalent von zwei Pops). Abhängig von dem, was der Compiler um die Ask-Anweisungen vor der Rückkehr von "SendCommandToConsole" macht, ist eine solche Bereinigung jedoch nicht unbedingt erforderlich, und der Verfasser hat gerade die Bereinigung vergessen. – technomage