Project1

标题: 请教API中函数参数类型的问题(不知道是不是这个问题= =) [打印本页]

作者: fux2    时间: 2011-1-24 13:33
标题: 请教API中函数参数类型的问题(不知道是不是这个问题= =)
本帖最后由 fux2 于 2011-1-26 12:09 编辑

原句
  1. @GetPID = Win32API.new("user32","GetWindowThreadProcessId",['L'],'L')
  2. ppid = @GetPID.call(pid)
复制代码
不知道为何这里获得的ppid和VB中获取的不同,导致后面的工程无法继续,于是请假
是因为函数类型错误么?
[line]1[/line]
另请教一下这里为什么会得到一个非定值的错误返回值?
作者: 蕾米莉亚·斯卡雷特    时间: 2011-1-24 17:14
本帖最后由 蕾米莉亚·斯卡雷特 于 2011-1-24 19:09 编辑

DWORD GetWindowThreadProcessId(
  HWND hWnd,
  LPDWORD lpdwProcessId
);

确定没有写错?

Win32API.new("user32.dll", "GetWindowThreadProcessId", "lp", "l")
[line]2[/line]

如果想获得 Ruby 运行的 PID 的话, 可以直接使用  $$ 来获取.

p $$
作者: 苏小脉    时间: 2011-1-25 02:02
本帖最后由 苏小脉 于 2011-1-25 02:02 编辑

参数类型声明写错了,你只声明了一个 'L' 参数,但实际上 GetWindowThreadProcessId 接受两个参数,一个是窗口句柄,一个是保存进程标识的指针(可为 NULL)。API 是本地函数,不存在参数默认值这样的高层概念,VB 这玩意儿可能是在 API 上面抽象了一层,实现了可选参数的机制,所以才可以只传递第一个参数。如果对本地函数也这么做,结果就是未知的。Windows API 遵循标准调用约定(stdcall),参数是从右到左压入栈中的。对于动态链接库函数调用这样的未经优化的代码,如果你只传递了一个参数给接受两个参数的函数,那在栈内存中本该是第二个参数的位置就没有被实际压入任何数据,但却保留着上一次使用这个位置的内存后遗留下来的值,所以对于函数调用者来说是不可知的,而且是可变的,这取决于整个程序帧在什么内存地址被装载。最后 GetWindowThreadProcessId 获取到的两个参数都是错误的值。

应该是:

@GetPID = Win32API.new("user32","GetWindowThreadProcessId",['L', 'p'],'L')
ppid = @GetPID.call(pid, 0)
作者: fux2    时间: 2011-1-25 10:50
回复 苏小脉 的帖子

多谢苏大人赐教,但是此方法获得的pid还是与VB有出入(本次是3700和3704)
以至于玩呗后面的hProcess = @OpenPro.call(2035711,0,pid)无法取得正确值
还求继续详解
作者: 苏小脉    时间: 2011-1-25 11:40
回复 fux2 的帖子

没明白你想做什么,GetWindowThreadProcessId 返回的是创建了指定窗口的线程的标识,不是进程标识。如果同时需要进程标识,那需要给第二个参数传递一个有效的缓冲区指针,该 API 函数检测到这个指针不是 NULL,就会把进程标识拷贝到指针指向的内存中。
作者: fux2    时间: 2011-1-25 11:42
本帖最后由 fux2 于 2011-1-26 07:04 编辑

回复 苏小脉 的帖子

啊……
调用:
  1. if findwindow("扫雷")
  2.   cheat(openpro(getpid(findwindow("扫雷"))))
  3. end
复制代码
一共有如下方法
  1.   def findwindow(name)
  2.     buf = name * 1024
  3.     Win32API.new("kernel32", "MultiByteToWideChar", ['I', 'L', 'P', 'I', 'P', 'I'], 'I').call(65001, 0, "扫雷", -1, buf, 1024)
  4.     buf.strip!
  5.     isfind = @FindWindow.call(0, buf)
  6.     isfind == 0 ? false : isfind
  7.   end
  8.   
  9.   def getpid(pid)
  10.     return nil if pid == 0
  11.     ppid = @GetPID.call(pid, 0)
  12.     return ppid
  13.   end
  14.   
  15.   def openpro(pid)
  16.     p pid
  17.     return nil if pid == nil or pid == 0
  18.     hProcess = @OpenPro.call(2035711,0,pid)
  19.     hProcess == 0 ? false : hProcess
  20.   end
  21. def cheat(hProcess)
  22.     return false if hProcess == nil
  23.     baseaddr = 16798561
  24.     @Writeaddr.call(hProcess,baseaddr,0x41,1,0)
  25.   end
复制代码

作者: 苏小脉    时间: 2011-1-25 23:24
回复 fux2 的帖子

虽然你没给出你是如何调用方法的,但从你的方法命名来推断,你大概是把 GetWindowThreadProcessId 返回的线程标识传给 OpenProcess 了?OpenProcess 需要的是进程标识,所以你应该给 GetWindowThreadProcessId 传递一个有效的缓冲区地址,这样进程标识就会被拷贝到这个缓冲区中,然后再把它传给 OpenProcess。
作者: 紫苏    时间: 2011-1-26 12:08
所以说你确实是把线程标识当作进程标识在用了嘛,正确做法:
  1.         buf = '    '
  2.     @GetPID.call(hwindow, buf)
  3.     pid = buf.unpack('I')[0]
复制代码
这个 pid 才是创建了 hwindow 所标识的窗口的进程 ID。




欢迎光临 Project1 (https://rpg.blue/) Powered by Discuz! X3.1