Results 1 to 33 of 33

Thread: About DEXWERX's subclassing dll

  1. #1

    Thread Starter
    PowerPoster
    Join Date
    Sep 2012
    Posts
    2,083

    About DEXWERX's subclassing dll

    This question comes from another thread. In order not to hijack the original thread, I posted a new thread to discuss this question.

    http://www.vbforums.com/showthread.p...=1#post5273985

    Quote Originally Posted by DEXWERX View Post
    Hi Doug,
    If you get into subclassing, feel free to use my subclassing dll. It will save a lot of heart ache and crashes.
    Welcome to the forums. I am also a power person.
    Hi DEXWERX, I have a question: What is the difference between your subclassing dll and the following Subclassing solutions, and what are the advantages of your subclassing dll:

    1. vbRichClient5.Subclass
    2. The trick's Subclass (ASM)
    3. Steve McMahon([email protected])'s SSubTmr6.dll
    4. Krool's Subclass
    5. LaVolpe's Subclass
    6. Paul Caton's Self-Subclass

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

    Re: About DEXWERX's subclassing dll

    There is no #5. Any relatively recent (last 5-10 years?) subclass thunks I designed were based off of Paul Caton's (with his permission) and tried to enhance it, make it more stable. Some of those you listed can fail when placed in a usercontrol that subclasses its parent, and multiple usercontrols placed on the same form. A common problem if not specifically handled.

    #7 was not mentioned: Common Controls APIs for subclassing.
    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
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    10,791

    Re: About DEXWERX's subclassing dll

    hahaha, geez. Dream, you putting Dex on the spot there a bit?

    And hey, you forgot my approach, shown here by example. I suppose mine has the downside that it's not 100% IDE safe, but I still like it. It has the advantage that there are no thunks nor extra DLL dependencies. It's a pure within-project VB6 solution. Basically, these days, I think everyone rather strongly recommends the ComCtl32 approach to subclassing, regardless of thunks and/or dependencies used.

    All The Best,
    Elroy
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  4. #4
    PowerPoster
    Join Date
    Jun 2015
    Posts
    2,229

    Re: About DEXWERX's subclassing dll

    Please comment with corrections if you see any errors, I'll try and update this chart.

    Name:  Subclassing.gif
Views: 920
Size:  8.0 KB

    Source - Source is available
    DLL - DLL Dependency when debugging in IDE
    Thunk - self contained, thunk is in Assembly, memory is managed outside of IDE, (removed FUD about thunks)
    ComCtl - Uses API to manage multiple subclasses curing tear down crashes, adds a small memory leak per callback address.
    SetProp - GetProp/SetProp API can cause issues on some systems
    Pause - Allows breaking, even in subclassing procedure. *if you can only view where a bug is before crashing the IDE.
    Stop - Survives stop button being pressed
    End - Immune to the End Statement
    Debug - Allows Edit and Continue of Subclass procedure, bugs in any procedure won't crash the IDE


    NOTES:
    Also just like there isn't a "Lavolpe Subclass" which is an improvement of Caton's Self-Subclass.
    Krool's subclass is the generic ComCtl32 subclassing with an added thunk to handle pressing the Stop Button.
    Generic ComCtl32 are all basically the same (Bonnie,Dilettante etc) and came from Karl E. Peterson's HookXP.
    I believe wqweto uses a DLL based on SSubTmr.
    Eduardo also says he has a subclassing dll, based on SSubTmr that also handles Stop/End/Debug
    Elroy's modifications catch most Stop conditions, and is noticeably more stable in the IDE otherwise.
    Also added that pausing (if not in the subclass proc) is more stable in the IDE when using ComcCtl32 subclassing.

    edit:
    modified chart with latest inputs, from Trick/Elroy/V.B.IV
    Last edited by DEXWERX; Mar 27th, 2018 at 04:05 PM.

  5. #5
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    10,791

    Re: About DEXWERX's subclassing dll

    Quote Originally Posted by DEXWERX View Post
    Generic ComCtl32 are all basically the same
    Basically, I completely agree with that. However, by always checking for WM_DESTROY in the subclassed procedure, keeping all the subclassing in a BAS module, and creating a bSetWhenSubclassing_UsedByIdeStop variable, I've created a setup that's IDE safe in many situations. You can't stop in modal forms and you can't use the syntax error popup End button, but you can safely use the IDE's stop button in most (if not all) other circumstances (i.e., just stopping in a non-modal form).

    What's quite interesting is that, when subclassing, the subclassed procedure will still execute even after you've pressed the stop button. Therefore, you still get a chance to un-subclass stuff. The instant you hit "Stop", all objects are uninstantiated and all global, module, & static variables are set to zero. But code can still get executed even after that. With that knowledge, we can become partially IDE safe, without any thunks or DLLs. So maybe "Pause", "Stop", "End", & "Debug" in your table get a 1/2 asterisk for ComCtl.

    Best Regards,
    Elroy
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  6. #6
    PowerPoster
    Join Date
    Jun 2015
    Posts
    2,229

    Re: About DEXWERX's subclassing dll

    Quote Originally Posted by Elroy View Post
    Basically, I completely agree with that. However, by always checking for WM_DESTROY in the subclassed procedure, keeping all the subclassing in a BAS module, and creating a bSetWhenSubclassing_UsedByIdeStop variable, I've created a setup that's IDE safe in many situations. You can't stop in modal forms and you can't use the syntax error popup End button, but you can safely use the IDE's stop button in most (if not all) other circumstances (i.e., just stopping in a non-modal form).

    What's quite interesting is that, when subclassing, the subclassed procedure will still execute even after you've pressed the stop button. Therefore, you still get a chance to un-subclass stuff. The instant you hit "Stop", all objects are uninstantiated and all global, module, & static variables are set to zero. But code can still get executed even after that. With that knowledge, we can become partially IDE safe, without any thunks or DLLs. So maybe "Pause", "Stop", "End", & "Debug" in your table get a 1/2 asterisk for ComCtl.

    Best Regards,
    Elroy
    If you post an example, I'll go ahead and test it out. If you can indeed survive the stop button, that's more than an asterisk
    Also considering your improvements, I'll give you your own row.

  7. #7

  8. #8
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    10,791

    Re: About DEXWERX's subclassing dll

    Hi Dex,

    I really don't need my own row. The thought is appreciated though.

    But here's an example with two routines included for subclassing (SubclassFormFixedSize and SubclassFormMinMaxSize). Also, note that there's a global gbAllowSubclassing that must be set or nothing will get subclassed. Here's the example, moderately commented:

    Code:
    '
    ' Notes on subclassing with Comctl32.DLL:
    '
    '   1.  A subclassed function will get executed even AFTER the IDE "Stop" button is pressed.
    '       This gives us an opportunity to un-subclass everything if things are done correctly.
    '       Things that will still crash the IDE:
    '
    '       *   Executing the "END" statement in code.
    '       *   Clicking IDE "Stop" on modal form loaded after something else is subclassed.
    '       *   Clicking the "End" button after a runtime error on the "End", "Debug", "Help" form.
    '
    '   2.  "Each subclass is uniquely identified by the address of the pfnSubclass and its uIdSubclass"
    '       (quote from Microsoft.com).
    '
    '   3.  For a particular hWnd, the last procedure subclassed will be the first to execute.
    '
    '   4.  If we call SetWindowSubclass repeatedly with the same hWnd, same pfnSubclass,
    '       same uIdSubclass, and same dwRefData, it does nothing at all.
    '       Not even the order of the subclassed functions will change,
    '       even if other functions were subclassed later, and then SetWindowSubclass was
    '       called again with the same hWnd, pfnSubclass, uIdSubclass, and dwRefData.
    '
    '   5.  Similar to the above, if we call SetWindowSubclass repeatedly,
    '       and nothing changes but the dwRefData, the dwRefData is changed like we want,
    '       but the order of execution of the functions still stays the same as it was.
    '        "To change reference data you can make subsequent calls to SetWindowSubclass"
    '       (quote from Microsoft.com).
    '
    '   6.  When un-subclassing, we can call RemoveWindowSubclass in any order we like, with no harm.
    '
    '   7.  We don't have to call DefSubclassProc in a particular subclassed function, but if we don't,
    '       all other "downstream" subclassed functions won't execute.
    '
    '   8.  In the subclassed function, if uMsg = WM_DESTROY we should absolutely call
    '       DefSubclassProc so that other possible "downstream" procedures can also un-subclassed.
    '
    '   9.  Things that are cleared BEFORE the subclass proc is executed again when the
    '       IDE "Stop" button is clicked (i.e., before "uMsg = WM_DESTROY"):
    '       *   All COM objects are uninstantiated (including Collections).
    '       *   All dynamic arrays are erased.
    '       *   All static arrays are reset (i.e., set to zero, vbNullString, etc.)
    '       *   ALL variables are reset, including local Static variables.
    '
    '   10. Continuing on the above, even after all that is done, we can still make use of
    '       variables, just recognizing that they'll be "fresh" variables.
    '
    '   11. The dwRefData can be used for whatever we want.  It's stored by Comctl32.DLL and is
    '       returned everytime the subclassed procedure is called, or when explicitly requested by
    '       a call to GetWindowSubclass.
    '
    Option Explicit
    '
    Public gbAllowSubclassing As Boolean    ' Be sure to turn this on if you're going to use subclassing.
    '
    Private Const WM_DESTROY As Long = &H2&
    '
    Private Declare Function SetWindowSubclass Lib "comctl32.dll" Alias "#410" (ByVal hWnd As Long, ByVal pfnSubclass As Long, ByVal uIdSubclass As Long, Optional ByVal dwRefData As Long) As Long
    Private Declare Function GetWindowSubclass Lib "comctl32.dll" Alias "#411" (ByVal hWnd As Long, ByVal pfnSubclass As Long, ByVal uIdSubclass As Long, pdwRefData As Long) As Long
    Private Declare Function RemoveWindowSubclass Lib "comctl32.dll" Alias "#412" (ByVal hWnd As Long, ByVal pfnSubclass As Long, ByVal uIdSubclass As Long) As Long
    Private Declare Function NextSubclassProcOnChain Lib "comctl32.dll" Alias "#413" (ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    'Private Declare Function DefSubclassProc Lib "comctl32.dll" Alias "#413" (ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    '
    Dim bSetWhenSubclassing_UsedByIdeStop As Boolean ' Never goes false once set by first subclassing, unless IDE Stop button is clicked.
    '
    Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByRef Dest As Any, ByRef Source As Any, ByVal Bytes As Long)
    '
    '**************************************************************************************
    ' The following MODULE level stuff is specific to individual subclassing needs.
    '**************************************************************************************
    '
    Private Enum ExtraDataIDs
        ' These must be unique for each piece of extra data.
        ' They just give us 4 bytes each managed by ComCtl32.
        ID_ForMaxSize = 1
    End Enum
    #If False Then  ' Intellisense fix.
        Dim ID_ForMaxSize
    #End If
    '
    Public Type POINTAPI
        X As Long
        Y As Long
    End Type
    Private Type MINMAXINFO
        ptReserved As POINTAPI
        ptMaxSize As POINTAPI
        ptMaxPosition As POINTAPI
        ptMinTrackSize As POINTAPI
        ptMaxTrackSize As POINTAPI
    End Type
    '
    
    '**************************************************************************************
    '**************************************************************************************
    '**************************************************************************************
    '
    ' Generic subclassing procedures (used in many of the specific subclassing).
    '
    '**************************************************************************************
    '**************************************************************************************
    '**************************************************************************************
    
    Private Sub SubclassSomeWindow(hWnd As Long, AddressOf_ProcToSubclass As Long, Optional dwRefData As Long)
        ' This just always uses hWnd for uIdSubclass, as we never have a need to subclass the same window to the same proc.
        ' The uniqueness is pfnSubclass and uIdSubclass (2nd and 3rd argument below).
        '
        ' This can be called AFTER the initial subclassing to update dwRefData.
        '
        If Not gbAllowSubclassing Then Exit Sub
        '
        bSetWhenSubclassing_UsedByIdeStop = True
        Call SetWindowSubclass(hWnd, AddressOf_ProcToSubclass, hWnd, dwRefData)
    End Sub
    
    Private Sub SubclassExtraData(hWnd As Long, dwRefData As Long, ID As ExtraDataIDs)
        ' This is used solely to store extra data.
        '
        If Not gbAllowSubclassing Then Exit Sub
        '
        bSetWhenSubclassing_UsedByIdeStop = True
        Call SetWindowSubclass(hWnd, AddressOf DummyProcForExtraData, ID, dwRefData)
    End Sub
    
    Private Function GetSubclassRefData(hWnd As Long, AddressOf_ProcToSubclass As Long) As Long
        ' This one is used only to fetch the optional dwRefData you may have specified when calling SubclassSomeWindow.
        ' Typically this would only be used by the subclassed procedure, but it is available to anyone.
        Call GetWindowSubclass(hWnd, AddressOf_ProcToSubclass, hWnd, GetSubclassRefData)
    End Function
    
    Private Function GetExtraData(hWnd As Long, ID As ExtraDataIDs) As Long
        Call GetWindowSubclass(hWnd, AddressOf DummyProcForExtraData, ID, GetExtraData)
    End Function
    
    Private Function IsSubclassed(hWnd As Long, AddressOf_ProcToSubclass As Long) As Boolean
        ' This just tells us we're already subclassed.
        Dim dwRefData As Long
        IsSubclassed = GetWindowSubclass(hWnd, AddressOf_ProcToSubclass, hWnd, dwRefData) = 1&
    End Function
    
    Private Sub UnSubclassSomeWindow(hWnd As Long, AddressOf_ProcToSubclass As Long)
        ' Only needed if we specifically want to un-subclass before we're closing the form (or control),
        ' otherwise, it's automatically taken care of when the window closes.
        '
        ' Be careful, some subclassing may require additional cleanup that's not done here.
        Call RemoveWindowSubclass(hWnd, AddressOf_ProcToSubclass, hWnd)
    End Sub
    
    Private Sub UnSubclassExtraData(hWnd As Long, ID As ExtraDataIDs)
        Call RemoveWindowSubclass(hWnd, AddressOf DummyProcForExtraData, ID)
    End Sub
    
    Private Function ProcedureAddress(AddressOf_TheProc As Long)
        ' A private "helper" function for writing the AddressOf_... functions (see above notes).
        ProcedureAddress = AddressOf_TheProc
    End Function
    
    Private Function DummyProcForExtraData(ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long, ByVal uIdSubclass As Long, ByVal dwRefData As Long) As Long
        ' Just used for SubclassExtraData (and GetExtraData and UnSubclassExtraData).
        If uMsg = WM_DESTROY Then Call RemoveWindowSubclass(hWnd, AddressOf_DummyProc, uIdSubclass)
        DummyProcForExtraData = NextSubclassProcOnChain(hWnd, uMsg, wParam, lParam)
    End Function
    
    Private Function AddressOf_DummyProc() As Long
        AddressOf_DummyProc = ProcedureAddress(AddressOf DummyProcForExtraData)
    End Function
    
    Private Function IdeStopButtonClicked() As Boolean
        ' The following works because all variables are cleared when the STOP button is clicked,
        ' even though other code may still execute such as Windows calling some of the subclassing procedures below.
        IdeStopButtonClicked = Not bSetWhenSubclassing_UsedByIdeStop
    End Function
    
    '**************************************************************************************
    '**************************************************************************************
    '**************************************************************************************
    '
    ' The following are our functions to be subclassed, along with their AddressOf_... function.
    ' All of the following should be Private to make sure we don't accidentally call it,
    ' except for the first procedure that's actually used to initiate the subclassing.
    '
    '**************************************************************************************
    '**************************************************************************************
    '**************************************************************************************
    
    Public Sub SubclassFormFixedSize(frm As VB.Form)
        '
        ' This fixes the size of a window, even if it won't fit on a monitor.
        '
        ' On this one, we use dwRefData on the first time through so we can do some setup (see FixedSize_RefData).
        ' We can't use GetWindowRect.  It reports an already resized value.
        '
        ' NOTE: If done in the form LOAD event, the form will NOT have been resized from a smaller monitor.
        '       If done in form ACTIVATE or anywhere else, we're too late, and the form will have been resized.
        '
        ' ALSO: If you're in the IDE, and the monitors aren't big enough, do NOT open the form in design mode.
        '       So long as you don't open it, everything is fine, although you can NOT compile in the IDE.
        '       If you're compiling without large enough monitors, you MUST do a command line compile.
        '
        ' This can simultaneously be used by as many forms as will need it.
        '
        ' NOTICE:  Be sure the window is moved (possibly centered) AFTER this is call, or we may not see WM_GETMINMAXINFO until a bit later.
        '
        SubclassSomeWindow frm.hWnd, AddressOf FixedSize_Proc, FixedSize_RefData(frm)
    End Sub
    
    Private Function FixedSize_Proc(ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long, ByVal uIdSubclass As Long, ByVal dwRefData As Long) As Long
        If uMsg = WM_DESTROY Then
            UnSubclassSomeWindow hWnd, AddressOf_FixedSize_Proc
            FixedSize_Proc = NextSubclassProcOnChain(hWnd, uMsg, wParam, lParam)
            Exit Function
        End If
        If IdeStopButtonClicked Then ' Protect the IDE.  Don't execute any specific stuff if we're stopping.  We may run into COM objects or other variables that no longer exist.
            FixedSize_Proc = NextSubclassProcOnChain(hWnd, uMsg, wParam, lParam)
            Exit Function
        End If
        '
        Dim PelWidth As Long
        Dim PelHeight As Long
        Dim MMI As MINMAXINFO
        Const WM_GETMINMAXINFO As Long = &H24&
        '
        ' And now we force our size to not change.
        If uMsg = WM_GETMINMAXINFO Then
            ' Force the form to stay at initial size.
            PelWidth = dwRefData And &HFFFF&
            PelHeight = (dwRefData And &H7FFF0000) \ &H10000
            '
            CopyMemory MMI, ByVal lParam, LenB(MMI)
            '
            MMI.ptMinTrackSize.X = PelWidth
            MMI.ptMinTrackSize.Y = PelHeight
            MMI.ptMaxTrackSize.X = PelWidth
            MMI.ptMaxTrackSize.Y = PelHeight
            '
            CopyMemory ByVal lParam, MMI, LenB(MMI)
            Exit Function ' If we process the message, we must return 0 and not let more subclassed procedures execute.
        End If
        '
        ' Give control to other procs, if they exist.
        FixedSize_Proc = NextSubclassProcOnChain(hWnd, uMsg, wParam, lParam)
    End Function
    
    Private Function FixedSize_RefData(frm As VB.Form) As Long
        ' We must use this to pass the form's initial width and height.
        ' Note that using GetWindowRect absolutely doesn't work.  It reports an already resized value.
        '
        Dim PelWidth As Long
        Dim PelHeight As Long
        '
        PelWidth = frm.Width \ Screen.TwipsPerPixelX
        PelHeight = frm.Height \ Screen.TwipsPerPixelY
        '
        ' Push PelHeight to high two-bytes, and add PelWidth.
        ' This will easily accomodate any monitor in the foreseeable future.
        FixedSize_RefData = (PelHeight * &H10000 + PelWidth)
    End Function
    
    Private Function AddressOf_FixedSize_Proc() As Long
        AddressOf_FixedSize_Proc = ProcedureAddress(AddressOf FixedSize_Proc)
    End Function
    
    '**************************************************************************************
    '**************************************************************************************
    '**************************************************************************************
    
    Public Sub SubclassFormMinMaxSize(frm As VB.Form, Optional ByVal MinWidth As Long, Optional ByVal MinHeight As Long, Optional ByVal MaxWidth As Long, Optional ByVal MaxHeight As Long)
        ' It's PIXELS.
        '
        ' MUST be done in Form_Load event so Windows doesn't resize form on small monitors.
        ' Also, move (such as center) the form after calling so that WM_GETMINMAXINFO is fired.
        ' Can be called repeatedly to change MinWidth, MinHeight, MaxWidth, and MaxHeight with no harm done.
        ' Although, all must be supplied that you wish to maintain.
        '
        ' Not supplying an argument (i.e., leaving it zero) will cause it to be ignored.
        '
        ' Some validation before subclassing.
        If MinWidth > MaxWidth And MaxWidth <> 0 Then MaxWidth = MinWidth
        If MinHeight > MaxHeight And MaxHeight <> 0 Then MaxHeight = MinHeight
        '
        SubclassSomeWindow frm.hWnd, AddressOf MinMaxSize_Proc, CLng(MinHeight * &H10000 + MinWidth)
        SubclassExtraData frm.hWnd, CLng(MaxHeight * &H10000 + MaxWidth), ID_ForMaxSize
    End Sub
    
    Private Function MinMaxSize_Proc(ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long, ByVal uIdSubclass As Long, ByVal dwRefData As Long) As Long
        If uMsg = WM_DESTROY Then
            UnSubclassSomeWindow hWnd, AddressOf_MinMaxSize_Proc
            MinMaxSize_Proc = NextSubclassProcOnChain(hWnd, uMsg, wParam, lParam)
            Exit Function
        End If
        If IdeStopButtonClicked Then ' Protect the IDE.  Don't execute any specific stuff if we're stopping.  We may run into COM objects or other variables that no longer exist.
            MinMaxSize_Proc = NextSubclassProcOnChain(hWnd, uMsg, wParam, lParam)
            Exit Function
        End If
        '
        Dim MinWidth As Long
        Dim MinHeight As Long
        Dim MaxWidth As Long
        Dim MaxHeight As Long
        Dim MMI As MINMAXINFO
        Const WM_GETMINMAXINFO As Long = &H24&
        '
        Select Case uMsg
        Case WM_GETMINMAXINFO
            MinWidth = dwRefData And &HFFFF&
            MinHeight = (dwRefData And &H7FFF0000) \ &H10000
            dwRefData = GetExtraData(hWnd, ID_ForMaxSize)
            MaxWidth = dwRefData And &HFFFF&
            MaxHeight = (dwRefData And &H7FFF0000) \ &H10000
            '
            CopyMemory MMI, ByVal lParam, LenB(MMI)
            If MinWidth <> 0 Then MMI.ptMinTrackSize.X = MinWidth
            If MinHeight <> 0 Then MMI.ptMinTrackSize.Y = MinHeight
            If MaxWidth <> 0 Then MMI.ptMaxTrackSize.X = MaxWidth
            If MaxHeight <> 0 Then MMI.ptMaxTrackSize.Y = MaxHeight
            CopyMemory ByVal lParam, MMI, LenB(MMI)
            Exit Function ' If we process the message, we must return 0 and not let more subclass procedures execute.
        End Select
        '
        ' Give control to other procs, if they exist.
        MinMaxSize_Proc = NextSubclassProcOnChain(hWnd, uMsg, wParam, lParam)
    End Function
    
    Private Function AddressOf_MinMaxSize_Proc() As Long
        AddressOf_MinMaxSize_Proc = ProcedureAddress(AddressOf MinMaxSize_Proc)
    End Function
    And to use the SubclassFormMinMaxSize, you'd just do something like the following, no un-subclassing required:

    Code:
    Option Explicit
    
    Private Sub Form_Load()
        gbAllowSubclassing = True
        SubclassFormMinMaxSize Me, 300, 400, 500, 0
        Me.Top = (Screen.Height - Me.Height) / 2
        Me.Left = (Screen.Width - Me.Width) / 2
    End Sub
    With that code, and when used on a non-modal form, you can hit the IDE's stop button with no harm done. That MinMaxSize_Proc will be executed after the stop button is clicked, hitting the WM_DESTROY message, and then correctly un-subclass things.

    For my money, it's pretty nifty. But it basically is the basic ComCtl32 subclassing with just a few enhancements.

    Best Regards,
    Elroy
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  9. #9
    The Idiot
    Join Date
    Dec 2014
    Posts
    2,909

    Re: About DEXWERX's subclassing dll

    the "little" subclassing that im using (mostly winsock) the WM_DESTROY is helping me avoid crashes. but its not 100% safe, sometimes it can freeze if theres some unknown errors.
    mostly i avoid subclassing and try other solutions first.

  10. #10
    PowerPoster
    Join Date
    Jun 2015
    Posts
    2,229

    Re: About DEXWERX's subclassing dll

    Quote Originally Posted by The trick View Post
    Hi DEXWERX. What's the issue exactly?
    My code uses the thunk in the compiled form only because it has the "single-class" implementation. If someone adds a standard module he can avoid the thunk at all. Also my class is slower because it uses the event-base model. It uses ComCtl only because it has already implemented sublassing chain.
    I have no issue? Thunks work fine for most of us, heck wqweto puts whole libraries into thunks

    Good inputs. Thanks for adding the details / design decisions on how your Single Class implementation works.


    @Elroy: your implementation is nothing like the generic comctl32 usage, per HookXP. The generic use is modular / removing the boilerplate.
    You don't even forward the subclass, it's just a single Static hook in a bas module (specialized to that one type of function).
    The advantage being you just plop the needed bas into each project.

    (in case you're wondering why i grouped most of them together, it's because they're all derivatives including my own implementation)
    Last edited by DEXWERX; Mar 27th, 2018 at 01:22 PM.

  11. #11
    Hyperactive Member
    Join Date
    Aug 2017
    Posts
    380

    Re: About DEXWERX's subclassing dll

    Quote Originally Posted by DEXWERX View Post
    Generic ComCtl32 are all basically the same (Elroy,Bonnie,Dilettante, etc) and came from Paul Caton's HookXP.
    I believe what you actually meant to say is that they all came from Karl E. Peterson's HookXP sample. Paul Caton eventually did use Common Control subclassing though.

  12. #12
    PowerPoster
    Join Date
    Jun 2015
    Posts
    2,229

    Re: About DEXWERX's subclassing dll

    Quote Originally Posted by Victor Bravo VI View Post
    I believe what you actually meant to say is that they all came from Karl E. Peterson's HookXP sample. Paul Caton eventually did use Common Control subclassing though.
    You're absolutely right. Credit where it's due. I'll fix my original post.

  13. #13
    PowerPoster
    Join Date
    Feb 2017
    Posts
    5,466

    Re: About DEXWERX's subclassing dll

    Quote Originally Posted by DEXWERX View Post
    Eduardo also says he has a subclassing dll, based on SSubTmr that also handles Stop/End/Debug
    Hi,

    Yes, the source code is used here. In this case not as a Dll but integrated into the main project.

    It uses the interface of Steve McMahon's SSubTmr6.dll (with little modification) but internally adapted to use ComCtl's APIs.

    When used as an external DLL, it is quite IDE safe.
    One advantage of this subclassing (also present in the original SSubTmr6.dll) is to receive in the WindowProc only the messages that I want to handle.
    Another is the ability to preprocess, postprocess or consume the messages.

    One problem that I found is that sometimes (generally after many program crashes) the SetProp/GetProp database can get full and doesn't work anymore (I found that when used SSubTmr6.dll).
    I tried to overcome this (rare) problem detecting the situation and using a collection instead in those cases, so the program can still run.
    I decided not to replace the SetProp/GetProp with the collection always because SetProp/GetProp can handle data across instances.
    But as I said, that database full situation doesn't happen normally, so it is only an additional meassure.

  14. #14
    PowerPoster
    Join Date
    Jun 2015
    Posts
    2,229

    Re: About DEXWERX's subclassing dll

    Quote Originally Posted by Eduardo- View Post
    Hi,

    Yes, the source code is used here. In this case not as a Dll but integrated into the main project.

    It uses the interface of Steve McMahon's SSubTmr6.dll (with little modification) but internally adapted to use ComCtl's APIs.

    When used as an external DLL, it is quite IDE safe.
    One advantage of this subclassing (also present in the original SSubTmr6.dll) is to receive in the WindowProc only the messages that I want to handle.
    Another is the ability to preprocess, postprocess or consume the messages.

    One problem that I found is that sometimes (generally after many program crashes) the SetProp/GetProp database can get full and doesn't work anymore (I found that when used SSubTmr6.dll).
    I tried to overcome this (rare) problem detecting the situation and using a collection instead in those cases, so the program can still run.
    I decided not to replace the SetProp/GetProp with the collection always because SetProp/GetProp can handle data across instances.
    But as I said, that database full situation doesn't happen normally, so it is only an additional meassure.
    I've also seen this fixed by entirely replacing GetProp/SetProp with a collection.
    I'm not completely sure why you would need subclassing data across sessions though?
    Last edited by DEXWERX; Mar 27th, 2018 at 01:15 PM.

  15. #15
    PowerPoster
    Join Date
    Feb 2017
    Posts
    5,466

    Re: About DEXWERX's subclassing dll

    Quote Originally Posted by DEXWERX View Post
    I'm not completely sure why you would need subclassing data across sessions though?
    Hummm, I don't remember now why I thought it was a better idea to keep it when I did it (many years ago). And I could have been wrong.
    It would take to analyze what happens with both options when attaching the same message for the same window from two program instances. An unlikely case anyway, because it would take to subclass a window of other process.

  16. #16
    PowerPoster
    Join Date
    Jun 2012
    Posts
    2,557

    Re: About DEXWERX's subclassing dll

    Quote Originally Posted by Elroy View Post
    What's quite interesting is that, when subclassing, the subclassed procedure will still execute even after you've pressed the stop button. Therefore, you still get a chance to un-subclass stuff. The instant you hit "Stop", all objects are uninstantiated and all global, module, & static variables are set to zero. But code can still get executed even after that. With that knowledge, we can become partially IDE safe, without any thunks or DLLs. So maybe "Pause", "Stop", "End", & "Debug" in your table get a 1/2 asterisk for ComCtl.
    Agree. The thunk used in my projects to handle Stop is primarily for VTable unsubclassing. The normal comctl32 subclass would survive even without that handler.

  17. #17
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,840

    Re: About DEXWERX's subclassing dll

    Quote Originally Posted by DEXWERX View Post
    I have no issue? Thunks work fine for most of us, heck wqweto puts whole libraries into thunks )
    And compilers! . . . LOL

    cheers,
    </wqw>

  18. #18
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    10,791

    Re: About DEXWERX's subclassing dll

    For the most part, I've got no issue with thunks either. My primary concern is that it's just been quite a while since I've been involved in any assembler project. In fact, to be honest, the last time I really felt totally on-top of an assembly project, it was with 8080 code. The last time I really wrote a program in assembler was 2004. Here it is. There were several projects before that one, but they're all long gone.

    So, I suppose the main reason I'm a bit leary of thunks is that I'm not up-to-speed on totally thinking them through, the way I am with VB6 code. In itself, that's not a reason to never use them. But there is a certain satisfaction in being able to "think through" all the code you're using (other than the core Windows and VB6 libraries).

    I will say one last thing about them though. When I see a thunk, I sure do appreciate it when someone takes the time to comment each machine instruction with its corresponding assembly code, along with what they're doing. Just a bunch of hex shoved into a string (or byte array) and then patched into my memory always makes me a bit nervous.

    Best Regards,
    Elroy
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

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

    Re: About DEXWERX's subclassing dll

    Quote Originally Posted by Elroy View Post
    I will say one last thing about them though. When I see a thunk, I sure do appreciate it when someone takes the time to comment each machine instruction with its corresponding assembly code, along with what they're doing. Just a bunch of hex shoved into a string (or byte array) and then patched into my memory always makes me a bit nervous.
    I hear ya, especially the last sentence. Reason why I try to remember to include the raw uncompiled source (with comments) in any project I post that uses thunks I've created/modified.
    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}

  20. #20

    Thread Starter
    PowerPoster
    Join Date
    Sep 2012
    Posts
    2,083

    Re: About DEXWERX's subclassing dll

    This discussion is very useful, thanks to everyone. Thanks to Dexwerx's chart, it's wonderful.

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

    Re: About DEXWERX's subclassing dll

    One thing not really discussed... For a typical exe project, the type of subclassing is only important during design IMO. This helps prevent crashing during development. Once it works and debugged, it should work regardless of the method chosen.
    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}

  22. #22

    Thread Starter
    PowerPoster
    Join Date
    Sep 2012
    Posts
    2,083

    Re: About DEXWERX's subclassing dll

    Quote Originally Posted by LaVolpe View Post
    One thing not really discussed... For a typical exe project, the type of subclassing is only important during design IMO. This helps prevent crashing during development. Once it works and debugged, it should work regardless of the method chosen.
    Yes, subclassing cannot be absolutely safe in VB6-IDE. Is subclassing absolutely safe in VC6-IDE? How does .NET handle subclassing and hooking?

  23. #23
    PowerPoster
    Join Date
    Jun 2015
    Posts
    2,229

    Re: About DEXWERX's subclassing dll

    Quote Originally Posted by dreammanor View Post
    Yes, subclassing cannot be absolutely safe in VB6-IDE.
    I should stop calling my subclasser bullet proof

  24. #24
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,840

    Re: About DEXWERX's subclassing dll

    Quote Originally Posted by dreammanor View Post
    Is subclassing absolutely safe in VC6-IDE?
    Yes, because the debugging session is out-of-process *and* target process message pump is paused.

    Both of these are different in VB6 IDE but then while in break mode in VB6 IDE you get the forms behind being redrawn as needed.

    cheers,
    </wqw>

  25. #25

    Thread Starter
    PowerPoster
    Join Date
    Sep 2012
    Posts
    2,083

    Re: About DEXWERX's subclassing dll

    Quote Originally Posted by DEXWERX View Post
    I should stop calling my subclasser bullet proof
    Sometimes we need to find the best in imperfections. Sometimes imperfections are perfect. Your lib is great, thank you, DEXWERX.

    Quote Originally Posted by wqweto View Post
    Yes, because the debugging session is out-of-process *and* target process message pump is paused.

    Both of these are different in VB6 IDE but then while in break mode in VB6 IDE you get the forms behind being redrawn as needed.

    cheers,
    </wqw>
    Thank you, wqweto.

  26. #26
    Member
    Join Date
    Mar 2022
    Posts
    56

    Re: About DEXWERX's subclassing dll

    Quote Originally Posted by Eduardo- View Post
    Hi,

    One problem that I found is that sometimes (generally after many program crashes) the SetProp/GetProp database can get full and doesn't work anymore (I found that when used SSubTmr6.dll).

    This is an interesting read... I'm not sure I understand everything, but what I *do* understand is that I have a large program that has lots of SGrid2 (from vbAccelerator) and that this control, and most all others from vbAccelerator, use SSubTmr6.

    It doesn't take very long for heavy users to run into the problem that they have to reboot the computer (or logout/login) in order to run it again. I'm not sure if this is a "leak" of sorts, or because of the SetProp/GetProp database that you reference.

    If it's the latter, is there someone that can post *HOW* to fix these vbAcc controls? I have all the source from days gone by..

    Thanks!!

  27. #27
    PowerPoster
    Join Date
    Jan 2020
    Posts
    5,090

    Re: About DEXWERX's subclassing dll

    Quote Originally Posted by BooksRUs View Post
    This is an interesting read... I'm not sure I understand everything, but what I *do* understand is that I have a large program that has lots of SGrid2 (from vbAccelerator) and that this control, and most all others from vbAccelerator, use SSubTmr6.

    It doesn't take very long for heavy users to run into the problem that they have to reboot the computer (or logout/login) in order to run it again. I'm not sure if this is a "leak" of sorts, or because of the SetProp/GetProp database that you reference.

    If it's the latter, is there someone that can post *HOW* to fix these vbAcc controls? I have all the source from days gone by..

    Thanks!!
    you need upload full sample ,what happend?

  28. #28
    Member
    Join Date
    Mar 2022
    Posts
    56

    Re: About DEXWERX's subclassing dll

    Quote Originally Posted by xiaoyao View Post
    you need upload full sample ,what happend?
    Thanks for the response!

    I'm not sure what you want me to upload? I can upload an old version of vbAccelerator source code, if necessary, but it's the same that would be available elsewhere on the internet.

    After reading through the discussion, I thought the inner workings of SSubTmr6.dll were "well known" by the other participants. I was hoping someone has taken the original SSubTmr6 code and fixed it so this type of subclassing wouldn't cause the system problems noted in the original response:

    Quote Originally Posted by Eduardo- View Post
    One problem that I found is that sometimes (generally after many program crashes) the SetProp/GetProp database can get full and doesn't work anymore (I found that when used SSubTmr6.dll).

  29. #29
    PowerPoster
    Join Date
    Jun 2015
    Posts
    2,229

    Re: About DEXWERX's subclassing dll

    MSubclassDebugging.bas as posted on my github

    VB6 Code:
    1. Attribute VB_Name = "MSubclass"
    2. ' Copyright © 2017 Dexter Freivald. All Rights Reserved. DEXWERX.COM
    3. '
    4. ' MSubclassDebugging.bas
    5. '
    6. ' Subclassing Routines
    7. '   - Dependancies: ISubclass.cls or VB6.tlb
    8. '   - STOP/END/PAUSE works when compiled unlike DbgWProc.dll (Curland)
    9. '   - Multiple Subclassing of the same window
    10. '   - Adapted from HookXP by Karl E. Peterson - [url]http://vb.mvps.org/samples/HookXP/[/url]
    11. '   - No SetProp/GetProp Bugs like SubTimer.dll(McKinney), SSubTmr6.dll(McMahon)
    12. '   - No DEP issues or Assembly Thunks PushParamThunk(Curland) / SelfSub(Caton)
    13. '   - No UserObject leaks [url]http://stackoverflow.com/questions/1120337/setwindowsubclass-is-leaking-user-objects[/url]
    14. '
    15. Option Explicit
    16.  
    17. Private Enum VbDebugMode
    18.     vbStopped
    19.     vbRunning
    20.     vbBreak
    21. #If False Then
    22.     Dim vbStopped, vbRunning, vbBreak
    23. #End If
    24. End Enum
    25.  
    26. Private Declare Function GetModuleHandle Lib "kernel32" Alias "GetModuleHandleW" (ByVal lpModuleName As Long) As Long
    27. Private Declare Function SetWindowSubclass Lib "comctl32" Alias "#410" (ByVal hWnd As Long, ByVal pfnSubclass As Long, ByVal uIdSubclass As Long, ByVal dwRefData As Long) As Long
    28. Private Declare Function RemoveWindowSubclass Lib "comctl32" Alias "#412" (ByVal hWnd As Long, ByVal pfnSubclass As Long, ByVal uIdSubclass As Long) As Long
    29. Public Declare Function DefSubclassProc Lib "comctl32" Alias "#413" (ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    30. Private Declare Function EbMode Lib "vba6" () As Long
    31. Private Declare Function EbIsResetting Lib "vba6" () As Long
    32.  
    33. Private Function InIDE() As Boolean
    34. ' InIDE will only return true if we have the VB's IDE DLL loaded
    35.     Static Init As Boolean, InIDE_ As Boolean
    36.     If Not Init Then
    37.         Init = True
    38.         InIDE_ = GetModuleHandle(StrPtr("vba6"))
    39.     End If
    40.     InIDE = InIDE_
    41. End Function
    42.  
    43. Public Function SetSubclass(ByVal hWnd As Long, ByVal This As ISubclass, Optional ByVal dwRefData As Long) As Long
    44.     SetSubclass = SetWindowSubclass(hWnd, AddressOf MSubclass.SubclassProc, ObjPtr(This), dwRefData)
    45. End Function
    46.  
    47. Public Function RemoveSubclass(ByVal hWnd As Long, ByVal This As ISubclass) As Long
    48.     RemoveSubclass = RemoveWindowSubclass(hWnd, AddressOf MSubclass.SubclassProc, ObjPtr(This))
    49. End Function
    50.  
    51. Private Function SubclassProc(ByVal hWnd As Long, _
    52.                               ByVal uMsg As Long, _
    53.                               ByVal wParam As Long, _
    54.                               ByVal lParam As Long, _
    55.                               ByVal uIdSubclass As ISubclass, _
    56.                               ByVal dwRefData As Long _
    57.                               ) As Long
    58.    
    59.     Const WM_NCDESTROY As Long = &H82&
    60.    
    61.     If uMsg = WM_NCDESTROY Then
    62.         ' We still pass WM_NCDESTROY to the subclass proc, before removing ourselves
    63.         SubclassProc = uIdSubclass.SubclassProc(hWnd, uMsg, wParam, lParam, dwRefData)
    64.         RemoveSubclass hWnd, uIdSubclass
    65.         'SubclassProc = DefSubclassProc(hWnd, uMsg, wParam, lParam)
    66.         Exit Function
    67.     End If
    68.    
    69.     If Not InIDE() Then
    70.         SubclassProc = uIdSubclass.SubclassProc(hWnd, uMsg, wParam, lParam, dwRefData)
    71.     Else
    72.         If EbIsResetting() Then
    73.             RemoveSubclass hWnd, uIdSubclass
    74.         Else
    75.             Select Case EbMode()
    76.            
    77.                 Case vbStopped
    78.                     RemoveSubclass hWnd, uIdSubclass
    79.                    
    80.                 Case vbRunning
    81.                     ' An unhandled exception here will take down the IDE...
    82.                     ' This happens when ebProjectReset (Stop/End) is called
    83.                     ' during a Break (Pause) in the subclassing procedure,
    84.                     ' or when attempting to forward to an invalid ISubclass
    85.                     On Error Resume Next
    86.                     SubclassProc = uIdSubclass.SubclassProc(hWnd, uMsg, wParam, lParam, dwRefData)
    87.                     If Err Then RemoveSubclass hWnd, uIdSubclass
    88.                     On Error GoTo 0
    89.                     Exit Function
    90.                    
    91.                 Case vbBreak
    92.            
    93.             End Select
    94.         End If
    95.        
    96.         SubclassProc = DefSubclassProc(hWnd, uMsg, wParam, lParam)
    97.     End If
    98. End Function

  30. #30
    Member
    Join Date
    Mar 2022
    Posts
    56

    Re: About DEXWERX's subclassing dll

    Quote Originally Posted by DEXWERX View Post
    MSubclassDebugging.bas as posted on my github
    Appreciate the code... I hate to sound dumb, but I really don't know where to inject this code.

    I don't mind doing any/all the work to fix and test these controls, but I need a little more direction on how to accomplish this.

    Do I somehow remove the SSubTmr6.dll references at the lowest level and replace the code with this .BAS file?

    Thanks for any help!

  31. #31
    PowerPoster
    Join Date
    Jun 2015
    Posts
    2,229

    Re: About DEXWERX's subclassing dll

    Quote Originally Posted by BooksRUs View Post
    Appreciate the code... I hate to sound dumb, but I really don't know where to inject this code.

    I don't mind doing any/all the work to fix and test these controls, but I need a little more direction on how to accomplish this.

    Do I somehow remove the SSubTmr6.dll references at the lowest level and replace the code with this .BAS file?

    Thanks for any help!
    No worries - my post is out of context from yours, and is just a piece of puzzle if you want to build my subclassing dll from source.
    The function calls I used are more general than ssubtmr, so it definitely wouldn't be a 1-1 replacement.

    Lazy example of using vbsubclass.dll in a form. I think I rely on the dll to catch tear down.
    Code:
    Private Sub Form_Load()
        Subclasser.SetSubclass hWnd, Me
    End Sub
    
    Private Function ISubclass_SubclassProc(ByVal hWnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long, ByVal dwRefData As Long) As Long
        Const WM_CLOSE As Long = &H10
        Const WM_SETCURSOR As Long = &H20
    '    Static lmsg As Long
    '    Select Case uMsg
    '        Case WM_SETCURSOR
    '            If Form7.Visible And AnyMouseButtonIsDown Then
    '                PostMessage Form7.hWnd, WM_CLOSE, 0, 0
    '                ISubclass_SubclassProc = 1
    '                Exit Function
    '            End If
    '    End Select
        ISubclass_SubclassProc = DefSubclassProc(hWnd, uMsg, wParam, lParam)
    End Function
    Last edited by DEXWERX; Mar 25th, 2025 at 02:27 PM.

  32. #32
    Member
    Join Date
    Mar 2022
    Posts
    56

    Re: About DEXWERX's subclassing dll

    Quote Originally Posted by DEXWERX View Post
    No worries - my post is out of context from yours, and is just a piece of puzzle if you want to build my subclassing dll from source.
    The function calls I used are more general than ssubtmr, so it definitely wouldn't be a 1-1 replacement.
    If you, or anyone else, wants to figure out a way to make this happen, I'm all in. I have made some really low-level changes to the SGrid for my internal use. But, the vbAccelerator controls are all based on the SSubTmr6.dll.

    Let me know where to go from here.

  33. #33
    PowerPoster
    Join Date
    Jun 2015
    Posts
    2,229

    Re: About DEXWERX's subclassing dll

    Quote Originally Posted by BooksRUs View Post
    If you, or anyone else, wants to figure out a way to make this happen, I'm all in. I have made some really low-level changes to the SGrid for my internal use. But, the vbAccelerator controls are all based on the SSubTmr6.dll.

    Let me know where to go from here.
    ssubtmr6 removes you from program flow of the SubclassProc so you'd have to recode the handlers to include calling DefSubclassProc depending on if you set emrPreprocess / postproess.

    If you have an example that would help.

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