Subclassing Class and Module...can anyone see whats wrong???
VB Code:
'In Module:
Option Explicit
Const GWL_WNDPROC = -4
Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal ndx As Long, ByVal newValue As Long) As Long
Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Type mtypWindowInfoUDT
hWnd As Long
OldWndProc As Long
MsgHook As MsgHook
End Type
Dim mudtWindowInfo() As mtypWindowInfoUDT
Dim mlngmudtWindowInfoCount As Long
Public Sub HookWindow(ByRef pobjMsgHook As MsgHook, ByVal hWnd As Long)
If mlngmudtWindowInfoCount = 0 Then
ReDim mudtWindowInfo(10) As mtypWindowInfoUDT
ElseIf mlngmudtWindowInfoCount > UBound(mudtWindowInfo) Then
ReDim Preserve mudtWindowInfo(mlngmudtWindowInfoCount + 9) As mtypWindowInfoUDT
Event BeforeMessage(ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long, ByRef RetValue As Long, ByRef Cancel As Boolean)
Event AfterMessage(ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long)
Private mlnghWnd As Long
Public Sub StartSubclass(ByVal hWnd As Long)
If mlnghWnd Then
Call StopSubclass
End If
mlnghWnd = hWnd
If mlnghWnd Then
Call HookWindow(Me, mlnghWnd)
End If
End Sub
Public Sub StopSubclass()
If mlnghWnd Then
Call UnhookWindow(Me)
End If
End Sub
Friend Function WndProc(ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long, ByVal oldWindowProc As Long) As Long
I may be wrong, but it is very clear where your code fails.
Here in your Hook procedure, as soon your array ubound reaches 11 elements (or 10 elements if your Option Base is 1), you re-allocate more dynamic memory of 9 elements. Soon after which, you increment the counter mlngmudtWindowInfoCount only by 1 element. Immediately after that, you populate the UDT instance based on the value of mlngmudtWindowInfoCount . All of it will fall in place except in one situation. Consider when the ubound of your UDT array mudtWindowInfo reaches exactly 10. You have no construct for that, do you? You simply increment your counter and move forward, the 11th element (or the 10th one if your Option Base is 1) escapes the hook.
Code:
ElseIf mlngmudtWindowInfoCount > UBound(mudtWindowInfo) Then
ReDim Preserve mudtWindowInfo(mlngmudtWindowInfoCount + 9) As mtypWindowInfoUDT
End If
mlngmudtWindowInfoCount = mlngmudtWindowInfoCount + 1
With mudtWindowInfo(mlngmudtWindowInfoCount)
.hWnd = hWnd
Set .MsgHook = pobjMsgHook
.OldWndProc = SetWindowLong(hWnd, GWL_WNDPROC, AddressOf WndProc)
End With
End Sub
The correct code be just adding an = sign here instead of a greater than sign.
Code:
ElseIf mlngmudtWindowInfoCount = UBound(mudtWindowInfo) Then
Yea, but I am only added 1 message hook class...never added 10, I cut and pasted that part of the code...theoreticall when I get round to writeing in correctly I would use a collenot a stupid array
Originally posted by Wokawidget Yea, but I am only added 1 message hook class...never added 10, I cut and pasted that part of the code...theoreticall when I get round to writeing in correctly I would use a collenot a stupid array
In an active X EXE create a window using CreateWindowEx API...
The module and class module above are in the same activeX EXE and I subclass this new window...from another app I pass a custom message to it...If the ActiveX is running in the IDE OR when it's compiled it works...BUT
If I add the 2 things above into a seperate DLL, one that I can use for subclassing in many projects, then use this DLL in the ActiveX EXE and subclass the Newly created window then the following happens...
If The activeX EXE is running in the IDE then it works, it traps my custom message and processes it...BUT if I compile the ActiveX EXE it doesn't trap my Message and So the SendMessage command I use returns straight away with a return value of 0...
Here's the general DLL I use with the NewWindow and The MsgHook classes...
Ignore the modSubclass...this is only used for the subclassing of the SystemTray...should change this to sue the MsgHook class, but I subclass the form instead for the Systray...very old code...
I have just created a small ActiveX EXE demo to show you...
Here it is...Compile the above project and then reference it in the following attached project...
Now here's my main app, again a simplified cut down version...Reference ProxyDLL.EXE in this app...
Now run ProxyDLL.EXE in the VB IDE then run the app I have attached to tyhis post....you should see the msgbox "Woof" followed by a MsgBox 1234567
Ok, sunclassing works...
Now close the apps down...compile the ProxyDLL activeX EXE and reference the ActiveX EXE in the project attached to this post...now run it...you'll notice no msgbox "Woof" and the return from the sendmessage is 0!!!
Now, if you remove the relevant classes and modules and add them into ProxyDLL.EXE, so you're not using VBTools.DLL in this project anymore then it works!
The classes to add, from VBTools, to ProxyDLL.EXE are module modMsgHook, Class MsgHook and class NewWindow....add these to proxyDLL and remove the refereence to VBTools and compile....the app now works....so why doesn't it trap my message when it references VBTools and uses the classes in there to subclass and create new window???
I could howveer just add the required modules and classes into my project, but I didn't want this, I wanted a generic DLL will tools that I use frequently...Booooooooooooooooooooo
Come on you API gobbling guru's...I thought it was me being a prune and that someone would have looked at the code and said "Woka, you are a real moron, you forogot to do..."
Come on, prove that I am a moron and am doing something really stupid in the above demos...
So which classes need to be set to single use? I have the set to MultiUse...
Did you get the problem I have having if you didn't set this property?
Why does it do this?
OK, so I set the class I reference in my Starndard EXE project to Single use, in the demo above it's ReferenceClass...what about MsgHook and NewWindow???
Woka
Don't suppose you know why this is happening?
What's the defference between MultiUser, which I had it set to, and singleuse???
What's the defference between MultiUser, which I had it set to, and singleuse???
When you set the Instancing property of a COM object to MultiUse, which is also the default property, every client using it uses the same copy of the object. The object is only loaded once in the memory and it serves multiple client references. Multiuse is the default property setting.
SingleUse means just the opposite. Every single AddRef call creates a new object of the COM component/class. This uses more memory than the MultiUse setting.
As to what your problem in the project on subclassing was, I haven't looked at it. I downlaoded the first project you'd sent, the one with the modules modSubclass and stuff, but one of the modules was missing perhaps, that had the declaration to your CUSTOM_MESSAGE used by SendByteArray() routine, so I dropped the idea.
Besides, although I have been using subclassing for a fair amount of time now, I admit, there is still more to it. And I believe it is generally true of all the average programmers, many of us know how to subclass, some of us know to subclass elegantly, but then at the end of the day, we're still defeated.
Haven't downloaded your files, but I just hope you aren't trying to subclass windows in a foreign process. Its near impossible.
I think the single/multi use thing may be a red herring....I just instinctively set anything that uses subclassing to single use because the idea of multiple processes basically sharing the same window is too freaky for a bear of very little brain such as me.
I cannot say anything at this point without looking at any of your code as a whole. The first of your projects itself did not compile for me. And since it had a binary compatibility option, I did not deem fit to remove SendByteArray() from the interface, even after having checked you were not using it anywhere else.
What you will use as Instancing really depends on your needs. I do not have much knowledge to comment on that. May be someone else who's done enough of under-the-hood COM scum would better be able to advise you on Instancing. And without having seen your code as a whole, the ActiveX EXE, the Standard EXE, I cannot make a decisive comment. However, one truth I might tell you about subclassing is that you cannot subclass a window in another process , under no circumstances. (There are workarounds for everything though, someone will tell you, and he'd not be lying). Now, taking into account this statement, just let me flip a wild guess (not having seen your code), that every WndProc has an address, we know that, right? This address is a memory address relative to the process in which it runs (in this case, the process space of the calling thread that your DLL shares). Now, you've not created a global subclass. You actually did subclass only the window under question being passed to your StartSubclass procedure (you've posted your code above). Since this window is a local subclass, its procedure address (AddressOf WndProc) resides locally in the calling thread's process shared by the DLL containing the WndProc). This process address is relative to the process and as such does not have any meaning outside the process context. Right? From here it get's a little loose. Now tie this up with the Merrion's observation about the project working as soon as he set the Instancing to SingleUse. Do you not get some feelers? Of course, I cannot be very sure of what exactly is the problem even now unless I have your code. Even then, I might not be competent enough to comment on it. Just a thought.
I don't think any modules are missing from the 1st project...Merrion is there any missing...the CUSTOM MESSAGE was just a number...523453 I think...
U can subclass something in another process but you have to do some VERY nasty API calls and "inject" your app into the processes memory space
Just recompiling all my DLLs and EXE's to test of Merrions theory...will get back to u if it works
OK badger baiters, espescially Techyspeccy!
Here's my code...that create a client-server multiuser app using TCP IP...
OK, in SQLServer create a DB Called MBELots:
then
Code:
if exists (select * from sysobjects where id = object_id(N'[dbo].[tblRecipes]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
drop table [dbo].[tblRecipes]
GO
if exists (select * from sysobjects where id = object_id(N'[dbo].[tblStructures]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
drop table [dbo].[tblStructures]
GO
CREATE TABLE [dbo].[tblRecipes] (
[UID] [uniqueidentifier] NOT NULL ,
[StructureUID] [uniqueidentifier] NOT NULL ,
[Description] [varchar] (30) NOT NULL
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[tblStructures] (
[UID] [uniqueidentifier] NOT NULL ,
[Description] [varchar] (30) NOT NULL
) ON [PRIMARY]
Now do do some insert commands on tblStructures...