DELPHI盒子
!实时搜索: 盒子论坛 | 注册用户 | 修改信息 | 退出
检举帖 | 全文检索 | 关闭广告 | 捐赠
技术论坛
 用户名
 密  码
自动登陆(30天有效)
忘了密码
≡技术区≡
DELPHI技术
lazarus/fpc/Free Pascal
移动应用开发
Web应用开发
数据库专区
报表专区
网络通讯
开源项目
论坛精华贴
≡发布区≡
发布代码
发布控件
文档资料
经典工具
≡事务区≡
网站意见
盒子之家
招聘应聘
信息交换
论坛信息
最新加入: monica9612
今日帖子: 0
在线用户: 3
导航: 论坛 -> DELPHI技术 斑竹:liumazi,sephil  
作者:
男 tx001 (tx) ▲▲△△△ -
普通会员
2019/8/22 10:12:27
标题:
美化调用的dll中ShowMessage弹出的消息窗体 浏览:1875
加入我的收藏
楼主: 调用第三方delphi写的dll,dll中的消息是用ShowMessage弹出的,和程序的风格不匹配,想美化ShowMessage弹出窗体,或者能获取到ShowMessage的消息也行
----------------------------------------------
-
作者:
男 bahamut8348 (leonna) ★☆☆☆☆ -
普通会员
2019/8/22 10:29:15
1楼: 抓消息可以反编译找找字符串,或者hook掉showmessage函数。
再或者用findwindow等函数查找对话框窗口句柄,再用setwindowlongptr替换窗口函数,然后你就可以为所欲为了。
----------------------------------------------
--
作者:
男 wang_80919 (Flying Wang) ★☆☆☆☆ -
普通会员
2019/8/22 11:17:27
2楼: ShowMessage 和 MessageBox 是两个概念。
ShowMessage 是 DELPHI FORM 做的。
改起来很难。
达成条件
1 你 IDE 必须和 DLL 的编译环境一样,控件一样。控件版本或源码一样。
2 你的美化代码,必须获取到 这个 Message Form 对象。
然后 你才能修改。
不过 VCL 是有 皮肤接口的。
很多 VCL 皮肤控件,都是 利用 皮肤接口美化控件的。
最简单的是 VCLSKIN 最复杂的是 AlphaControls
----------------------------------------------
(C)(P)Flying Wang
作者:
男 tx001 (tx) ▲▲△△△ -
普通会员
2019/8/22 13:56:37
3楼: @bahamut8348 能详细说一下如何抓消息吗?想法是用findwindow函数找到ShowMessage弹出的窗口句柄,将他关闭,再根据消息弹自己的窗口
----------------------------------------------
-
作者:
男 bahamut8348 (leonna) ★☆☆☆☆ -
普通会员
2019/8/22 16:10:14
4楼: 看看findwindow的参数。然后自己用spy照一下你要折腾的窗口就行。
----------------------------------------------
--
作者:
男 tx001 (tx) ▲▲△△△ -
普通会员
2019/8/22 17:49:49
5楼: 用findwindow能取到窗体句柄,但用WM_GETTEXT只能取到标题,取不到内容
----------------------------------------------
-
作者:
男 iamdream (银河恒久远,梦想无止境!) ★☆☆☆☆ -
大贡献会员
2019/8/23 9:23:33
6楼: ShowMessage/MessageDlg在不同Windows/Delphi环境中可能会采用不同的方法,有用TMessageForm实现的,也有调用Windows API创建的,此时窗口类名为#32770,并且新的windows会采用DirectUIHWND来画窗口,此时用FindWindow是找不到显示Message的组件的,必须用OleAcc单元中的接口函数来访问。
不知道楼主想怎样美化,如果只是取Message内容,倒是有办法,可以用我写的一些方法:
uses
  ..., Forms, Dialogs, OleAcc, ...;

function MyGetClassName(Handle: THandle): string;
var
  buf: array[0..255] of Char;
begin
  if GetClassName(Handle, buf, SizeOf(buf)) > 0 then begin
    Result := buf;
  end else begin
    Result := '';
  end;
end;

function MyGetWindowText(hWnd: THandle): string;
var
  len: Integer;
begin
  Result := '';
  len := SendMessage(hWnd, WM_GETTEXTLENGTH, 0, 0);
  if len > 0 then begin
    SetLength(Result, len +1);
    len := SendMessage(hWnd, WM_GETTEXT, len +1, Integer(PChar(Result)));
    if len > 0 then begin
      SetLength(Result, len);
    end else begin
      Result := '';
    end;
  end;
end;

function FindFormByClass(const AClassName: string): TForm;
var
  i: Integer;
begin
  Result := nil;
  for i := 0 to Application.ComponentCount -1 do begin
    if Application.Components[i].ClassNameIs(AClassName) then begin
      Result := TForm(Application.Components[i]);
      Exit;
    end;
  end;
end;

function GetRoleTextW(dwRole: DWORD; lpszRole: PWideChar;
  cchRoleMax: UINT): UINT; stdcall; external 'OLEACC.DLL';

function MyGetRoleText(Acc: IAccessible; varChild: OleVariant): string;
var
  varRole : OleVariant;
  Len: Integer;
begin
  Result := '';
  if Acc.get_accRole(varChild, varRole) = S_OK then begin
    if TVariantArg(varRole).vt = VT_I4 then begin
      Len := GetRoleTextW(TVariantArg(varRole).lVal, nil, 0);
      SetLength(Result, Len);
      GetRoleTextW(TVariantArg(varRole).lVal, PWideChar(Result), Len + 1);
    end;
  end;
end;

function GetDialogMsgText(Handle: THandle): string;
var
  clsName: string;
  frmMsg: TForm;
  lblMsg: TLabel;
  h: THandle;
  i: Integer;
  childCount: Integer;
  acc:     IAccessible;
  oChild:  IDispatch;
  s: WideString;
begin
  Result := '';
  if Handle = 0 then Exit;

  clsName := MyGetClassName(Handle);
  if SameText('TMessageForm', clsName) then begin
    frmMsg := FindFormByClass('TMessageForm');
    if Assigned(frmMsg) then begin
      lblMsg := frmMsg.FindComponent('Message') as TLabel;
      if Assigned(lblMsg) then begin
        Result := lblMsg.Caption;
      end;
    end;
  end else if SameText('#32770', clsName) then begin
    h := FindWindowEx(Handle, 0, 'DirectUIHWND', nil);
    if h <> 0 then begin
      /// DirectUI
      if AccessibleObjectFromWindow(h, OBJID_CLIENT, IID_IAccessible, acc) = S_OK then begin
        if S_OK = acc.Get_accChildCount(childCount) then begin
          for i := 1 to childCount do begin
          if (S_OK = acc.Get_accChild(i, oChild)) and
          SameText('text', MyGetRoleText(oChild as IAccessible, 0)) then begin
          s := '';
          if (S_OK = IAccessible(oChild).Get_accName(0, s)) and (s <> '') then begin
          Result := s;
          Break;
          end;
          end;
          end;
        end;
      end;
    end else begin
      /// Tradiontal dialog
      h := 0;
      repeat
        h := FindWindowEx(Handle, h, 'Static', nil);
        if h <> 0 then begin
          Result := MyGetWindowText(h);
        end;
      until (h = 0) or (Result <> '');
    end;
  end;
end;
----------------------------------------------
-广袤璀璨的银河,永无止境的梦想(梦无止境游银河) 博客挂了……
作者:
男 earthsbest (全能中间件) ▲▲▲▲△ -
普通会员
2019/8/23 12:08:54
7楼: D10.3调用D7的DLL,vclstyle除了标题栏,其他有效。
此帖子包含附件:
PNG 图像
大小:70.1K
----------------------------------------------
Delphi4Linux Delphi三层/FireDAC 技术群:734515869 http://www.cnblogs.com/rtcmw
作者:
男 earthsbest (全能中间件) ▲▲▲▲△ -
普通会员
2019/8/23 13:44:33
8楼: 如果DLL也是D10,showmessage 正常了。
此帖子包含附件:
PNG 图像
大小:17.2K
----------------------------------------------
Delphi4Linux Delphi三层/FireDAC 技术群:734515869 http://www.cnblogs.com/rtcmw
作者:
男 tx001 (tx) ▲▲△△△ -
普通会员
2019/8/23 14:13:17
9楼: @iamdream谢谢帮助,但按照你提供的方法,只能获取程序自己弹出的ShowMessage的内容,无法获取其他dll中ShowMessage的内容,其他的dll是delphi6的,我自己的程序也是用delphi6的
@earthsbest谢谢帮助,最初想法是把ShowMessage弹出窗体标题加上公司名,增加背景图片,程序中没有使用皮肤,都是用图片美化的
----------------------------------------------
-
作者:
男 iamdream (银河恒久远,梦想无止境!) ★☆☆☆☆ -
大贡献会员
2019/8/23 15:36:59
10楼: Delphi6应该用的是TMessageForm实现的,我的代码没试过DLL,的确是只能在程序内部使用。如果你只改标题,那应该可以用WM_GETTEXT/WM_SETTEXT消息来实现,往DLL中窗体里加图片没弄过,不知道能不能实现,毕竟TMessageForm传统上是用一个Label来显示消息文字的。
----------------------------------------------
-广袤璀璨的银河,永无止境的梦想(梦无止境游银河) 博客挂了……
作者:
男 wang_80919 (Flying Wang) ★☆☆☆☆ -
普通会员
2019/8/23 15:42:50
11楼: FindFormByClass
写的明明白白,只是本 exe 的 Application。
DLL 的没被列入。
----------------------------------------------
(C)(P)Flying Wang
作者:
男 bahamut8348 (leonna) ★☆☆☆☆ -
普通会员
2019/8/23 19:12:06
12楼: 我的意思是说替换窗口函数,并不是用getwindowtext。
无论什么方式,只要是windows平台上的ui,总是有一个消息循环的。
直接处理这个消息循环就可以拦截原有窗口的所有处理过程。
----------------------------------------------
--
作者:
男 tx001 (tx) ▲▲△△△ -
普通会员
2019/8/24 10:58:03
13楼: 谢谢各位帮助,用了非常麻烦的方式实现了,
在调用dll中的函数时,启动hooh api检测DrawText,如果获取到内容,用FindWindow找弹窗,找到弹窗后发送SendMessage将弹窗关闭,再调用程序中通用的弹窗,将内容显示
bahamut8348说的方法不会用,用setwindowlongptr替换哪个函数?我试了替换消息函数,想抓取WM_PAINT消息中的内容,再调用程序中已有的弹窗显示内容,但窗体已经显示了才能用FindWindow找到句柄,不再触发WM_PAINT消息,没有抓到消息
SetWindowLong(WH, GWL_WNDPROC, LongInt(MakeObjectInstance(GridProc)));
procedure TForm1.GridProc(var Meg: Tmessage);
begin
  if Meg.Msg = WM_PAINT then
  begin
    Memo1.Lines.Add('没有抓到消息');
  end;
end;
----------------------------------------------
-
作者:
男 bahamut8348 (leonna) ★☆☆☆☆ -
普通会员
2019/8/25 12:33:06
14楼: ..

过程拦截了,它自己不触发,你不会强制刷新么??按此在新窗口浏览图片
----------------------------------------------
--
作者:
男 stacker (OOP才是王道) ★☆☆☆☆ -
普通会员
2019/8/26 9:14:03
15楼: 如果你是用AlphaControl的元件的话,记得他有个单元叫sDialogs,然后所有sShowMessage,sMessageDlg...都经过加工了,应该就是如楼主的意思。
----------------------------------------------
-
作者:
男 tx001 (tx) ▲▲△△△ -
普通会员
2019/8/26 13:36:42
16楼: bahamut8348谢谢,没有想到,在调用RedrawWindow()就可以抓到了
----------------------------------------------
-
信息
登陆以后才能回复
Copyright © 2CCC.Com 盒子论坛 v3.0.1 版权所有 页面执行125毫秒 RSS