java能做游戏开发吗开发游戏外挂吗

Java外挂开发之内存修改器(类似CE) - CSDN博客
Java外挂开发之内存修改器(类似CE)
最近闲着蛋疼,无聊之中用CE耍了一哈游戏,发现挺好用的,于是就想,我自己能不能写个内存修改器呢?于是乎,这个软件就诞生了!
当然我只会Java,C++嘛,了解了解,嘿嘿,所以这个工具也是用Java写的
这个工具在写内存搜索时,简直累死了,最开始暴力搜索,效率慢的要死,经过三天的不懈努力,终于搞定这搜索功能!这也是整个工具最难的部分,至少我是这么认为的
微软的MSDN都被我翻了又翻 - - !
完整源码和项目我已上传csdn
http://download.csdn.net/detail/qq07030
下载解压后的目录结构:
第一个是源代码:用Eclipse导入即可,记得修改Build Path
第二个是打包好的Jar,如果电脑安装了Java,就可以直接运行
第三个是打包好的exe安装程序,可以在没有安装Java的电脑上运行
不多说了,先上一张效果图: (这里用植物大战僵尸做实验,4399的小游戏)
原来阳光是150,被我改成1024了
先说说这个软件的使用步骤吧,与CE用法差不多,先打开游戏进程,输入搜索的游戏值(比如这里改阳光,所以输入150),然后开始搜索,搜索完成后,种一柱植物,或者捡一个阳光,总之让阳光值发生变化,然后再点击搜索变化,地址就出来啦,最后,鼠标点击,输入修改值,点击写入内存就可以咯如果搜索变化没有,就多搜两次哦
本工具开发环境如下:
开发工具:Eclipse
开发语言:Java
开发系统:windows7
JDK版本:1.6
项目所需的第三方包:
官网下载JNA包:/java-native-access/jna&& 这个包用于调用windows系统函数库
官网下载皮肤包:http://www.jtattoo.net/ & 这个包是Swing的皮肤包,用于做界面用的
代码实现大致思路如下:
获取Debug权限-&创建系统快照-&获取进程ID-&获取进程在内存中的首地址与结束地址-&打开进程-&遍历内存-&查找数据-&修改数据
项目包目录如下:
entity 这是实体包
event 这是窗体的事件监听相应包
impl 功能的核心实现
interfaces C++ API函数接口定义
quantity C++ API函数常量描述
structure C++结构体描述
wnd 软件界面
下面开始给出关键代码:
代码一:获取Debug权限,这里可以理解为赋予软件管理员,如果不获取Debug权限,会导致有些进程可能会拒绝访问
* processHandle 需要给予的进程句柄
* privilegeValue 特权值,详情请参阅LookupPrivilegeValue接口
public ExecuteResult give(int processHandle,String privilegeValue)
ExecuteResult executeResult = new ExecuteResult();
//创建令牌句柄指針,用于保存OpenProcessToken函数返回的令牌
HANDLEByReference tokenHandle = new HANDLEByReference();
//打开进程令牌,用于查询和修改令牌
if(Advapi32_DLL.INSTANCE.OpenProcessToken(processHandle, OpenProcessToken.TOKEN_ADJUST_PRIVILEGES|OpenProcessToken.TOKEN_QUERY, tokenHandle))
//创建一个令牌特权,初始化为1,用于保存LookupPrivilegeValue函数返回的令牌特权
TOKEN_PRIVILEGES tkp = new TOKEN_PRIVILEGES(1);
//初始化令牌特LUID值
tkp.Privileges[0] = new LUID_AND_ATTRIBUTES();
tkp.Privileges[0].Luid = new LUID();
tkp.Privileges[0].Attributes = OpenProcessToken.SE_PRIVILEGE_ENABLED;
//查看系统权限的特权值,返回到tkp LUID
if(Advapi32_DLL.INSTANCE.LookupPrivilegeValue(null, privilegeValue, tkp.Privileges[0].Luid))
//告诉系统启用该令牌
Advapi32_DLL.INSTANCE.AdjustTokenPrivileges(tokenHandle.getValue(), false, tkp, tkp.size(), null, null);
//释放令牌指针
ReferenceFree.free(tokenHandle);
//获取执行结果
executeResult.setLastError(Kernel32_DLL.INSTANCE.GetLastError());
//释放句柄资源
Kernel32_DLL.INSTANCE.CloseHandle(processHandle);
return executeR
代码二:创建系统快照,获取系统进程相关信息
* 得到系统进程列表
public ExecuteResult getProcess()
ExecuteResult executeResult = new ExecuteResult();
//获取结果集
List&Process& list = new ArrayList&Process&();
//创建当前系统进程快照,返回快照句柄,具体参考com.memory.interfaces.Kernel32_DLL中的描述
int processHandle = Kernel32_DLL.INSTANCE.CreateToolhelp32Snapshot(CreateToolhelp32Snapshot.TH32CS_SNAPPROCESS, 0);
//快照結果
int lastError = Kernel32_DLL.INSTANCE.GetLastError();
if(processHandle==0 || lastError!=0)
executeResult.setLastError(lastError);
executeResult.setMessage(&获取系统进程信息失败,错误代码:&+lastError);
return executeR
//创建进程结构体,用于保存进程的相关信息,具体参考com.memory.entity.Process中的描述
PROCESSENTRY32 lppe = new PROCESSENTRY32();
//根据快照句柄遍历系统进程
while(Kernel32_DLL.INSTANCE.Process32Next(processHandle, lppe))
Process temp = new Process();
temp.setProcessName(lppe.getSzExeFileStr());
temp.setPid(lppe.th32ProcessID);
list.add(temp);
if(list.size()!=0)
executeResult.setValue(list);
lastError = Kernel32_DLL.INSTANCE.GetLastError();
executeResult.setLastError(lastError);
executeResult.setMessage(&获取系统进程信息失败,错误代码:&+lastError);
//释放句柄资源
Kernel32_DLL.INSTANCE.CloseHandle(processHandle);
return executeR
代码三: 获取进程的开始内存地址与结束内存地址,获取系统的内存地址
* 查询进程在内存中的开始地址与结束地址
public ExecuteResult queryProcessRange(int pid)
ExecuteResult executeResult = new ExecuteResult();
//创建内存范围对象
MemoryRange range = new MemoryRange();
//创建进程模版快照,查询应用程序的在内存中的基地址
int handleModule = Kernel32_DLL.INSTANCE.CreateToolhelp32Snapshot(CreateToolhelp32Snapshot.TH32CS_SNAPMODULE, pid);
//快照执行结果
int lastError = Kernel32_DLL.INSTANCE.GetLastError();
executeResult.setLastError(lastError);
//判断结果
if(lastError==5)
executeResult.setMessage(&无法打开进程,系统Debug权限获取失败,请以管理员方式重新运行程序!&);
return executeR
//如果为299,说明只有部分权限,判断该进程是否是64位进程
else if(lastError==299)
//声明INT指针,保存IsWow64Process返回的值
IntByReference Wow64Process = new IntByReference();
int handle = Kernel32_DLL.INSTANCE.OpenProcess(OpenProcess.PROCESS_ALL_ACCESS, false, pid);
if(Kernel32_DLL.INSTANCE.IsWow64Process(handle, Wow64Process))
//如果为64位进程,那么久获取系统的内存范围
if(Wow64Process.getValue()==0)
executeResult = querySystemRange();
executeResult.setMessage(&无法打开该进程,错误代码:&+lastError);
//释放内存
ReferenceFree.free(Wow64Process);
Kernel32_DLL.INSTANCE.CloseHandle(handle);
return executeR
else if(lastError!=0)
executeResult.setMessage(&无法打开该进程,OpenProcess函数返回错误码:&+lastError);
return executeR
MODULEENTRY32 lpme = new MODULEENTRY32();
if(Kernel32_DLL.INSTANCE.Module32First(handleModule, lpme))
range.setMinValue(lpme.modBaseAddr);
if(Kernel32_DLL.INSTANCE.Module32Next(handleModule, lpme))
range.setMaxValue(lpme.modBaseAddr);
//执行结果返回值
executeResult.setValue(range);
//执行结果
lastError = Kernel32_DLL.INSTANCE.GetLastError();
if(range.getMinValue() == 0 && lastError!=0)
executeResult.setLastError(lastError);
executeResult.setMessage(&Module32Next失败,错误代码:&+lastError);
//释放快照
Kernel32_DLL.INSTANCE.CloseHandle(handleModule);
return executeR
* 查询当前系统的可搜索的开始地址与结束地址
public ExecuteResult querySystemRange()
ExecuteResult executeResult = new ExecuteResult();
//创建内存范围对象
MemoryRange range = new MemoryRange();
//创建描述系统信息的结构
SYSTEM_INFO info = new SYSTEM_INFO();
//获取系统内存范围
Kernel32_DLL.INSTANCE.GetSystemInfo(info);
range.setMinValue(Pointer.nativeValue(info.lpMinimumApplicationAddress));
range.setMaxValue(Pointer.nativeValue(info.lpMaximumApplicationAddress));
executeResult.setValue(range);
//调用结果
int lastError = Kernel32_DLL.INSTANCE.GetLastError();
if(lastError!=0)
executeResult.setLastError(lastError);
executeResult.setMessage(&获取系统内存地址范围失败,错误代码:&+lastError);
return executeR
代码四:搜索内存,也是最核心的部分,个人感觉也是最难的部分,可能是之前没做个之类的软件吧,反正耗费我三天,头都要炸了
package com.memory.
import java.util.ArrayL
import java.util.C
import java.util.HashM
import java.util.L
import java.util.M
import com.memory.entity.ExecuteR
import com.memory.entity.MemoryV
import com.memory.interfaces.Kernel32_DLL;
import com.memory.quantity.OpenP
import com.memory.quantity.VirtualP
import com.memory.structure.MEMORY_BASIC_INFORMATION;
import com.sun.jna.M
import com.sun.jna.P
* 内存搜索实现类
* 作者:Code菜鸟
* 技术交流QQ:
* CSDN博客:http://blog.csdn.net/qq
public class MemorySearchImpl
//保存查询内存结果信息的结构体类
private MEMORY_BASIC_INFORMATION memoryInfo = new MEMORY_BASIC_INFORMATION();
//查询结果的大小
private int size = memoryInfo.size();
//统计内存扫描数量
public int memoryScore = 0;
//保存搜索
public List&MemoryValue& searchResult = Collections.synchronizedList(new ArrayList&MemoryValue&());
* pid 进程ID
* value 需要搜索的值
* searchDataType 搜索的实际数据类型 0=INT 1=Short 2=long 3=float 4=double 5=byte
* equalsSearchValue 与搜索值相比较 0等于,1大于,2小于
* startBaseAddr 搜索开始的内存基址
* endBaseAddr 搜索结束的内存基址
* increasing 搜索地址的递增量
public ExecuteResult search(int pid,String searchValue,int searchDataType,int equalsSearchValue,int startBaseAddr,int endBaseAddr)
if(searchResult.size()!=0) searchResult.clear();
ExecuteResult executeResult = new ExecuteResult();
memoryScore = 0;
//根据进程ID,打开进程,返回进程句柄
int handle = Kernel32_DLL.INSTANCE.OpenProcess(OpenProcess.PROCESS_ALL_ACCESS, false, pid);
//判断进程句柄是否打开成功
int lastError = Kernel32_DLL.INSTANCE.GetLastError();
executeResult.setLastError(lastError);
if(lastError==5)
executeResult.setMessage(&无法打开进程,系统Debug权限获取失败,请以管理员方式重新运行程序!&);
return executeR
else if(lastError!=0)
executeResult.setMessage(&无法打开该进程,OpenProcess函数返回错误码:&+lastError);
return executeR
//根据基址遍历内存
while(startBaseAddr &= endBaseAddr)
//读取内存信息
int vqe = Kernel32_DLL.INSTANCE.VirtualQueryEx(handle, startBaseAddr, memoryInfo, size);
if(vqe==0)
//判断内存是否已提交,非空闲内存
if (memoryInfo.state == MEMORY_BASIC_INFORMATION.MEM_COMMIT)
//更改内存保护属性为可写可读,成功返回TRUE,执行这个函数,OpenProcess函数必须为PROCESS_ALL_ACCESS
boolean vpe = Kernel32_DLL.INSTANCE.VirtualProtectEx(handle, startBaseAddr, memoryInfo.regionSize, VirtualProtect.PAGE_READWRITE, memoryInfo.protect);
//判断内存是否可读可写
if(vpe || memoryInfo.protect == MEMORY_BASIC_INFORMATION.PAGE_READWRITE)
//声明一块内存空间,保存读取内存块的值,这个空间的大小与内存块大小相同
Pointer buffer = new Memory(memoryInfo.regionSize);
//判断是否读取成功
if(Kernel32_DLL.INSTANCE.ReadProcessMemory(handle, startBaseAddr, buffer, memoryInfo.regionSize, 0))
//对比的值
double searchValueDouble = Double.parseDouble(searchValue);
//根据搜索类型查找对应数据
switch(searchDataType)
//查找整形int,4字节,所以i+=4
for(int i = 0; i & memoryInfo.regionS i+=4)
double memoryValue = buffer.getInt(i);
//统计内存数量
memoryScore++;
//与搜索值相比较释放符合条件 0等于,1大于,2小于
if((equalsSearchValue ==0 &&
memoryValue == searchValueDouble) ||
(equalsSearchValue==1 && memoryValue & searchValueDouble) ||
(equalsSearchValue==2 && memoryValue & searchValueDouble))
MemoryValue temp = new MemoryValue();
temp.setAddress(startBaseAddr + i);
temp.setAddress16(&0x&+Long.toString((startBaseAddr + i), 16).toUpperCase());
temp.setValue(memoryValue+&&);
searchResult.add(temp);
//查找短整形short,2字节,所以i+=2
for(int i = 0; i & memoryInfo.regionS i+=2)
double memoryValue = buffer.getShort(i);
//统计内存数量
memoryScore++;
//与搜索值相比较释放符合条件 0等于,1大于,2小于
if((equalsSearchValue ==0 &&
memoryValue == searchValueDouble) ||
(equalsSearchValue==1 && memoryValue & searchValueDouble) ||
(equalsSearchValue==2 && memoryValue & searchValueDouble))
MemoryValue temp = new MemoryValue();
temp.setAddress(startBaseAddr + i);
temp.setAddress16(&0x&+Long.toString((startBaseAddr + i), 16).toUpperCase());
temp.setValue(memoryValue+&&);
searchResult.add(temp);
//查找长整形Long,8字节,所以i+=8
for(int i = 0; i & memoryInfo.regionS i+=8)
double memoryValue = buffer.getLong(i);
//统计内存数量
memoryScore++;
//与搜索值相比较释放符合条件 0等于,1大于,2小于
if((equalsSearchValue ==0 &&
memoryValue == searchValueDouble) ||
(equalsSearchValue==1 && memoryValue & searchValueDouble) ||
(equalsSearchValue==2 && memoryValue & searchValueDouble))
MemoryValue temp = new MemoryValue();
temp.setAddress(startBaseAddr + i);
temp.setAddress16(&0x&+Long.toString((startBaseAddr + i), 16).toUpperCase());
temp.setValue(memoryValue+&&);
searchResult.add(temp);
//查找单精度浮点 float,4字节,所以i+=4
for(int i = 0; i & memoryInfo.regionS i+=4)
double memoryValue = buffer.getFloat(i);
//统计内存数量
memoryScore++;
//与搜索值相比较释放符合条件 0等于,1大于,2小于
if((equalsSearchValue ==0 &&
memoryValue == searchValueDouble) ||
(equalsSearchValue==1 && memoryValue & searchValueDouble) ||
(equalsSearchValue==2 && memoryValue & searchValueDouble))
MemoryValue temp = new MemoryValue();
temp.setAddress(startBaseAddr + i);
temp.setAddress16(&0x&+Long.toString((startBaseAddr + i), 16).toUpperCase());
temp.setValue(memoryValue+&&);
searchResult.add(temp);
//查找双精度浮点 double,8字节,所以i+=8
for(int i = 0; i & memoryInfo.regionS i+=8)
double memoryValue = buffer.getDouble(i);
//统计内存数量
memoryScore++;
//与搜索值相比较释放符合条件 0等于,1大于,2小于
if((equalsSearchValue ==0 &&
memoryValue == searchValueDouble) ||
(equalsSearchValue==1 && memoryValue & searchValueDouble) ||
(equalsSearchValue==2 && memoryValue & searchValueDouble))
MemoryValue temp = new MemoryValue();
temp.setAddress(startBaseAddr + i);
temp.setAddress16(&0x&+Long.toString((startBaseAddr + i), 16).toUpperCase());
temp.setValue(memoryValue+&&);
searchResult.add(temp);
//查找字节byte,1字节,所以i++
for(int i = 0; i & memoryInfo.regionS i++)
double memoryValue = buffer.getByte(i);
//统计内存数量
memoryScore++;
//与搜索值相比较释放符合条件 0等于,1大于,2小于
if((equalsSearchValue ==0 &&
memoryValue == searchValueDouble) ||
(equalsSearchValue==1 && memoryValue & searchValueDouble) ||
(equalsSearchValue==2 && memoryValue & searchValueDouble))
MemoryValue temp = new MemoryValue();
temp.setAddress(startBaseAddr + i);
temp.setAddress16(&0x&+Long.toString((startBaseAddr + i), 16).toUpperCase());
temp.setValue(memoryValue+&&);
searchResult.add(temp);
//释放内存
ReferenceFree.free(buffer);
//设置基地址偏移
startBaseAddr = (int) Pointer.nativeValue(memoryInfo.baseAddress) + memoryInfo.regionS
catch (Exception e)
e.printStackTrace();
executeResult.setLastError(-1);
executeResult.setMessage(&内存地址扫描错误!\n&+e.getMessage());
return executeR
//释放资源
Kernel32_DLL.INSTANCE.CloseHandle(handle);
return executeR
* 再次搜索实现
* pid 进程ID
* addressList 搜索的内存地址列表
* searchDataType 搜索的数据类型
public ExecuteResult search(int pid,List&MemoryValue& addressList,int searchDataType)
ExecuteResult executeResult = new ExecuteResult();
if(searchResult.size()!=0) searchResult.clear();
memoryScore = 0;
//获取进程句柄
int handle = Kernel32_DLL.INSTANCE.OpenProcess(OpenProcess.PROCESS_ALL_ACCESS, false,pid);
//保存读取的新值
Map&String,MemoryValue& tableValueMap = new HashMap&String,MemoryValue&();
//声明一块内存,保存读取值
Pointer readResult = new Memory(1024);
for(int i = 0;i&addressList.size();i++)
memoryScore++;
//将0xffff table中的值转换为int类型
int temp = Integer.parseInt(addressList.get(i).getAddress16().replace(&0x&, &&),16);
if(Kernel32_DLL.INSTANCE.ReadProcessMemory(handle, temp, readResult, 1024, 0))
MemoryValue m = new MemoryValue();
m.setAddress(temp);
m.setAddress16(&0x&+(Integer.toString(temp, 16).toUpperCase()));
//根据搜索类型读取对应数据
switch(searchDataType)
m.setValue(readResult.getInt(0)+&&);
//短整形short
m.setValue(readResult.getShort(0)+&&);
//长整形Long
m.setValue(readResult.getLong(0)+&&);
//单精度浮点 float
m.setValue(readResult.getFloat(0)+&&);
//双精度浮点 double
m.setValue(readResult.getDouble(0)+&&);
//字节byte
m.setValue(readResult.getByte(0)+&&);
tableValueMap.put(m.getAddress16(), m);
//释放内存
ReferenceFree.free(readResult);
//移除列表中没有发生变化的内存值
for(int i = 0;i&addressList.size();i++)
String key = addressList.get(i).getAddress16();
String value = addressList.get(i).getValue();
if(tableValueMap.get(key)!=null
&& Double.parseDouble(tableValueMap.get(key).getValue())==Double.parseDouble(value))
tableValueMap.remove(key);
//搜索结果
for(String key:tableValueMap.keySet())
searchResult.add(tableValueMap.get(key));
executeResult.setLastError(Kernel32_DLL.INSTANCE.GetLastError());
if(executeResult.getLastError()!=0)
executeResult.setMessage(&搜索内存发生错误!错误代码:&+executeResult.getLastError());
catch (Exception e)
e.printStackTrace();
executeResult.setLastError(-1);
executeResult.setMessage(&内存地址扫描错误!\n&+e.getMessage());
//资源释放
Kernel32_DLL.INSTANCE.CloseHandle(handle);
return executeR
代码五:内存的写实现
package com.memory.
import com.memory.entity.ExecuteR
import com.memory.interfaces.Kernel32_DLL;
import com.memory.quantity.OpenP
import com.memory.structure.MEMORY_BASIC_INFORMATION;
import com.sun.jna.M
import com.sun.jna.P
* 内存的写实现类
* 作者:Code菜鸟
* 技术交流QQ:
* CSDN博客:http://blog.csdn.net/qq
public class MemoryWrite
* 写入内存实现方法
* pid 进程ID
* lpBaseAddress 写入地址
* value 写入值
* dataType 数据类型,这个值确定value的实际数据类型
public ExecuteResult write(int pid,int lpBaseAddress,String value,int dataType)
ExecuteResult result = new ExecuteResult();
int hProcess = Kernel32_DLL.INSTANCE.OpenProcess(OpenProcess.PROCESS_ALL_ACCESS, false, pid);
//判断进程句柄是否打开成功
int lastError = Kernel32_DLL.INSTANCE.GetLastError();
result.setLastError(lastError);
if(lastError==5)
result.setMessage(&进程拒绝访问,可能是系统Debug权限获取失败,请以管理员方式重新运行程序!&);
else if(lastError!=0)
result.setMessage(&无法打开该进程,错误代码:&+lastError);
//判断内存地址是否合法幷且是否满足读写权限
MEMORY_BASIC_INFORMATION lpBuffer = new MEMORY_BASIC_INFORMATION();
Kernel32_DLL.INSTANCE.VirtualQueryEx(hProcess, lpBaseAddress, lpBuffer, lpBuffer.size());
if(!(lpBuffer.state == MEMORY_BASIC_INFORMATION.MEM_COMMIT
&& lpBuffer.protect == MEMORY_BASIC_INFORMATION.PAGE_READWRITE))
result.setLastError(-1);
result.setMessage(&内存地址不存在或者该内存无法读写!&);
//新内存地址,用于写入内存用
Pointer updatePointer =
int size = 4;
switch(dataType)
updatePointer = new Memory(size);
updatePointer.setInt(0, Integer.parseInt(value));
//短整形short
updatePointer = new Memory(size);
updatePointer.setShort(0, Short.parseShort(value));
//长整形Long
updatePointer = new Memory(size);
updatePointer.setLong(0, Long.parseLong(value));
//单精度浮点 float
updatePointer = new Memory(size);
updatePointer.setFloat(0, Float.parseFloat(value));
//双精度浮点 double
updatePointer = new Memory(size);
updatePointer.setDouble(0, Double.parseDouble(value));
//字节byte
updatePointer = new Memory(size);
updatePointer.setByte(0, Byte.parseByte(value));
//写入内存
boolean writeResult = Kernel32_DLL.INSTANCE.WriteProcessMemory(hProcess, lpBaseAddress, updatePointer, size, 0);
//是否写入成功
lastError = Kernel32_DLL.INSTANCE.GetLastError();
if((!writeResult) || lastError!=0)
result.setLastError(lastError);
result.setMessage(&内存写入发生错误,错误代码:&+lastError);
result.setLastError(0);
result.setMessage(&写入成功!&);
catch (Exception e)
result.setLastError(-1);
result.setMessage(&写入失败,请检查输入值是否正确或超出范围!\n错误代码:&+e.getMessage());
Kernel32_DLL.INSTANCE.CloseHandle(hProcess);
代码六:进程的杀死实现
package com.memory.
import com.memory.entity.ExecuteR
import com.memory.interfaces.Kernel32_DLL;
import com.memory.quantity.OpenP
import com.sun.jna.ptr.IntByR
* 进程杀死实现类
* 作者:Code菜鸟
* 技术交流QQ:
* CSDN博客:http://blog.csdn.net/qq
public class KillProcess
* 具体解释,请查看com.memory.interfaces.Kernel32_DLL接口中的描述
* pid 进程ID,这个值可以通过任务管理器查看或通过CreateToolhelp32Snapshot函数获取
public ExecuteResult kill(int pid)
ExecuteResult executeResult = new ExecuteResult();
int hProcess = Kernel32_DLL.INSTANCE.OpenProcess(OpenProcess.PROCESS_ALL_ACCESS, false, pid);
//INT指针,保存GetExitCodeProcess函数调用成功后,返回的程序退出值
IntByReference lpExitCode = new IntByReference();
//获取程序的退出代码
if(Kernel32_DLL.INSTANCE.GetExitCodeProcess(hProcess, lpExitCode))
//退出程序
Kernel32_DLL.INSTANCE.TerminateProcess(hProcess, lpExitCode.getValue());
//释放INT指针
ReferenceFree.free(lpExitCode);
Kernel32_DLL.INSTANCE.CloseHandle(hProcess);
//获取执行结果
int lastError = Kernel32_DLL.INSTANCE.GetLastError();
executeResult.setLastError(lastError);
if(lastError!=0)
executeResult.setMessage(&杀死进程时发生错误,错误代码:&+lastError);
return executeR
本文已收录于以下专栏:
相关文章推荐
能够利用JAVA来编游戏外挂,这真的是一个让人很感兴趣的话题。在讨论这个题目之前,我们首先来给不玩网络游戏的人补一下课,首先网络游戏的概念大家应该都是知道了,从虾米最早接触的文字MUD《重出江湖》,一...
前几天写了个QQ游戏练练看的外挂,不过实现原理很简单,先是从内存中读出练练看的棋盘数据,然后再用算法进行分析,得到两个可以连接的棋子坐标,再用软模拟鼠标在游戏窗口内点击两个棋子。
    如果要...
第一步:下载struts2.3.3 
/apache/struts/2.3.30/struts-2.3.30-all.zip
第二步:新建一个WEB项目...
集成开发环境
Eclipse是最有名也最广泛使用的Java集成开发环境(IDE),允许开发者结合语言支持和其他功能到任何的默认包中,而且Eclipse市场有许多定制和扩展的插件。
IntelliJ...
Eclipse 将他的工作流分成了三个部分:Workbench, Workspace, perspective。Workbench的作用就是相当于开发环境中的起点。而Worksp...
在用JDBC的过程中,我们可能会根据实际需求来编写N个查询方法(特别是新手),这样虽然简单,但是会产生大量的重复代码。且不容易维护。那么有没有办法,只编写一个方法呢?
通过分析,不难...
他的最新文章
讲师:宋宝华
讲师:何宇健
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)

我要回帖

更多关于 java能开发ios吗 的文章

 

随机推荐