首先,很抱歉我给你的回答不正确
所以,我在再次收到您的问题后立即测试了您的代码。
我必须为这个问题创建自己的课程。
我们看一下GetModuleFileName
的原型
DWORD WINAPI GetModuleFileName(
_In_opt_ HMODULE hModule,
_Out_ LPTSTR lpFilename,
_In_ DWORD nSize
);
您的原型是为 GetModuleFileNameEx 而不是 GetModuleFileName。 link
我错过的要点是 lpFilename 参数必须是可变对象。
它可以是任何可变对象,例如作为参数的字符数组或字节数组。
我认为我们不能使用 String 类作为参数,因为它是一个不可变类。
我认为 GetModuleFileName 比 msdn site 中的 GetModuleFileNameEx 更推荐。
你可以在他们说的文章中间找到,
要检索当前进程中的模块名称,请使用
GetModuleFileName 函数。这样更高效、更可靠
而不是使用当前进程的句柄调用 GetModuleFileNameEx
这里有两个条件。
首先,我的操作系统是 Windows 7 Ultimate 64-bit
其次,你我有不同的开发环境。
我从原site下载了最新的jna.jar和jna-platform.jar。
我已经测试了四种不同的方法..其中一种失败了。
我的入口点如下
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: 查找函数时出错
'GetModuleFileName' java.lang.UnsatisfiedLinkError:查找错误
函数'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 >>==> native@0x34d0000
allocPoint ==> native@0x34d0000
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);
}
希望对你有帮助
附言
最后,我对这个问题有了自己的答案......
可以用 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
然后,我调用了这个方法。