子类化问题,请大大们帮忙一下,分不多,表示一下心意. ( 积分: 150 )

  • 主题发起人 主题发起人 初学者1号
  • 开始时间 开始时间

初学者1号

Unregistered / Unconfirmed
GUEST, unregistred user!
为了使自己的EDIT不被别的程序取得其中内容,我从tEdit继承出一个newEdit,并且重新定义了消息函数WM_GETTEXT.这下问题来了,连edit1.text:=newEdit1.text执行的时候,都会被拦截。请问大大,如何分辨出是本程序发送的消息还是外部程序发送的消息?
 
为了使自己的EDIT不被别的程序取得其中内容,我从tEdit继承出一个newEdit,并且重新定义了消息函数WM_GETTEXT.这下问题来了,连edit1.text:=newEdit1.text执行的时候,都会被拦截。请问大大,如何分辨出是本程序发送的消息还是外部程序发送的消息?
 
你需要重载newEdit1.text这个属性,如何处理看你自己了,比如你可以把发送WM_NEWGETTEXT消息(自定义),然后在WNDPROC中如果监测到WM_NEWGETTEXT,那么result:= inherited(..., WM_GETTEXT,..);
 
你要先继承父类的消息!inherited();
 
to zjan521:<br>您的意思是不是自定义一个消息,需要取文本框内容的时候,就发这个消息?如果是这样,同样会使用到WM_GETTEXT消息。还有,inherited这个的用法如您所说?<br>to zhengyong7381:<br>如果继承了父类的消息,那么,相当于执行了子类自定义的消息以及父类的默认过程。<br>问题的关键是如何区别其他进程与本程的消息。我的困境是,现在连本身进程都无法取文本框内容了。
 
好心人帮帮忙。。。。
 
如zjan521所说,重载Text属性,设定一个内部标志,然后inherited Text,完了清此标志,在WM_GETTEXT中,判断这个标志,如果没有置这个标志,那么应该就不是本程序的调用,给它返回一个随机字符串[:D][:D]
 
收到gettext消息时,让祖先窗口函数处理,把结果保存在私有变量里面然后破坏掉返回值,再重载text属性:先发送wm_gettext消息,然后读取私有变量作为返回结果.
 
type<br> &nbsp;myEdit=class(tEdit)<br> &nbsp; &nbsp;private<br> &nbsp; &nbsp; &nbsp;canGet:boolean; <br> &nbsp; &nbsp;public<br> &nbsp; &nbsp; &nbsp;procedure mGetText(var msg:tMessage);message:WM_GETTEXT;<br> &nbsp; &nbsp; &nbsp;begin<br> &nbsp; &nbsp; &nbsp; &nbsp;if canGet then inherited; <br> &nbsp; &nbsp; &nbsp;end; &nbsp; <br> &nbsp; &nbsp;end;<br>var<br> &nbsp;edit:myEdit;<br>在执行tempStr:=edit.text 前,先edit.canGet:=true;执行完后是edit.canGet:=false;<br>这样就能限制别的程序使用WM_GETTEXT来读文本了。这样行吗?<br>如果有有的方法请提出来,一切为了研究技术。
 
其实我很想知道QQ怎么弄的,用Spy根本找不出句柄,如果做到那样,其实也是一种方式<br><br>不过没测试过<br><br><br>unit Main;<br><br>interface<br><br>uses<br> &nbsp; &nbsp;Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,<br> &nbsp; &nbsp;Dialogs, StdCtrls;<br><br>type<br> &nbsp; &nbsp;TMyEdit = class(tEdit)<br> &nbsp; &nbsp;private<br> &nbsp; &nbsp; &nbsp; &nbsp;FcanGet: boolean;<br> &nbsp; &nbsp;public<br> &nbsp; &nbsp; &nbsp; &nbsp;procedure DefaultHandler(var Message); override;<br> &nbsp; &nbsp; &nbsp; &nbsp;property canGet: boolean read FcanGet write FcanGet;<br> &nbsp; &nbsp; &nbsp; &nbsp;constructor Create(AOwner: TComponent); override;<br> &nbsp; &nbsp; &nbsp; &nbsp;destructor Destroy; override;<br> &nbsp; &nbsp;end;<br><br><br> &nbsp; &nbsp;TForm1 = class(TForm)<br> &nbsp; &nbsp; &nbsp; &nbsp;Button1: TButton;<br> &nbsp; &nbsp; &nbsp; &nbsp;procedure Button1Click(Sender: TObject);<br> &nbsp; &nbsp; &nbsp; &nbsp;procedure FormCreate(Sender: TObject);<br> &nbsp; &nbsp;private<br> &nbsp; &nbsp; &nbsp; &nbsp;{ Private declarations }<br> &nbsp; &nbsp;public<br> &nbsp; &nbsp; &nbsp; &nbsp;{ Public declarations }<br> &nbsp; &nbsp;end;<br><br>var<br> &nbsp; &nbsp;Form1: TForm1;<br><br>implementation<br><br>{$R *.dfm}<br><br>procedure TForm1.Button1Click(Sender: TObject);<br>var<br> &nbsp; &nbsp;H: THandle;<br> &nbsp; &nbsp;textmaxlength: integer;<br> &nbsp; &nbsp;textcontent: array[0..100] of char;<br>begin<br> &nbsp; &nbsp;H := FindWindowEx(self.Handle, 0, PChar('TMyEdit'), 0);<br> &nbsp; &nbsp;if H &gt; 0 then begin<br> &nbsp; &nbsp; &nbsp; &nbsp;SendMessage(H, WM_GETTEXT, textmaxlength, lparam(@textcontent));<br> &nbsp; &nbsp; &nbsp; &nbsp;Caption := textcontent;<br> &nbsp; &nbsp;end;<br>end;<br><br>{ TmyEdit }<br><br>constructor TMyEdit.Create(AOwner: TComponent);<br>begin<br> &nbsp; &nbsp;inherited Create(AOwner);<br> &nbsp; &nbsp;FcanGet := False;<br>end;<br><br>procedure TMyEdit.DefaultHandler(var Message);<br>var<br> &nbsp; &nbsp;P: PChar;<br>begin<br> &nbsp; &nbsp;with TMessage(Message) do<br> &nbsp; &nbsp; &nbsp; &nbsp;case Msg of<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;WM_GETTEXT: begin<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if FcanGet then begin<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if PChar(Text) &lt;&gt; nil then<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;P := PChar(Text)<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;else<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;P := '';<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Result := StrLen(StrLCopy(PChar(lparam), P, WParam - 1));<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;end<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;else<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Result := StrLen(StrLCopy(PChar(lparam), PChar(''), WParam - 1)); ;<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;end;<br> &nbsp; &nbsp; &nbsp; &nbsp;else<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;inherited;<br> &nbsp; &nbsp; &nbsp; &nbsp;end;<br>end;<br><br>destructor TMyEdit.Destroy;<br>begin<br><br> &nbsp; &nbsp;inherited;<br>end;<br><br>procedure TForm1.FormCreate(Sender: TObject);<br>begin<br> &nbsp; &nbsp;with TMyEdit.Create(nil) do begin<br> &nbsp; &nbsp; &nbsp; &nbsp;Parent := self;<br> &nbsp; &nbsp; &nbsp; &nbsp;Left := 0;<br> &nbsp; &nbsp; &nbsp; &nbsp;Top := 0;<br> &nbsp; &nbsp; &nbsp; &nbsp;Width := 100;<br> &nbsp; &nbsp; &nbsp; &nbsp;Height := 25;<br> &nbsp; &nbsp; &nbsp; &nbsp;Text := 'asdf';<br> &nbsp; &nbsp; &nbsp; &nbsp;show;<br> &nbsp; &nbsp;end;<br>end;<br><br>end.<br><br><br>好像没有到WM_GetText,帮看看哪里写错了,H句柄已经获得了,但是跟踪不到TMyEdit的那个消息循环里面去
 
//来自:chenybin, 时间:2005-9-6 21:17:31, ID:3194192<br>//其实我很想知道QQ怎么弄的,用Spy根本找不出句柄,如果做到那样,其实也是一种方式<br>找不到句柄有很多种方式.<br>1.本身就没有句柄,比如JAVA的程序,全部都是它内部调度.自己也可以模拟实现,不外乎DrawBorder/DrawText/SetCaretPos/KeyMessage这些,并不复杂,仅仅是麻烦.而且RichEdit支持一种无句柄模式,不过没有具体接触过。<br>2.可能是直接用SPY++得不到,可是如果你查看父窗体的子窗体,可能是存在的,这个具体原因不是很清楚,这两天一个WindowsMCE05中的舞者的更新程序发现是这样的,似乎跟Z_ORDER有关。<br><br>unit EditEx;<br><br>interface<br><br>uses<br> SysUtils, Classes, Controls, StdCtrls, Messages;<br><br>const WM_GETTEXT_EX = WM_USER + $1001;<br><br>type<br> TEditEx = class(TEdit)<br> &nbsp;private<br> &nbsp; &nbsp;function GetText: String;<br> procedure SetText(const Value: String);<br> protected<br> procedure WndProc(var Mesg: TMessage); override;<br> function GetTextBuf(Buffer: PChar; BufSize: Integer): Integer;<br> published<br> property Text : String read GetText write SetText;<br> end;<br><br>procedure Register;<br><br>implementation<br><br>procedure Register;<br>begin<br> RegisterComponents('ZJAn521', [TEditEx]);<br>end;<br><br>{ TEditEx }<br><br>function TEditEx.GetText: String;<br>var<br> Len: Integer;<br>begin<br> Len := GetTextLen;<br> SetString(Result, PChar(nil), Len);<br> if Len &lt;&gt; 0 then GetTextBuf(Pointer(Result), Len + 1);<br>end;<br><br>function TEditEx.GetTextBuf(Buffer: PChar; BufSize: Integer): Integer;<br>begin<br> Result := Perform(WM_GETTEXT_EX, BufSize, Longint(Buffer));<br>end;<br><br>procedure TEditEx.SetText(const Value: String);<br>begin<br> Inherited Text:= Value;<br>end;<br><br>procedure TEditEx.WndProc(var Mesg: TMessage);<br>begin<br> case Mesg.Msg of<br> WM_GETTEXT:<br> Mesg.Result:= 0;<br> WM_GETTEXT_EX:<br> begin<br> Mesg.Msg:= WM_GETTEXT;<br> Inherited;<br> end;<br> else<br> Inherited;<br> end;<br>end;<br><br>end.
 
这不叫子类化吧。(subclassing)<br>用spyxx还是可以看到自定义的消息吧。
 
to 江南草:<br>请问如何才能称得上子类化,诚心请教!
 
没弄过,转一篇文章,是VC的<br><br>http://www.ddvip.net/program/masm/index1/20.htm<br><br>窗口子类化 <br>作者:unknown 更新时间: 2005-03-13 &nbsp; &nbsp; <br> &nbsp;<br>  在这一讲,我们将学习什么是窗口子类化和怎样按你所想要的方式方便地使用它。<br><br>理论:<br><br>如果你曾经在 Windows 环境下编过程序,有时候就会发现:有一个现成的窗口,几乎有你所需要的全部功能,但还不完全一样(否则就没有必要讲这一节了)。你曾遇到过这样的处境吗,如果你需要一个具有过滤特殊字符功能的 Edit 控件。当然最直接的方法就是自己用代码来实现,但这的确是一个费时又很困难的任务,而窗口子类化就可以用来做这种事情。 <br><br>窗口子类化允许你接管被子类化的窗口,使你对它有绝对的控制权。举个例子了来阐明一下:例如你需要一个只接受十六进制数字输入的文本编辑框,如果使用一个简单的 Edit控件,当用户输入十六进制以外的字符时,你既不知道也无计可施。也就是说,当用户进文本框中输入字符串 &quot;zb+q*&quot; 时,如果除了拒绝接受整个字符串以外几乎什么也不能做,至少这显得特别不专业。重要的是,你需要具有输入检测的能力,即每当用户输入一个字符到编辑框中时要能检测这个字符。<br><br>现在来解释实现细节:当用户往文本框中输入字符时,Windows 会给Edit控件的窗口函数发送 WM_CHAR 消息。这个窗口函数本身寄生于 Windows 中,因此不能直接修改它。但是我们可以重定向这个消息使之发送到我们自己编写的窗口处理函数。如果自定义窗口要处理这个消息那就可以处理它,如果不处理就可以把这个消息转发到它原来窗口处理函数。通过这种方式,自定义的窗口处理函数就把它自己插入到 Windows 系统和 Edit 控件之间。<br><br>看下面的流程: <br>窗口子类化之前 <br>Windows ==&gt;Edit 控件的窗口处理函数。 <br><br>子类化之后 <br>Windows ==&gt;自定义的窗口处理函数==&gt; Edit 控件的窗口处理函数。 <br><br>注意子类化并不局限于控件,可以子类化任何窗口,现在我们要把精力集中到怎样实现子类化一个窗口上。让我们想想Windows 怎样知道 Edit 控件的窗口处理函数放在什么地方。猜的?…肯定不是。原来 WNDCLASSEX 结构的成员 lpfnWndProc 指出了窗口函数地址。如果能用自己编写的窗口函数的地址来替换这个成员变量,那 Windows 不就把消息发到自定义的窗口函数了吗! 我们通过调用函数SetWindowLong 来实现这个任务,此函数的原型为: <br><br>SetWindowLong PROTO hWnd:DWORD, nIndex:DWORD, dwNewLong:DWORD<br><br>hWnd = 将要实施子类化的窗口的句柄 <br>nIndex = 函数了功能索引 <br>GWL_EXSTYLE 设置窗口的扩展风格. <br>GWL_STYLE 设置新的窗口风格<br>GWL_WNDPROC 设置新的窗口处理函数地址<br>GWL_HINSTANCE 设置新的应用程序句柄<br>GWL_ID 设置新的窗口标识<br>GWL_USERDATA 设置一个与这个窗口相关的给用户使用的32位的数据 <br>dwNewLong = 用来更新的数据 <br>我们的工作还是比较简单的: <br><br>写一个窗口函数用于处理发给 Edit 控件的消息。 <br>用参数GWL_WNDPROC调用SetWindowLong 函数,如果调用成功那么返回值就是与调用功能相联系的一个32位的整数 <br>在我们的程序中,返回值就是原先窗口函数的地址。我们要保存这个值以便以后使用。 记住:有一些我们不处理的消息,需要把它们派遣给原来的窗口函数来处理,这就用到另外一个函数 CallWindowProc, 函数原型为:<br><br>CallWindowProc PROTO lpPrevWndFunc:DWORD, hWnd:DWORD, Msg:DWORD, wParam:DWORD, lParam:DWORD <br><br>lpPrevWndFunc = 窗口原来函数的地址. 剩下的四个参数就是发给自定义函数的参数,直接把它们传给函数 CallWindowProc 就行了。<br><br>代码举例: <br><br><br>.386 <br>.model flat,stdcall <br>option casemap:none <br>include /masm32/include/windows.inc <br>include /masm32/include/user32.inc <br>include /masm32/include/kernel32.inc <br>include /masm32/include/comctl32.inc <br>includelib /masm32/lib/comctl32.lib <br>includelib /masm32/lib/user32.lib <br>includelib /masm32/lib/kernel32.lib <br>WinMain PROTO :DWORD,:DWORD,:DWORD,:DWORD <br>EditWndProc PROTO :DWORD,:DWORD,:DWORD,:DWORD <br><br>.data <br>ClassName db &quot;SubclassWinClass&quot;,0 <br>AppName db &quot;Subclassing Demo&quot;,0 <br>EditClass db &quot;EDIT&quot;,0 <br>Message db &quot;You pressed Enter in the text box!&quot;,0 <br><br>.data? <br>hInstance HINSTANCE ? <br>hwndEdit dd ? <br>OldWndProc dd ? <br><br>.code <br>start: <br>invoke GetModuleHandle, NULL <br>mov hInstance,eax <br>invoke WinMain, hInstance,NULL,NULL, SW_SHOWDEFAULT <br>invoke ExitProcess,eax <br><br>WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD <br>LOCAL wc:WNDCLASSEX <br>LOCAL msg:MSG <br>LOCAL hwnd:HWND <br>mov wc.cbSize,SIZEOF WNDCLASSEX <br>mov wc.style, CS_HREDRAW or CS_VREDRAW <br>mov wc.lpfnWndProc, OFFSET WndProc <br>mov wc.cbClsExtra,NULL <br>mov wc.cbWndExtra,NULL <br>push hInst <br>pop wc.hInstance <br>mov wc.hbrBackground,COLOR_APPWORKSPACE <br>mov wc.lpszMenuName,NULL <br>mov wc.lpszClassName,OFFSET ClassName <br>invoke LoadIcon,NULL,IDI_APPLICATION <br>mov wc.hIcon,eax <br>mov wc.hIconSm,eax <br>invoke LoadCursor,NULL,IDC_ARROW <br>mov wc.hCursor,eax <br>invoke RegisterClassEx, addr wc <br>invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR ClassName,ADDR AppName,/ <br>WS_OVERLAPPED+WS_CAPTION+WS_SYSMENU+WS_MINIMIZEBOX+WS_MAXIMIZEBOX+WS_VISIBLE,CW_USEDEFAULT,/ <br>CW_USEDEFAULT,350,200,NULL,NULL,/ <br>hInst,NULL <br>mov hwnd,eax <br>.while TRUE <br>invoke GetMessage, ADDR msg,NULL,0,0 <br>.BREAK .IF (!eax) <br>invoke TranslateMessage, ADDR msg <br>invoke DispatchMessage, ADDR msg <br>.endw <br>mov eax,msg.wParam <br>ret <br>WinMain endp <br><br>WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM <br>.if uMsg==WM_CREATE <br>invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR EditClass,NULL,/ <br>WS_CHILD+WS_VISIBLE+WS_BORDER,20,/ <br>20,300,25,hWnd,NULL,/ <br>hInstance,NULL <br>mov hwndEdit,eax <br>invoke SetFocus,eax <br>;----------------------------------------- <br>; Subclass it! <br>;----------------------------------------- <br>invoke SetWindowLong,hwndEdit,GWL_WNDPROC,addr EditWndProc <br>mov OldWndProc,eax <br>.elseif uMsg==WM_DESTROY <br>invoke PostQuitMessage,NULL <br>.else <br>invoke DefWindowProc,hWnd,uMsg,wParam,lParam <br>ret <br>.endif <br>xor eax,eax <br>ret <br>WndProc endp <br><br>EditWndProc PROC hEdit:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD <br>.if uMsg==WM_CHAR <br>mov eax,wParam <br>.if (al&gt;=&quot;0&quot; &amp;&amp; al&lt;=&quot;9&quot;) || (al&gt;=&quot;A&quot; &amp;&amp; al&lt;=&quot;F&quot;) || (al&gt;=&quot;a&quot; &amp;&amp; al&lt;=&quot;f&quot;) || al==VK_BACK <br>.if al&gt;=&quot;a&quot; &amp;&amp; al&lt;=&quot;f&quot; <br>sub al,20h <br>.endif <br>invoke CallWindowProc,OldWndProc,hEdit,uMsg,eax,lParam <br>ret <br>.endif <br>.elseif uMsg==WM_KEYDOWN <br>mov eax,wParam <br>.if al==VK_RETURN <br>invoke MessageBox,hEdit,addr Message,addr AppName,MB_OK+MB_ICONINFORMATION <br>invoke SetFocus,hEdit <br>.else <br>invoke CallWindowProc,OldWndProc,hEdit,uMsg,wParam,lParam <br>ret <br>.endif <br>.else <br>invoke CallWindowProc,OldWndProc,hEdit,uMsg,wParam,lParam <br>ret <br>.endif <br>xor eax,eax <br>ret <br>EditWndProc endp <br>end start <br><br>分析:<br><br>invoke SetWindowLong,hwndEdit,GWL_WNDPROC,addr EditWndProc<br>mov OldWndProc,eax <br><br>在创建 Edit 控件后,通过调用 SetWindowLong 把原来的窗口函数地址替换为自定义函数的地址,从而对它实施了窗口子类化,要注意 为了调用函数 CallWindowProc,我们存储了原窗口函数地址,自已编写的EditWndProc 仅仅是个普普通通的窗口函数。当然也可以再调用一次 SetWindowLong 函数来存储这个32位的值,<br><br>invoke SetWindowLong ,hwndEdit,GWL_USERDATA,eax 。<br><br>当然用的时候就要调用GetWindowLong 来取回这个值。 <br><br><br>.if uMsg==WM_CHAR <br>mov eax,wParam <br>.if (al&gt;=&quot;0&quot; &amp;&amp; al&lt;=&quot;9&quot;) || (al&gt;=&quot;A&quot; &amp;&amp; al&lt;=&quot;F&quot;) || (al&gt;=&quot;a&quot; &amp;&amp; al&lt;=&quot;f&quot;) || al==VK_BACK <br>.if al&gt;=&quot;a&quot; &amp;&amp; al&lt;=&quot;f&quot; <br>sub al,20h <br>.endif <br>invoke CallWindowProc,OldWndProc,hEdit,uMsg,eax,lParam <br>ret <br>.endif <br><br>在函数 EditWndProc 中,我们自己处理了WM_CHAR消息: 如果输入的字符是'0'--'9'、'A'-'F'或者是'a'--'f'就接受,并且把此消息转发给原窗口函数,其中若输入的是小写的'a'--'f'就把它变为大写。如果输入的不是十六进制字符,就丢掉它,并且也不转发此消息。因此当输入是非十六进制字符时,这个字符就不会显示在 Edit 控件中。 <br><br>.elseif uMsg==WM_KEYDOWN <br>mov eax,wParam <br>.if al==VK_RETURN <br>invoke MessageBox,hEdit,addr Message,addr AppName,MB_OK+MB_ICONINFORMATION <br>invoke SetFocus,hEdit <br>.else <br>invoke CallWindowProc,OldWndProc,hEdit,uMsg,wParam,lParam <br>ret <br>.end <br><br>在这里我们通过处理 回车(Enter) 键进一步示范了子类化的能力。EditWndProc 通过检查 WM_KEYDONW 消息来判断是否是 回车键,若是显示提示消息框,否则转发此消息。 你可以用窗口子类化来控制另外的窗口,这是必须掌握的十分有用的技术之一。
 
to chenybin大大:<br>您的方法感觉就像是重载了一个wndProc过程。我试着做了一下,感觉还不是一般的郁闷。特别是在取函数入口地址的时候。同样的用@MainWndProc取地址,如果在form中,就不能使用;但在project中,就能使用。汗啊
 
接受答案了.
 
后退
顶部