2017-05-06 38 views
0

我正在將User32Ext方法添加到JNI。特別是,我擴展了原有UserExt類:在java JNA中使用什麼來代替LPTSTR?

package sirius.core; 

import com.sun.jna.Native; 
import com.sun.jna.Pointer; 
import com.sun.jna.platform.win32.Kernel32; 
import com.sun.jna.platform.win32.WinDef; 
import com.sun.jna.platform.win32.WinNT; 
import com.sun.jna.win32.W32APIOptions; 

public abstract interface Kernel32Ext 
    extends Kernel32 
{ 
    public static final Kernel32Ext INSTANCE = (Kernel32Ext)Native.loadLibrary("kernel32.dll", Kernel32Ext.class, W32APIOptions.DEFAULT_OPTIONS); 

    public abstract Pointer VirtualAllocEx(WinNT.HANDLE paramHANDLE, Pointer paramPointer, int paramInt, WinDef.DWORD paramDWORD1, WinDef.DWORD paramDWORD2); 
    public abstract boolean VirtualFreeEx(WinNT.HANDLE paramHANDLE, Pointer paramPointer, int paramInt, WinDef.DWORD paramDWORD); 
} 

我想補充的GetModuleFileNameEx功能。

我會寫這樣的:沒有定義

public abstract DWORD getModuleFileName(WinNT.HANDLE hProcess, WinNT.HMODULE hModule, WinNT.LPTSTR pathString, WinNT.DWORD pathStringLength); 

WinNT.LPTSTR。它顯然應該是一個指針(我猜是char?)。那麼,我該怎麼做呢?

+0

使用String類檢查其他人的答案http://stackoverflow.com/questions/5308655/jna-for-windows-api-function-getvolumepathnamesforvolumename – tommybee

+0

@tommybee String類不能通過refference接收值。我試過'char []'但是沒有奏效。 –

+3

調用Unicode接口和LPTSTR是wchar_t * –

回答

2

首先,我爲我的不正確的答案對不起你

所以,我便又收到你的問題後,測試你的代碼。 我必須爲這個問題做我自己的課。

讓我們來看看GetModuleFileName

DWORD WINAPI GetModuleFileName(
    _In_opt_ HMODULE hModule, 
    _Out_ LPTSTR lpFilename, 
    _In_  DWORD nSize 
); 

原型的原型是爲GetModuleFileNameEx沒有爲GetModuleFileNamelink

我錯過的主要觀點是lpFilename參數,它必須是可變對象。

它可以是任何可變對象,如char數組或字節數組作爲參數。

我認爲我們不能使用String類作爲參數,因爲它是一個不可變的類。

我覺得GetModuleFileName比msdn site中的GetModuleFileNameEx更值得推薦。

你可以在他們說的文章中找到,

To retrieve the name of a module in the current process, use the GetModuleFileName function. This is more efficient and more reliable than calling GetModuleFileNameEx with a handle to the current process

這裏有兩個條件。首先,我的操作系統是Windows 7旗艦版64位 其次,你和我有不同的開發環境。

我下載了最新的jna.jarJNA-platform.jar從原來的site

我測試了四種不同的方法..其中一個失敗了。

我的切入點是如下

public static void main(String[] args) { 
     testCopyFile(); 
       printProcesses(); 
     testAllocFree(PROCESSID); 
     testAllocFree2(PROCESSID); 
     testModuleFileName(PROCESSID); 
     testModuleFileName2(PROCESSID); 
    } 

的testCopyFile方法只是複製一些文本文件,用不同的方法來你的。

private static void testCopyFile() { 
     Function copyFunc = Function.getFunction("kernel32", "CopyFileA"); 
     Object[] params = new Object[3]; 
     params[0] = "C:\\DEV\\temp\\_info.txt"; 
     params[1] = "C:\\DEV\\temp\\_info2.txt"; 
     params[2] = false; 
     copyFunc.invoke(params); 
    } 

通過實現相同的功能,需要Function類,Object作爲參數和Function類的invoke方法。

下一步是找到測試的進程ID。

private static void printProcesses() 
    { 
     Tlhelp32.PROCESSENTRY32.ByReference processEntry = new Tlhelp32.PROCESSENTRY32.ByReference(); 

     HANDLE snapshot = Kernel32Me.INSTANCE.CreateToolhelp32Snapshot(Tlhelp32.TH32CS_SNAPPROCESS, 
       new DWORD(0)); 
     try { 
      while (Kernel32Me.INSTANCE.Process32Next(snapshot, processEntry)) { 
       System.out.println(processEntry.th32ProcessID + "\t" + Native.toString(processEntry.szExeFile)); 
      } 
     } finally { 
      Kernel32Me.INSTANCE.CloseHandle(snapshot); 
     } 
    } 

只需選擇其中一個顯示在屏幕上。 爲了方便起見,我首先測試了兩個具有常用函數VirtualAllocEx和VirtualFreeEx的方法。

我測試成功完成..

以下兩種不同的方法,和testAllocFree功能testAllocFree2導致相同的輸出。

private static void testAllocFree(final int processId) { 
     SIZE_T dwSize = new SIZE_T(1024); 

     DWORD flAllocationType = new DWORD(Kernel32Me.MEM_RESERVE | Kernel32Me.MEM_COMMIT); 
     DWORD flProtect = new DWORD(Kernel32Me.PAGE_READWRITE); 
     Pointer allocPoint = null; 
     boolean ret = false; 
     DWORD options 
      = new DWORD(
       Kernel32Me.PROCESS_VM_OPERATION | 
       Kernel32Me.PROCESS_VM_WRITE | 
       Kernel32Me.PROCESS_VM_READ | 
       Kernel32Me.PROCESS_CREATE_THREAD | 
       Kernel32Me.PROCESS_QUERY_INFORMATION); 

     DWORD procs = new DWORD(processId); 

     HANDLE hProcess = Kernel32Me.INSTANCE.OpenProcess(options, false, procs); 

     if(null == hProcess) 
     { 
      System.err.println("Can't have a handle for you..sorry"); 
      return; 
     } 

     try 
     { 
      allocPoint = Kernel32Me.INSTANCE.VirtualAllocEx(hProcess, null, dwSize, flAllocationType, flProtect); 

      if(allocPoint==null) 
      { 
       System.err.println("Can't get a memory resource for you..sorry"); 
       int c = Kernel32Me.INSTANCE.GetLastError(); 
       System.out.println("\t>>" + c); 
       //c = Native.getLastError(); 
       //System.out.println("\t" + c); 
      } 

      if (allocPoint != null) { 
       dwSize = new SIZE_T(0); 
       DWORD freeType = new DWORD(Kernel32Me.MEM_RELEASE); 
       System.err.println("allocPoint >>==> " + allocPoint.toString()); 
       ret = Kernel32Me.INSTANCE.VirtualFreeEx(hProcess, allocPoint, dwSize, freeType); 

       if(!ret) 
       { 
        int c = Kernel32Me.INSTANCE.GetLastError(); 
        System.out.println("\t" + c); 
        c = Native.getLastError(); 
        System.out.println("\t" + c); 
       } 
       else 
       { 
        System.out.println("\t Free success"); 
       } 
      } 
     } 
     finally 
     { 
      Kernel32Me.INSTANCE.CloseHandle(hProcess); 
     } 


    } 

而且,

private static void testAllocFree2(final int processId) { 
     Function allocFunc = Function.getFunction("kernel32", "VirtualAllocEx"); 
     Function freeFunc = Function.getFunction("kernel32", "VirtualFreeEx"); 
     DWORD flAllocationType = new DWORD(Kernel32Me.MEM_RESERVE | Kernel32Me.MEM_COMMIT); 
     DWORD flProtect = new DWORD(Kernel32Me.PAGE_READWRITE); 
     SIZE_T dwSize = new SIZE_T(1024); 

     DWORD freeType = new DWORD(Kernel32Me.MEM_RELEASE); 
     DWORD options 
      = new DWORD(
       Kernel32Me.PROCESS_VM_OPERATION | 
       Kernel32Me.PROCESS_VM_WRITE | 
       Kernel32Me.PROCESS_VM_READ | 
       Kernel32Me.PROCESS_CREATE_THREAD | 
       Kernel32Me.PROCESS_QUERY_INFORMATION); 

     DWORD procs = new DWORD(processId); 

     Pointer allocPoint = null; 

     HANDLE hProcess = Kernel32Me.INSTANCE.OpenProcess(options, false, procs); 

     if(null == hProcess) 
     { 
      System.err.println("Can't have a handle for you..sorry"); 
      return; 
     } 

     Object[] inArgs = new Object[5]; 
     inArgs[0] = hProcess; 
     inArgs[1] = null; 
     inArgs[2] = dwSize; 
     inArgs[3] = flAllocationType; 
     inArgs[4] = flProtect; 

     allocPoint = (Pointer) allocFunc.invoke(Pointer.class, inArgs); 

     try 
     { 
      if(allocPoint==null) 
      { 
       System.err.println("Can't get a memory resource for you..sorry"); 
       int c = Kernel32Me.INSTANCE.GetLastError(); 
       System.out.println("\t>>" + c); 
       //c = Native.getLastError(); 
       //System.out.println("\t" + c); 
      } 

      if (allocPoint != null) { 
       Object[] inArgs2 = new Object[4]; 
       inArgs2[0] = hProcess; 
       inArgs2[1] = allocPoint; 
       inArgs2[2] = new SIZE_T(0); 
       inArgs2[3] = freeType; 
       System.err.println("allocPoint ==> " + allocPoint.toString()); 
       freeFunc.invoke(inArgs2); 
      } 
     } 
     finally 
     { 
      Kernel32Me.INSTANCE.CloseHandle(hProcess); 
     } 
    } 

最後,GetModuleFileName和GetModuleFileNameA功能下面

private static void testModuleFileName(final int processId) 
    { 
     DWORD nSize = new DWORD(256); 
     char lpFilename[] = new char[256]; 
     byte bFilename[] = new byte[256]; 
     String strFileName = new String(); 
     DWORD options = new DWORD(Kernel32Me.PROCESS_VM_READ | Kernel32Me.PROCESS_QUERY_INFORMATION); 
     DWORD procs = new DWORD(processId); 

     HANDLE hProcess = Kernel32Me.INSTANCE.OpenProcess(options,false, procs); 

     if(null == hProcess) 
     { 
      System.err.println("Can't have a handle for you..sorry"); 
      return; 
     } 

     try 
     { 
      Kernel32Me.INSTANCE.GetModuleFileName(null, lpFilename, nSize); 
      System.err.println("module path is " + new String(lpFilename)); 

      Kernel32Me.INSTANCE.GetModuleFileName(null, bFilename, nSize); 
      System.err.println("module path is " + new String(bFilename)); 

      Kernel32Me.INSTANCE.GetModuleFileNameEx(hProcess, null, strFileName, nSize); 
      System.err.println("module path is " + strFileName); 

     } 
     finally 
     { 
      Kernel32Me.INSTANCE.CloseHandle(hProcess); 
     } 
    } 

我有兩個原型測試,一種是數組字節,另一個是在所使用的字符的陣列碼。

DWORD GetModuleFileName(HMODULE hModule, char[] lpFilename, DWORD nSize); 
DWORD GetModuleFileName(HMODULE hModule, byte[] lpFilename, DWORD nSize); 

第三個沒工作,我在這告訴我UnsatisfiedLinkError .. 我不知道爲什麼一開始提到的..

DWORD GetModuleFileNameEx(HANDLE hProcess, HMODULE hModule, String lpFilename, DWORD nSize); 

另一種實現也是一樣的。 。查看代碼

private static void testModuleFileName2(final int processId) 
    { 
     Function allocFunc = Function.getFunction("kernel32", "GetModuleFileName"); 

     DWORD nSize = new DWORD(256); 
     char[] lpFilename = new char[256]; 

     DWORD procs = new DWORD(processId); 
     DWORD options 
      = new DWORD(
       Kernel32Me.PROCESS_VM_READ | 
       Kernel32Me.PROCESS_QUERY_INFORMATION); 

     HANDLE hProcess = Kernel32Me.INSTANCE.OpenProcess(options, false, procs); 

     if(null == hProcess) 
     { 
      System.err.println("Can't have a handle for you..sorry"); 
      return; 
     } 

     try 
     { 
      Object[] inArgs = new Object[3]; 
      inArgs[0] = null; 
      inArgs[1] = lpFilename; 
      inArgs[2] = nSize; 
      allocFunc.invoke(inArgs); 
      System.err.println("module path is " + new String(lpFilename)); 
     } 
     finally 
     { 
      Kernel32Me.INSTANCE.CloseHandle(hProcess); 
     } 


    } 

我發現這兩種方法最終都不起作用。

Function allocFunc = Function.getFunction("kernel32", "GetModuleFileName"); 
Function allocFunc = Function.getFunction("kernel32", "GetModuleFileNameEx"); 

告訴我沒有發現程序的消息...

java.lang.UnsatisfiedLinkError: Error looking up function 'GetModuleFileName' java.lang.UnsatisfiedLinkError: Error looking up function 'GetModuleFileNameEx'

我必須把它挖出來詳細瞭解這些錯誤在不久的將來一段時間。

最後一個......這裏是一個主要的原型類

public interface Kernel32Me extends StdCallLibrary { 
     final Kernel32Me INSTANCE 
      = (Kernel32Me) Native.loadLibrary("kernel32.dll", Kernel32Me.class, W32APIOptions.DEFAULT_OPTIONS); 

     //https://msdn.microsoft.com/en-us/library/windows/desktop/aa366890(v=vs.85).aspx 
     int PROCESS_CREATE_THREAD = 0x0002; 
     int PAGE_EXECUTE_READWRITE = 0x40; 
     int PROCESS_QUERY_INFORMATION = 0x0400; 
     int PROCESS_VM_OPERATION = 0x0008; 
     int PROCESS_VM_WRITE = 0x0020; 
     int PROCESS_VM_READ = 0x0010; 
     int PAGE_READWRITE = 0x04; 
     int MEM_RESERVE = 0x00002000; 
     int MEM_COMMIT = 0x00001000; 
     int MEM_RESET = 0x00080000; 
     int MEM_DECOMMIT = 0x4000; 
     int MEM_RELEASE = 0x8000; 


     Pointer VirtualAllocEx(HANDLE hProcess, Pointer lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect); 

     boolean VirtualFreeEx(HANDLE hProcess, Pointer lpAddress, SIZE_T dwSize, DWORD dwFreeType); 

     DWORD GetModuleFileName(HMODULE hModule, char[] lpFilename, DWORD nSize); 
     DWORD GetModuleFileName(HMODULE hModule, byte[] lpFilename, DWORD nSize); 
     DWORD GetModuleFileNameEx(HANDLE hProcess, HMODULE hModule, String lpFilename, DWORD nSize); 

     HANDLE CreateToolhelp32Snapshot(DWORD dwFlags, DWORD th32ProcessID); 

     boolean Process32First(HANDLE hSnapshot, PROCESSENTRY32 lppe); 

     boolean Process32Next(HANDLE hSnapshot, PROCESSENTRY32 lppe); 

     HANDLE OpenProcess(DWORD dwDesiredAccess, boolean bInheritHandle, DWORD dwProcessId); 

     boolean CloseHandle(HANDLE hObject); 

     int GetLastError(); 
    } 

輸出可能看起來像下面

0 [System Process] 
4 System 
280 smss.exe 
444 csrss.exe 
536 wininit.exe 
544 csrss.exe 
7860 chrome.exe 
8132 chrome.exe 
7808 chrome.exe 
7516 chrome.exe 
6176 chrome.exe 
8156 chrome.exe 
7120 chrome.exe 
7476 chrome.exe 
8016 chrome.exe 
5616 devmonsrv.exe 
1644 chrome.exe 
6548 chrome.exe 
5960 chrome.exe 
5636 chrome.exe 
8260 chrome.exe 
3440 notepad.exe 
8844 chrome.exe 
9416 chrome.exe 
6744 chrome.exe 
6032 chrome.exe 
9724 javaw.exe 
    Free success 
allocPoint >>==> [email protected] 
allocPoint ==> [email protected] 
module path is C:\DEV\COMP\Java\jdk1.7\bin\javaw.exe 
module path is C.... <== The output is strange... 
Exception in thread "main" java.lang.UnsatisfiedLinkError: Error looking up function 'GetModuleFileNameEx': 

您需要使用字符數組不是字節數組避免字符編碼問題。

我的導入語句,

import com.sun.jna.Function; 
import com.sun.jna.Native; 
import com.sun.jna.Pointer; 
import com.sun.jna.platform.win32.BaseTSD.SIZE_T; 
import com.sun.jna.platform.win32.Tlhelp32; 
import com.sun.jna.platform.win32.Tlhelp32.PROCESSENTRY32; 
import com.sun.jna.platform.win32.WinDef.DWORD; 
import com.sun.jna.platform.win32.WinDef.HMODULE; 
import com.sun.jna.platform.win32.WinNT.HANDLE; 
import com.sun.jna.win32.StdCallLibrary; 
import com.sun.jna.win32.W32APIOptions; 

可以依次使用下面的方法。

printProcesses(); testModuleFileName(PROCESSID);

private static final int PROCESSID = 3440; // the process id from printProcesses(); 
    public static void main(String[] args) { 
      printProcesses(); 
      testModuleFileName(PROCESSID); 
     } 

我希望這可以幫助

你P.S

最後,我有我自己的這個問題的答案... 它可以用PSAPI界面來完成... 這是我最後的測試方法...

private static void testModuleFileName2(final int processId) { 
    DWORD nSize = new DWORD(260); 
    char lpFilename[] = new char[260]; 
    byte bFilename[] = new byte[260]; 

    DWORD options = new DWORD(Kernel32Me.PROCESS_VM_READ | Kernel32Me.PROCESS_QUERY_INFORMATION); 
    DWORD procs = new DWORD(processId); 

    HANDLE hProcess = Kernel32Me.INSTANCE.OpenProcess(options, false, procs); 

    if (null == hProcess) { 
     System.err.println("Can't have a handle for you..sorry"); 
     return; 
    } 

    HMODULE handle = Kernel32.INSTANCE.GetModuleHandle("kernel32.dll"); 

    if (null == handle) { 
     System.err.println("Can't have a handle for you..sorry"); 
     return; 
    } 

    try { 
     Kernel32Me.INSTANCE.GetModuleFileName(handle, lpFilename, nSize); 
     System.err.println("2> module path is " + new String(lpFilename)); 

     Psapi.INSTANCE.GetModuleFileNameExA(hProcess, handle, bFilename, 260); 
     System.err.println("2> module path is " + new String(bFilename)); 

     Psapi.INSTANCE.GetModuleFileNameExW(hProcess, null, lpFilename, 260); 
     System.err.println("2> module path is " + new String(lpFilename)); 

    } finally { 
     Kernel32Me.INSTANCE.CloseHandle(hProcess); 
    } 
} 

我打開的notepad.exe,並得到了它的進程ID

然後,我調用此方法。

+1

那麼,簡短的答案是, char []'可以使用,但是感謝所有這些。由於所有這些使用winapi的例子,我相信這將在未來幫助我! –

相關問題