首先,我爲我的不正確的答案對不起你
所以,我便又收到你的問題後,測試你的代碼。 我必須爲這個問題做我自己的課。
讓我們來看看GetModuleFileName
DWORD WINAPI GetModuleFileName(
_In_opt_ HMODULE hModule,
_Out_ LPTSTR lpFilename,
_In_ DWORD nSize
);
原型的原型是爲GetModuleFileNameEx沒有爲GetModuleFileName。 link
我錯過的主要觀點是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.jar和JNA-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
然後,我調用此方法。
使用String類檢查其他人的答案http://stackoverflow.com/questions/5308655/jna-for-windows-api-function-getvolumepathnamesforvolumename – tommybee
@tommybee String類不能通過refference接收值。我試過'char []'但是沒有奏效。 –
調用Unicode接口和LPTSTR是wchar_t * –