一个子类化Pointer转换类型的问题

yuanxy 2012-01-31 01:48:51
子类化初始工作代码

FHookWndProc := MakeObjectInstance(HookWndProc);
OldWndProc := Pointer(GetWindowLong(ParentWindow, GWL_WNDPROC));
SetWindowLong(ParentWindow, GWL_WNDPROC, Longint(FHookWndProc));


OldWndProc的变量类型是Pointer

我想把OldWndProc转换类型为String保存成文本文件,用下面的代码可以转换成文本,貌似是函数的地址。

ShowMessage(Format('%p', [OldWndProc]));


我的问题是如何把它再转换成Pointer类型并且可以在窗口函数中使用

with Msg do
begin
Result := CallWindowProc(OldWndProc, ParentWindow, Msg, WParam, LParam);
end;

CallWindowProc函数里面的OldWndProc是通过String类型转换成Pointer类型。

谢谢大家,祝春节快乐。



...全文
158 24 打赏 收藏 转发到动态 举报
写回复
用AI写文章
24 条回复
切换为时间正序
请发表友善的回复…
发表回复
yuanxy 2012-01-31
  • 打赏
  • 举报
回复
高手收一下站内消息,我发小窗给你了。
funxu 2012-01-31
  • 打赏
  • 举报
回复
没怎么研究过ocx,我印象里ocx和dll类似,如果加载机制相同的话,应该在进程里只加载一次,多个线程调用只会将一个地址映射到调用函数中
yuanxy 2012-01-31
  • 打赏
  • 举报
回复
新问题来了,多是多次子类化ie窗口函数,但是只有一个ocx能捕获消息,其它的ocx没有消息响应了,郁闷。
funxu1 2012-01-31
  • 打赏
  • 举报
回复
刚才说错了,不是多个ie而是多个标签,当快速打开多个标签时,可能会出错,另外你是用窗口句柄做文件名的,句柄这东西同一时刻是唯一的,但是算上关闭的窗口就不一定了,所以要有销毁机制
funxu 2012-01-31
  • 打赏
  • 举报
回复
用内存映射吧,映射文件名使用进程句柄做唯一标识应该可以保证多个ie不会冲突
funxu 2012-01-31
  • 打赏
  • 举报
回复
刚看了下,你这个代码当打开多个ie时会出问题
funxu 2012-01-31
  • 打赏
  • 举报
回复
文件不好的地方就是读写操作会冲突,而且你无法判定里面写的地址是否是正确的,比如当多次关闭打开ie时,如何保证文件里写的地址是正确的,所以我才建议使用内存映射或者全局原子,这样至少可以保证数据不会冲突,8过解决了就好
yuanxy 2012-01-31
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 funxu 的回复:]

可以用内存映射保存地址,另外记得有个全局原子可以保存整形数据,不过不怎么用忘记了,百度一下吧,还有何时释放掉全局原子或者内存映射也很重要
[/Quote]

我貌似搞定了,我用txt文件保存ie原始窗口函数,只有第一次创建文本文件,以后的加载直接读文本文件,把里面的地址转换就行了,就是有一点不好,还要维护这个文本文件。

fn := 'c:\' + IntToStr(ParentWindow) + '.txt';
AssignFile(F, fn);

if (FileExists(fn)) then
begin
Reset(F);
Readln(F, cc);
ShowMessage(cc);
OldWndProc := Pointer(StrToInt('$'+ cc));
end else
begin
OldWndProc := Pointer(GetWindowLong(ParentWindow, GWL_WNDPROC));
Rewrite(F);
Writeln(F, Format('%p', [OldWndProc]));
end;
CloseFile(F);
funxu 2012-01-31
  • 打赏
  • 举报
回复
可以用内存映射保存地址,另外记得有个全局原子可以保存整形数据,不过不怎么用忘记了,百度一下吧,还有何时释放掉全局原子或者内存映射也很重要
yuanxy 2012-01-31
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 funxu 的回复:]

另外dll里是有进程和线程的访问处理的
DLL_PROCESS_ATTACH:
DLL_PROCESS_DETACH:
DLL_THREAD_ATTACH:
DLL_THREAD_DETACH:
[/Quote]

不是dll,是ocx。
yuanxy 2012-01-31
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 funxu 的回复:]

试试看用句柄区分,这东西玩得不多,只能靠你自己了,战斗吧骚年~
[/Quote]

高手别啊,其实只要在第一次运行ocx的时候把OleWndProc保存住,以后再子类化的时候就用保存的函数地址就行。我现在卡在这里了,不知道如何把这个oldwndproc持久化。
funxu 2012-01-31
  • 打赏
  • 举报
回复
另外dll里是有进程和线程的访问处理的
DLL_PROCESS_ATTACH:
DLL_PROCESS_DETACH:
DLL_THREAD_ATTACH:
DLL_THREAD_DETACH:
yuanxy 2012-01-31
  • 打赏
  • 举报
回复
通俗一点讲,假如一个网页已经加载了ocx
现在我又加载一次ocx,下面的代码OldWndProc保存的地址其实是第一次加载ocx的消息处理函数地址
FHookWndProc := MakeObjectInstance(HookWndProc);
OldWndProc := Pointer(GetWindowLong(ParentWindow, GWL_WNDPROC));
SetWindowLong(ParentWindow, GWL_WNDPROC, Longint(FHookWndProc));
如果把第一次加载的ocx网页关闭了
那么第二次加载的ocx在恢复窗口地址的时候就会出错,原因他要恢复的地址已经被ie回收了
SetWindowLong(ParentWindow, GWL_WNDPROC, Longint(OldWndProc));
这里的OleWndProc地址其实是第一个ocx的消息处理函数。
funxu 2012-01-31
  • 打赏
  • 举报
回复
试试看用句柄区分,这东西玩得不多,只能靠你自己了,战斗吧骚年~
yuanxy 2012-01-31
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 funxu 的回复:]

新旧函数必须在同一个线程内
[/Quote]

ie是多标签浏览器,每个标签类名是frame tab,所以的标签都是ie的子窗体。我是把这个地址值保存到一个文件中,如果需要多次加载ocx我就读取这个文件把ie的函数地址复原,以后关闭整个ie窗口的时候,可以复原所有正确的ie窗口地址。

比如说我有10个标签页都载入这个ocx,直接关闭ie肯定出错。我不太清楚关闭整个ie标签页回收资源的顺序。但可以肯定的是,这10个页面我按照后进先出的顺序,一个个关闭程序是完成正常的。如果先把第一个ocx关了,那么关闭其它任意9个页面当中的一个都会直接报错。
yuanxy 2012-01-31
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 funxu 的回复:]

如果你指的是主程序不关闭,指针指向的地址没有释放的话,你可以参看钩子的实现
http://wenku.baidu.com/view/8cd214717fd5360cba1adb71.html
这句是替换原始函数指针gwl_wndproc为你自己的函数newwndproc
oldwndproc=point(setwindowlong(application.handle,gwl_wndpro……
[/Quote]

谢谢高手回复,ie窗口是可以关闭的,只是会报错。这个原因这是清楚的。
具体流程我给你说一下:
1)首先ocx第一次运行取得的ie消息函数地址是正确的,直接关闭ie是没有问题的。复原的地址也是ie的
2)如果再打开一个新的ie标签,再载入相同的ocx这时候取的消息函数就不是ie的了,而是第一次ocx的消息处理函数,这样就会有一个问题,如果关闭第一个ocx网页,再关闭第二个的话,ie报错。这是因为关闭第一个网页的时候消息函数地址也被ie收回了,第二个网页复原的时候地址不存在。错非先关闭第二个ocx,再关闭第一个是正常的。
funxu 2012-01-31
  • 打赏
  • 举报
回复
新旧函数必须在同一个线程内
yuanxy 2012-01-31
  • 打赏
  • 举报
回复
OldWndProc := Pointer(cc); //cc是ie窗口函数的地址,我转换成功了但是程序报错了,这个问题真是头疼啊。
funxu 2012-01-31
  • 打赏
  • 举报
回复
如果你指的是主程序不关闭,指针指向的地址没有释放的话,你可以参看钩子的实现
http://wenku.baidu.com/view/8cd214717fd5360cba1adb71.html
这句是替换原始函数指针gwl_wndproc为你自己的函数newwndproc
oldwndproc=point(setwindowlong(application.handle,gwl_wndproc,intger(newwndproc)));
这句就是还原函数指针gwl_wndproc
setwindowlong(application.handle,gwl_wndproc,intger(oldwndproc));
yuanxy 2012-01-31
  • 打赏
  • 举报
回复
我想持久化这个窗体函数是因为多次调用ocx就会多次子类化ie窗口函数,导致复原IE的窗口函数出错,所以我在第一次运行ocx的时候就把IE的窗口函数保存在某个地方,留着以后复原用。
加载更多回复(4)

5,388

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 开发及应用
社区管理员
  • VCL组件开发及应用社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧