Results 1 to 11 of 11

Thread: @LaVolpe: your Thunker

  1. #1

    Thread Starter
    Lively Member
    Join Date
    Sep 2009
    Posts
    95

    @LaVolpe: your Thunker

    Hello LaVolpe!

    I wanted to move the WndProc to the 'cSubclass' class from Paul Catons subclassing example.
    I was trying this by implementing the interface in that class. - But it did not work:
    The callback did not receive any message! - I don't understand, why it is working for other classes,
    but not for the 'cSubclass' class itself. Do you know why this happens?

    Anyway, this question is not so important, because I found your awesome improvment of this project:
    http://www.xtremevbtalk.com/showthread.php?t=285517
    => One single class for everything. No TypeLib, no interface, no standard module needed!
    How are you achieving this exactly? - I just saw, that you are working with ordinals.

    PS: I did work with the linked project from 2004. - Now I found the project from 2007:
    http://www.planetsourcecode.com/vb/s...68737&lngWId=1
    Did you change something later on?


    But I also have some questions to it:

    * I read, that the API SetWindowSubclass should be used for more stable subclassing.
    http://www.classicvb.net/samples/HookXP/
    Can you tell me please, how your projects is performing compared to SetWindowSubclass?

    * In an article from Paul Caton and Steve McMahon I read, that it is not possible to subclass a form twice.
    (e.g. subclassing the parent form out of a UserControl, where two controls are placed on that form)
    http://www.vbaccelerator.com/home/vb...ks/article.asp
    (please see paragraph "The World Is Never Enough")

    But they also wrote that this is "currently". And since your template seems to be based on a later release,
    I like to ask, if this would be possible without any problem?

    PS: As solution this article suggests following:
    "There are two possible ways to stop this happening: use ComCt32.DLL v6.0 subclassing (fixes all problems; the
    downside is it requires new ASM code and only works on XP) or attempt to use the Windows Properties database again."


    Do they mean with ComCtl32.DLL v6.0 Subclassing, the subclassing technique, which I mentioned in the first point?
    (which after all is possible under earler versions of Windows than XP, acording to that first point)

    What is meant with that Windows Properties database?

    * A next thing which I noticed is, that you (and Paul Caton) are using the API IsBadCodePtr on several places.
    But according this the MSDN database this API is obsolete - it is not working correctly in preemptive multitasking
    environments:

    "Important! This function is obsolete and should not be used. Despite its name, it does not guarantee that the
    pointer is valid or that the memory pointed to is safe to use. For more information, see Remarks on this page."

    http://msdn.microsoft.com/en-us/library/aa366712.aspx

    Can this be a problem in your projects at any point?

    * Your template features a TimerProc, while your example not - but it has an EnumFontFamProc instead.
    Has this any reason? - I am asking, because I did add all of them to my code.

    * I also added two more security features:

    1.) In case of window destroying, the window messages are not handled anymore. - This you avoid, that code like
    Text1.Text = Message causes an exception, due to the fact, that Text1 got unloaded already.
    Because checking for WM_DESTROY did not help (this message comes to late), I did use hex 90 (=144), which
    came always short before WM_DESTROY. - But I did not find any documentation for this message number.
    Do you know, for what it is for?

    2.) I had the problem, that I did start the subclassing under Form_Initialize and had the Code Me.Caption = Message
    in the window procedure. This caused a heavy endless loop, which did prevent me from starting the task manager.
    I had to switch the user to be able to terminate the VBE.
    That is why I added some simple code to prevent this problem. Are you interested in it?

    Thank you in advance!

  2. #2
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: @LaVolpe: your Thunker

    Too many questions all at once.

    If you experiment with the most recent version of the thunker I put out there on PSC, you should ask questions about that version only.

    1. Windows database, use of SetProp/GetProp. It's a way of storing something like a Collection on a window. One can use a global array, collection or something else instead.

    2. Thunks kinda work like this: memory is created and executable code is written to that memory location. Subclassing is routed to that thunk. The thunk checks if the IDE code is on a breakpoint/stopped/paused. If so, it skips VB for that message else it passes the message to VB. This is the reason why thunks are a bit safer to use while project is uncompiled. Thunks have no advantage I can think of in a compiled application. Multithreading may be an exception, but I have little experience there

    3. Problem with multiple usercontrols subclassing same parent or window is that the usercontrols are not guaranteed to be unloaded in any order whatsoever. Generally, a usercontrol will unsubclass a window, if not done earlier, when the usercontrol's terminate event occurs. So if the unsubclassing is not in exact opposite order the parent was subclassed in, the calls to SetWindowLong API will pass an invalid window procedure address to be used for messages & crash! I solved that issue in the latest thunk by creating a timer delay. The timer simply delays unloading of the thunk until any messages in the thunk's subclassing queue are processed. A counter is used to track how many messages come into the thunk and how many messages leave the thunk. Before destroying itself, that thunk's counter must be zero.

    Edited: This is still not fool-proof. The last call to SetWindowLong will assign a procedure address to be used. All effort should be made to ensure that last call is correct. Though my implementation should work for multiple instances of one usercontrol subclassing a window; it is not guaranteed to work if other stuff in the project is also subclassing that same window because the the thunks have no knowledge of that and cannot control when or where that other stuff stops/redirects subclassing. The only way to make subclassing a single window multiple times absolutely safe is 1) ensure all unsubclassing is done in exact opposite order of subclassing, or 2) ensure that every window procedure addressed passed to SetWindowLong remains valid until the subclassed window is either destroyed or all subclassing has been terminated

    The thunks are not written to allow a single instance of anything to subclass multiple windows simultaneously.

    4. The way the ordinals work is simple enough. Ordinal #1 is the very last private function in the class. Ordinal #2 is the 2nd to last private function in the class. When a thunk is created, the logic finds the function at the ordinal you wanted and sends all traffic to that function. If the ordinals are wrong, or you later append code to the end of the class, you will crash until you update your code and pass the correct/adjusted ordinal to the thunk-creating routines. All ordinals should be contiguous, not separated by any public functions or subs.
    Code:
    Private SomeFunction(parameters) As Long ' ordinal #2
    
    End Function
    Private SomeOtherFunction(parameters) As Long ' ordinal #1
    
    End Function
    ' end of the class; absolutely no executable code can come after last private function
    5. Regarding IsBadCodePtr: I no longer trust/use that API

    Last but not least. I do not use thunks in compiled projects. Since a bas module will not be unloaded until the project unloads, the function in that module used for subclassing will remain until your project unloads which will occur after all windows in the project have been destroyed. Of course, the WM_DESTROY message should be handled in all subclass routines to unsubclass.
    Last edited by LaVolpe; Sep 4th, 2011 at 01:25 PM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  3. #3
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: @LaVolpe: your Thunker

    With the above being said, here's a basic issue with subclassing a window multiple times.

    Subclassing relies on the procedure processing the message to call the next window procedure. This means that the subclassing object keeps track of the previous procedure. And this is where things can become unstable when trying to use thunks or any other method where the window procedure exists in a disposable object, like a class, usercontrol, or thunk for example. What happens when a class gets destroyed and a message is sent to that class from another procedure? Crash of course. How does this happen? In the scenarios below, it doesn't matter if we are talking about classes, usercontrols, or thunks, same logic applies.

    Scenario 1:
    When Class #1 subclasses & it stores the previous procedure (original window procedure if first time the window is subclassed) when it calls SetWindowLong and tells the window to send messages to itself now. Well when Class#2 subclasses same window and the previous procedure it gets from SetWindowLong is an address related to Class#1. All works fine until a class earlier in the subclassing process removes itself from the chain. Let's say Class #1 at some point unsubclasses the window and assigns the window procedure back to what it stored as the previous procedure (the original window procedure in this case). Ok? No problem, right? Wrong. Now Class #2 won't be getting any more messages. And if Class #2 is destroyed before the subclassed window is destroyed, then crash as described in next scenario.

    Scenario 2:
    Similar as 1st scenario, but 3 classes: Class #1 subclasses & stores original procedure. Class #2 subclasses and stores current procedure (that of Class #1). Class #3 subclasses and stores current procedure (that of Class #2). All works well: message comes in, Class #3 processes it, sends message to Class #2 which sends message to Class #1 which sends message to window's default handler. But what happens if Class #2 is destroyed/released? It sets the window procedure back to Class #1 and Class #3 is choked off. But if Class #3 is later destroyed/released at some point before the window is destroyed, what happens there? It sets the window procedure to Class #2 (the previous procedure address it stored when it called SetWindowLong), but Class #2 has already been destroyed/released and the next message that comes in causes a crash.

    With above scenarios, you can write code that pretty much removes any of the problems by using some sort of custom queue method or ensuring classes are unloaded last in, first out. Where the danger comes in is when you introduce some ocx/dll that is subclassing the same window without your knowledge. You'll obviously have no control in the unsubclassing order at that point. Problem exists even with your own created usercontrols since they are form objects destroyed by VB in an order you have no control over.

    As mentioned in previous reply. To ensure safe subclassing, 1) the address(es) given to SetWindowLong must remain valid for life of the subclassed window or at least until the window is returned back to its original subclass procedure after all subclassing is finished, 2) or unsubclassing must be done in exact opposite order the window was subclassed in. Option 1 is solved by having the subclass procedure in a module. Option 2 is nearly impossible to solve unless you know 100% you are not adding any subclassing ocx/dlls to your project and you have a method of ensuring last in, first out of subclassing objects.
    Last edited by LaVolpe; Sep 4th, 2011 at 01:39 PM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  4. #4
    PowerPoster dilettante's Avatar
    Join Date
    Feb 2006
    Posts
    24,487

    Re: @LaVolpe: your Thunker

    *obsolete*
    Last edited by dilettante; Sep 4th, 2011 at 02:25 PM.

  5. #5
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: @LaVolpe: your Thunker

    dilettante.... You read my post before I updated it. I removed that statement when I re-read it an saw it was false.

    Regarding safer subclassing... Probably regarding some free, outside DLL (name escapes me) that was touted as the next best thing for safe subclassing within IDE. Never really caught on I guess.

    Points I was really attempting to make in my 2 replies above was that: Want to subclass something? Put the subclass procedure in a module. That does make subclassing unstable in IDE. Want to add thunks or something else to make subclassing safer in IDE? Fine in limited scope, but recommend moving to traditional subclassing before compiling.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  6. #6

    Thread Starter
    Lively Member
    Join Date
    Sep 2009
    Posts
    95

    Re: @LaVolpe: your Thunker

    Hello LaVolpe!

    Sorry for asking too many questions at once!

    Thank you very much for your helpful explainations. - Here I have a question to it:
    "And if Class #2 is destroyed before the subclassed window is destroyed, then crash as described in next scenario."
    From this I do understand, that nothing happens, if the subclassed window is destroyed first.
    But a friend of mine was facing crashes while doing this (module based subclassing).
    Do you have an explaination for this?

    Well, I did use the old Thunker from XtremeVBtalk unfortunatelly. - I just found the newer version while searching for the link in my first post.
    -> I will work with the newest version only from now on.

    "The thunks are not written to allow a single instance of anything to subclass multiple windows simultaneously."
    You mean, that I have to create an instance of your Thunker class for each window I subclass? - This is what I do.

    "Last but not least. I do not use thunks in compiled projects. Since a bas module will not be unloaded until the project unloads, the function in that module used for subclassing will remain until your project unloads which will occur after all windows in the project have been destroyed."
    Ok, reasonable. But I like to achieve a way of subclassing, which fits to the VB event philosophy.
    To reach that goal I just raise events in the callback of your Thunker - like you did in your example.
    For this I absolutely need the callback in class - and therefore I do need the thunks.

    Do you consider your thunks bullet-proof for using in compiled projects also, assuming that
    only one Thunker instance is used for one window and a window is only subclassed once?

    "Of course, the WM_DESTROY message should be handled in all subclass routines to unsubclass."
    Ok, I will do this.

    I like to prevent my code to raise an event while the subclassed window is in the destruction process.
    Since the WM_DESTROY message comes in, when the window has been destroyed already, I have to look for another message.
    Is the message 0x90 (=144) the right one for this? - Do you have any idea how to find some documentation to that message?

    You said, that you no longer trust/use the API IsBadCodePtr. - But it is still used in your newest Thunker project.
    Did I just understand something wrong? Or do you have already a newer version of it, which you did not upload so far?

    Regarding safer subclassing:
    Putting the subclassing code into a dll was not a solution for me in the past, since I did not want to depend on dependencies.
    But maybe I do change my mind, because I found out, that there are possibilites to compile a project group to one file.
    Oh, and the SetWindowSubclass API was another question. Did you ever have a look on this?

    Thanks again!
    (hope that there are not too much questions this time...)

  7. #7
    PowerPoster dilettante's Avatar
    Join Date
    Feb 2006
    Posts
    24,487

    Re: @LaVolpe: your Thunker

    Quote Originally Posted by LaVolpe View Post
    Want to subclass something? Put the subclass procedure in a module. That does make subclassing unstable in IDE.
    Hmm.

    I'm not questioning you on this, but I'm not sure that is true.

    Take a quick look at the attached project. It's a bit cobbled together out of other Projects so you can ignore most of the code. But it does use a static (BAS) module along with SetWindowSubclass and friends to subclass two different UserControls.

    I'm not saying it can "live through" an End statement execution, but it seems to work fine and doesn't crash the IDE if you bash the stop button.

    Where am I going wrong on this?


    To try the Project attached just unzip, open it in VB6. Then F5/Run and hit stop. F5/Run, minimize (to the tray) and hit stop again. Compile and then run. Seems to work fine here.
    Attached Files Attached Files

  8. #8
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: @LaVolpe: your Thunker

    I did not realize the thread was discussing some common controls library function.

    If that is the case, I retract all my statements since I have no experience with that function

    Edited: Having subclassing handled by a compiled DLL is generally safe, regardless which method is used
    Even with a VB dll. I once created a DLL (on PSC) that was 99.99% crash proof. It would still find occasions to crash like if user called CopyMemory with invalid pointers
    Last edited by LaVolpe; Sep 5th, 2011 at 04:01 PM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  9. #9
    PowerPoster dilettante's Avatar
    Join Date
    Feb 2006
    Posts
    24,487

    Re: @LaVolpe: your Thunker

    Quote Originally Posted by LaVolpe View Post
    I did not realize the thread was discussing some common controls library function.
    That is where they (the Shell/GUI team) had put the subclassing API, but from what I've read it had to go somewhere in Win32 and it just fit there the best.

    It wasn't really documented though until the XP SDK came out, when they also exported the entrypoints by name as well as ordinal.

  10. #10

    Thread Starter
    Lively Member
    Join Date
    Sep 2009
    Posts
    95

    Re: @LaVolpe: your Thunker

    Hello LaVolpe,

    I wanted to let you some more time - not bombing you with too much questions again.

    If you have an answer to a few of my last questions, I would be really glad.

    Quote Originally Posted by LaVolpe View Post
    I did not realize the thread was discussing some common controls library function.
    No, I am interested in any information about subclassing.

    If that is the case, I retract all my statements since I have no experience with that function
    Your statements are valued a lot. I also value dilettante post, mentioning his project.

    Edited: Having subclassing handled by a compiled DLL is generally safe, regardless which method is used
    Even with a VB dll. I once created a DLL (on PSC) that was 99.99% crash proof. It would still find occasions to crash like if user called CopyMemory with invalid pointers
    This sounds awesome! What is the projects name? - I want to check it!

    Thanks again!

  11. #11
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: @LaVolpe: your Thunker

    Quote Originally Posted by NeedHelp! View Post
    This sounds awesome! What is the projects name? - I want to check it!

    Thanks again!
    PlanetSourceCode: EZ Subclasser III

    In that project posting, I made the following statements. Don't take it too literally. Both methods (thunks/dlls) have their advantages and usage is really up to the coder's preferences. Thunks don't require any dependencies, external DLLs do. Both can make IDE subclassing much safer. Both, IMO, could be used for subclassing uncompiled projects, but traditional subclassing maybe should be used for compiled apps. The reason for the following statement was that thunks have the ability to test the IDE to see if it is in break mode. I could have included that in the PSC dll project, but didn't
    Quote Originally Posted by LaVolpe
    To all. I am no longer supporting this project. There is nothing wrong with it (to the best of my knowledge). However, recent collaboration with Paul Caton and seeing what he is accomplishing thru his newest thunks, I am now a convert -- thunking is the way to go IMO.
    Last edited by LaVolpe; Sep 12th, 2011 at 11:03 AM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width