dcsimg
Results 1 to 38 of 38

Thread: [vb6] IDE-Safety Thunks: A new breed

  1. #1

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    18,652

    [vb6] IDE-Safety Thunks: A new breed

    Updated 3 April 2020. No change to the test project. Updated clsThunks & documentation provided in separate download

    Attached project is something I've been thinking about for a couple years, just never found the time to put it together.

    Disclaimer. This is not compatible with VBA (i.e., Office modules).

    The suite of thunks included in the sample project are wrapped in VB COM objects. This means that the thunks have properties and methods exposed just like any VB object. Granted, the object methods are late-bound vs. early-bound and can be made early-bound with use of wrappers. See next posting below for download of sample wrappers.

    The documentation for each thunk and more is included with the attached Readme files. Those files are important for you to download if you want to play with the thunks outside of the sample projects. Also included are the NASM scripts used to compile the thunks and directions on how to compile them if you want to manipulate the scripts.

    What is a thunk? It is simply executable code placed in process memory, unknown to VB. Typically, thunks are used to enhance VB in one way or another beyond what can be done within VB and without using an external DLL. Thunks are not scary if you have the source code and can verify what is being done. I don't expect everyone to know how to read assembly; therefore, every thunk source is heavily commented so that anyone could follow the logic and see there is nothing malicious.

    Thunks included, along with a brief description:

    1) Subclassing. Uses the common controls subclassing library. The thunk can subclass multiple hWnds simultaneously.

    2) Hooks. Windows offers various hooks, i.e., keyboard, mouse, CBT and more. A sample project shows how subclassing and hooking are used together to create owner-drawn VB comboboxes.

    3) Timer. Probably of little use, but provided anyway. The only real advantage of a thunk timer is the ability to add it to a VB class and extended interval values.

    4) Custom Window Classes. For those of you that are API-nuts and like to create pure or semi-pure custom windows, the thunk helps manage the class procedure.

    5) Callbacks. Both standard Windows (stdCall) and C-style (cDecl) formats are supported. A sample project shows both.

    6) COM object hooks. Ability to hook/subclass a COM object, either one exposed by VB or a VTable-only interface. An example shows how to subclass the stdPicture object to hook its rendering.

    7) GDI+ token/handle management. Ensures GDI+ is shut down properly and GDI+ handles are destroyed even if the IDE is terminated unexpectedly. Sample included in using GDI+ to load and display a PNG inside of a VB image control and animating a GIF.

    8) API caller. This thunk ensures one or more APIs are called after the project unloads, regardless of how it is unloaded. Such a thunk can be used to ensure objects created with GDI or files opened with CreateFile APIs are destroyed/released. This thunk also enables CDecl APIs to be called on demand.

    9) VTable caller. Similar to DispCallFunc API, the thunk enables calling methods directly to a VTable-only interface.

    Name:  SShot.png
Views: 631
Size:  90.6 KB

    Each thunk type is included in the sample projects. Also included is a sample to allow you to attempt to crash the IDE due to "End" statements. There may be a scenario that includes various levels of usercontrols, but haven't discovered one yet that crashes the IDE due to "End". If you discover a scenario, let me know so I can find a workaround as needed.

    The key to strong resistance to crashing is the fact that the thunk is a COM object. By being one, VB will always unload it. Since it knows it is being unloaded, it can manage its own destruction, including its own clean-up and removal from process memory. The ReadMe files have far more details and information.

    Code:
    Update History
     5 Apr: updated documentation only. Resolved mislabeling of functions as properties/subs and vice versa
     3 Apr 2020: modified thunks to accept optional TLB VTable-only interfaces. Minor tweaks.
     3 Sep: re-upload. Failed to parse thunk 4-byte blocks with values of zero. Needed to include 
             them as it is possible their memory can be allocated with junk if not overwritten.
     1 Sep: Complete revision
        - uses private heap vs VirtualAlloc for thunks, overall memory reduction
        - includes two new thunks: APICaller and VTableCaller thunks
        - documentation completely redone, each thunk has its own readme file
        - thunks can be optionally used with wrappers for early-bound, intellisense capability
    22 Jun: Enhancements
        - replaced COM hook thunk with another that can hook multiple objects vs. just one
        - added a new thunk to help make GDI+ IDE-safe and added a sample of its usage
        - by request, increased default max method count expected in any VB code page to 700
        - other minor enhancements/changes made
     3 Jun: Bug reported when compiled. Fixed (see post #4)
     2 Jun 2019: initial release
    Note: In the future any changes to the clsThunk class will be attached separately. Will not repost the test project unless I change something in it. If the class is a separate attachment, it should be used in place of the one in the test project.
    Attached Files Attached Files
    Last edited by LaVolpe; Today at 06:15 PM. Reason: updated thunks
    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}

  2. #2

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    18,652

    Re: [vb6] Thunks - A new breed

    I'll reserve this section for tips & such...

    FYI: Included here are sample wrappers for each thunk. Wrappers enable intellisense on the late-bound thunk objects. At the top of each wrapper class are the simple instructions for using them: Wrappers.zip

    FYI: All thunks except the generic callback, COM hooking and VTable caller thunks know how many parameters and the size of the parameters that are required. With those other three, the thunk needs to be told when it is created or called because they are unknown at that point. The parameter count is straightforward, but the sizes of each are not. So, the creation routines expect you to provide the number of total DWords (4 bytes) for all parameters. All parameters will use minimum of 1 DWord each. Even if the parameter is just a Byte or Integer. This is because parameters are promoted to DWords in x86 assembly stdCall/cDecl. Basically, this means in most cases, the number of DWords required for all parameters is the same as the parameter count. However, with COM, a single parameter may require 2 or more DWords (i.e., LongLong, Currency, etc). This FYI is just meant to help you better understand what is required, relative to DWord parameter sizes. The readme files for those specific thunks detail more information.

    Tip. The GDI+ thunk creates tasker objects that have just a few properties, one of them being HandleByRef. That property is provided for convenience when creating handles via GDI+ API calls. But use caution. Simply referencing that property will destroy any handle already being managed by the tasker, by design, before it returns. If you are using that property, then you will be replacing its current value; hence the destruction. So don't Debug.Print it out. Its value is meaningless to you, it is just a memory location where the Handle is stored.
    Code:
    ' using the HandleByRef property as a convenience
    
    GdipCreateFromHDC hDC, ByVal oTasker.HandleByRef
    ' If you: Debug.Print oTasker.HandleByRef then you just destroyed the handle
    
    ' without using it requires 1 more line of code... 
    
    ' The Handle property only destroys existing handles when 
    ' a new handle is assigned to the tasker. So you can Debug.Print it out
    GdipCreateFromHDC hDC, hGraphics
    oTasker.Handle = hGraphics
    Tip: When wanting to hook stdPictures to draw PNGs inside of image controls, a transparent icon is useful as a placeholder inside the image control. The image control needs something assigned to it in order for VB to have it redraw as needed. We need that so we can intercept and draw our PNG instead. Attached here is a 100% transparent icon: blank.zip. Also, a sub-tip of sorts... make Image1.Stretch=True

    Tip: The pvGetAddressOf routine is hardcoded to search up to 700 methods of any host. If you have more than 700 in your host (form, class, whatever), then you will need to up that limit. In that routine, there is a constant that dictates the size limit.
    Last edited by LaVolpe; Yesterday at 11:48 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}

  3. #3
    Addicted Member
    Join Date
    Jun 2016
    Location
    Espaņa
    Posts
    134

    Re: [vb6] Thunks - A new breed

    very good project keeps improving it.
    I have not had much time to do tests.
    but I had the following problem, with the project compiled in the first two examples when it closes its window closes everything, in the ide no.

    a greeting and forgiveness for the language

  4. #4

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    18,652

    Re: [vb6] Thunks - A new breed

    @yokesee. I see what you are describing. I'll have to look at my subclassing thunk, something is wrong with the suicide timer procedure when compiled. Thank you for pointing it out. I'll upload the patched thunk soon.

    P.S. Same problem will be with the last example.

    Follow-up. Patched & re-uploaded. Problem was that I was using edi register but failed to preserve it beforehand which is a no-no and an oversight on my part. Unfortunately, the same logic was used in every thunk (copy & paste). So every thunk was modified to address the problem. Thanx again yokesee
    Last edited by LaVolpe; Jun 3rd, 2019 at 08:50 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}

  5. #5
    Frenzied Member
    Join Date
    Dec 2008
    Posts
    1,287

    Re: [vb6] Thunks - A new breed

    If us XP users thunk this would work in XP
    Would we be thunking wrong ?

  6. #6

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    18,652

    Re: [vb6] Thunks - A new breed

    Quote Originally Posted by Bobbles View Post
    If us XP users thunk this would work in XP
    Would we be thunking wrong ?
    No, you'd be thunking correct.

    The subclassing thunk actually checks for the common controls library exporting needed APIs by ordinal, which XP did. However, I did not test it on XP. If you do play around and it works, feedback is encouraged for others. If it has problems, would like to know that too.
    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}

  7. #7
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    2,442

    Re: [vb6] Thunks - A new breed

    4) Custom Window Classes. For those of you that are API-nuts and like to create pure or semi-pure custom windows, the thunk helps manage the class procedure.
    Baby you're singing my song

    Tip: The pvGetAddressOf routine is hardcoded to only search up to 256 methods of any host. If you have more than 256 in your host (form, class, whatever), then you will need to up that limit. In that routine, look for the value 1024. That is equal to 256*4. Increase it to a max number of methods your host could possibly have, multiplied by 4.
    What? That's crazy talk, who would ever have a class with more than 256 methods??? Or even more impossible, needing to up it above the 512 limit that was in the old one


    ---
    Great work, can't wait to check it all out.

  8. #8
    Frenzied Member wqweto's Avatar
    Join Date
    May 2011
    Posts
    1,809

    Re: [vb6] Thunks - A new breed

    Quote Originally Posted by fafalone View Post
    What? That's crazy talk, who would ever have a class with more than 256 methods???
    You already have 400-450 methods in default IDispatch vtbl "inherited" from VB's form/usercontrol base implementation. Of these significat percent are empty/dummy slots carried from legacy (VB3?) versions of the base classes but if not taken care of these use-cases explicitly, probing only first 256 methods might turn out insufficient.

    cheers,
    </wqw>

  9. #9

  10. #10
    Frenzied Member wqweto's Avatar
    Join Date
    May 2011
    Posts
    1,809

    Re: [vb6] Thunks - A new breed

    Quote Originally Posted by fafalone View Post
    The joke was that this exact problem happened, because my shell browser UC has over 512 methods just in the .ctl file
    Ouch! :-))

    cheers,
    </wqw>

  11. #11
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    2,442

    Re: [vb6] Thunks - A new breed

    Yeah it's a little crazy, Sub+Function+Property totals 797 right now

    LaVolpe, I'd even suggest retaining the default of 512; I've seen a number of UserControls that would exceed 256 (UC's being particularly vulnerable because of the desire to self-contain them and property let/gets running up the count).

  12. #12

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    18,652

    Re: [vb6] Thunks - A new breed

    Quote Originally Posted by fafalone View Post
    LaVolpe, I'd even suggest retaining the default of 512; I've seen a number of UserControls that would exceed 256 (UC's being particularly vulnerable because of the desire to self-contain them and property let/gets running up the count).
    Will consider it when I update the project. The newest version (on my pc only) uses a constant so it is easier to change for any individual user, as needed. The original intent of the limit imposed by Paul Caton was because he didn't provide a starting point for parsing VTables except for classes. And as mentioned, forms can be quite large, but so are UCs & property pages. I'm not sure it is even worthwhile any longer since I've added those offsets, but I haven't played with the various Designer VTables.

    BTW, the reason for the newest version is a multi-COM object thunk, otherwise, I might just be done with this project barring bugs.
    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}

  13. #13

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    18,652

    Re: [vb6] Thunks - A new breed

    Updated the project with enhancements and to correct some minor code flaws. The _ReadMe file is updated to address new thunks and any other pertinent information that changed.

    Major enhancements include the replacement of the COM hook thunk with a new one that can be used to hook multiple objects on the same thunk or a slightly smaller one used for single object hooking. Also included is a new GDI+ thunk that will ensure GDI+ and and handles it is managing are shut down/released even if the IDE is terminated with an End action.
    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}

  14. #14

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    18,652

    Re: [vb6] IDE-Safety Thunks: A new breed

    Looking at posting one more update, really a revision. That will remove most compatibility with this project.

    I'm leaning towards revamping how the thunks are created. Currently, they are created one thunk at a time as needed. Each thunk instance uses its own reserved memory. Let's say one thunk uses 2K memory and you wanted 5 of them: 10K total. The route I'm thinking about will use reserved memory just once for a "Factory" thunk. The factory creates/spawns worker objects as requested. Each worker object will use about 32 bytes (not a typo). So if a Factory uses 2K, you can create 10 workers that only use about 320 bytes more. The COM hook thunk will be the exception and will remain mostly as is since it doesn't fit well into my Factory theme.

    Also going to include one new thunk. For time being, calling it APIcaller. The gist is that you can assign an API to it, along with parameters and have it call that API when the worker is released. This can help reduce memory leaks and possible crashing when IDE is terminated unexpectedly, i.e., "End". Let's say you are using APIs to load files and want to ensure the file handle is freed on termination. That APIcaller worker is setup like:
    Code:
    oWorker.SetAPIcall "kernel32.dll", "CloseHandle", m_MyFileHandle
    The worker can contain a batch call, of sorts too, if more than one action needs to be taken in a specific order:
    Code:
    oWorker.SetAPIcall "kernel32.dll", "UnmapViewOfFile", m_MyView
    oWorker.SetAPIcall "kernel32.dll", "CloseHandle", m_MyFileHandle
    
    ' another example
    oWorker.SetAPIcall "gdi32.dll", "SelectObject", Array(m_Hdc, m_OrigBmp)
    oWorker.SetAPIcall "gdi32.dll", "DeleteObject", m_Bitmap
    oWorker.SetAPIcall "gdi32.dll", "DeleteDC", m_Hdc
    The worker will be able to accept multiple parameters also...
    Code:
    oWorker.SetAPIcall "kernel32.dll", "VirtualFree", Array(m_MemAddr, 0, MEM_RELEASE)
    The idea is that the worker is setup very similar to how an API declaration is setup -- with some restrictions. It usage would typically contain stuff that is declared at class/form level that should be cleaned up in the unload/terminate event which won't happen if IDE terminates with "End"
    Last edited by LaVolpe; Jun 25th, 2019 at 09: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}

  15. #15
    Frenzied Member wqweto's Avatar
    Join Date
    May 2011
    Posts
    1,809

    Re: [vb6] IDE-Safety Thunks: A new breed

    Quote Originally Posted by LaVolpe View Post
    Each worker object will use about 32 bytes (not a typo).
    MST thunks CoTaskMemAlloc between 16 and 24 bytes per COM object and their respective executable thunk code + vtable is VirtualAlloc'd once per process no matter if needed by self-contained thunks or by global module impl. Code address is shared through environment variables named "_MST_GLOBAL" & App.hInstance & "_" & sKey which is a bit awkward.

    cheers,
    </wqw>

  16. #16

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    18,652

    Re: [vb6] IDE-Safety Thunks: A new breed

    @wqweto. My factory approach appears similar to yours. A factory shares its thunk with any workers it spawns/workers (both being Com objects). The 2 VTables (factory/worker) are also included in the thunk. The workers currently use up to 28 bytes each. The factory object uses more, however only one instance of it is ever created. I could have opted to include much of the factory object data into the top/bottom of the thunk but chose against it and kept it with the Com object instead. A few different ways to skin that cat.

    I have a slightly different approach to shared data/variables. Each worker has the address of the factory's object data. The worker's object data contains only per-instance variables. When a worker needs to access the shared data, it gets it from known offsets off the factory's object. These offsets are constants within the thunk.

    The only thunk I have in this project, right now, that uses a factory approach is the GDI+ thunk. But I like it a lot and will convert all, except the COM-hook thunk, to factory/worker themes also.
    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}

  17. #17
    Frenzied Member wqweto's Avatar
    Join Date
    May 2011
    Posts
    1,809

    Re: [vb6] IDE-Safety Thunks: A new breed

    Yes, the GDI+ thunk has a lot of potential.

    I'm considering impl DISPID_VALUE get/let on my cleanup thunk too (which is a whole new IDispatch interface). Will come handy for such use-cases, provided that performance testing graphics intensive routines does not foil the effort.

    I'm very glad to see your alternative impl with new ideas and more use-cases.

    cheers,
    </wqw>

  18. #18

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    18,652

    Re: [vb6] IDE-Safety Thunks: A new breed

    Project and thunks have been completely rewritten. In short, the thunks now use a shared private heap that can significantly reduce overall memory usage when multiple thunks and taskers are used simultaneously. In addition, I've used a "class factory" approach. Each time a tasker is created, if it is the first tasker of its category (9 categories currently), then the factory is created along with the tasker. As each new tasker is created of the same category, that tasker uses the same thunk. Every thunk has been designed this way, regardless of past comments where I said there could/would be exceptions.

    Also included with this update are more detailed documentation and two additional thunks. See first post at top of thread.

    Also included are optional wrappers. The wrappers can be found in post #2 above. Wrappers enable early-bound method calling, intellisense capable.

    This revision is completely incompatible with the previous. Do not overwrite your previous download if you still want that.
    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}

  19. #19

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    18,652

    Re: [vb6] IDE-Safety Thunks: A new breed

    One more try - a big blunder on my part. You may not have experienced the problem, but not worth the risk. Project is uploaded once again.

    Problem: I changed the way I allocated and overwrote memory allocations to speed up thunk creation (efficiency tweak). In doing so, the thunk allocations were no longer guaranteed to be zeroized. That means I need to overwrite the 4-byte blocks that would otherwise contain the value zero. I failed to include those blocks. That means if Windows gave me the allocation with junk in it (not zeroized), then the junk for those blocks remained.

    Solution: Simply include z_Sc() statements that have a value of zero instead of not including them. Did that & reposted.
    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
    New Member
    Join Date
    Aug 2019
    Posts
    10

    Re: [vb6] IDE-Safety Thunks: A new breed

    Hi LaVolpe, thanks for this great project.
    I tried to do some improvements to your project.

    the changes i made are in 4 steps

    step 1: mostly cosmetic and a few overflow bug fixes in pointer math.
    step 2: created a typelib and added VBVM6Lib functions and replaced all possible thunkCopyMemory to their VBVM6Lib equivalent.
    step 3: moved all API declaration to typelib and fixed calling code if required.
    step 4: created all VTable interfaces in typelib and replaced Object with their equivalent interface.

    now the taskers are early-bound and IDispatch creation is not required,
    but the thunks are trying to free them on cleanup and will crash if IDispatch pointer is zero.

    can you help me on the last part and maybe check if i didn't break anything in your code ?
    Last edited by HosseinMoradi; Oct 26th, 2019 at 04:54 PM.

  21. #21
    New Member
    Join Date
    Aug 2019
    Posts
    10

    Re: [vb6] IDE-Safety Thunks: A new breed

    an update

    in step 1: a missed overflow fix, changed the way locating main window works and used SetSafeArrayPtr instead of VarPtrArray
    in step 2: replaced a few missed CopyMemory
    Last edited by HosseinMoradi; Oct 26th, 2019 at 04:54 PM.

  22. #22
    New Member
    Join Date
    Aug 2019
    Posts
    10

    Re: [vb6] IDE-Safety Thunks: A new breed

    new update

    replaced SetWindowSubclass with InitCommonControls for loading COMCTL32
    replaced hMod Collection with long variable
    replaced SetWindowSubclass Proc checking with GetWindowSubclass

    attached file include:
    "No TLB" version which is improved LaVolpe version with API declaration
    "With TLB" version is the more improved version and will require the TLB

    and the "Test" version that shows the Tasker Object can be replaced with interface from TLB, but i wasn't able to replace the TaskerObject of callback since it passed from Thunk

  23. #23
    New Member
    Join Date
    Aug 2019
    Posts
    10

    Re: [vb6] IDE-Safety Thunks: A new breed

    last update

    just a few small change and replaced If Err Then with If Err.Number Then which is faster


    LaVolpe since i don't know much of assembly, if it's easy can you give me a few point to remove the IDispatch and replaced it with interface in your thunks ?
    Attached Files Attached Files

  24. #24
    New Member
    Join Date
    Aug 2019
    Posts
    10

    Re: [vb6] IDE-Safety Thunks: A new breed

    LaVolpe did you found a time to look at this ?

  25. #25

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    18,652

    Re: [vb6] IDE-Safety Thunks: A new breed

    At first, I'm not sure how you are able to set your TLB interface to the object returned by the thunk functions.

    1. Those functions return an Object supporting IDispatch
    2. Your TLB interfaces do not support IDispatch and have their own GUIDs
    3. When you attempt to set a TLB interface to an existing object, a QueryInterface on that object occurs and tests whether the object supports your GUID. If not, VB will throw an error like, not supported or something similar.

    When QueryInterface is called on an object returned by the thunks class, the thunk logic I used goes something like this:
    1. If asking for IUnknown, then return the object's pointer
    2. If asking for IDispatch, then request is sent to the IDispatch itself for processing
    3. Any other scenario, like your TLB GUIDs, the thunk returns E_NOINTERFACE which should generate a VB error.

    Since your TLB interfaces fall into the 3rd scenario above, the thunk should reject your request & VB should error. You are saying that is not the case and that doesn't make sense to me.
    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}

  26. #26
    New Member
    Join Date
    Aug 2019
    Posts
    10

    Re: [vb6] IDE-Safety Thunks: A new breed

    Quote Originally Posted by LaVolpe View Post
    At first, I'm not sure how you are able to set your TLB interface to the object returned by the thunk functions.
    i don't set it, i just return the object pointer as TLB interface type, since it's an interface describing your VTable.
    in the attached example you can see that.

    now i can remove the IDispatch and ITypeInfo part but the thunk still expect it, and since i don't understand assembly i can't remove it from the thunk.
    also the thunk has to send the object pointer in TaskerObject variable instead of IDispatch object.
    Attached Files Attached Files

  27. #27

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    18,652

    Re: [vb6] IDE-Safety Thunks: A new breed

    Well, got good news & bad news. Bad news first. Attempting to modify the ASM would snowball into significant more work. Offsets within the compiled ASM would change, requiring the data in the clsThunks methods to be rewritten.

    Good news next. Allow the object to be created, including the IDispatch. However, creative use of CopyMemory can get what you want with only 3 modifications per tasker creation method.

    Important: In the sample code below, I'm using my original clsThunks, not the one you modified. But it is using your TLB. You are familiar with my original class but I'm not familiar with all your modifications, so defaulting to my class is common ground.

    Using the 1st project sample (subclass and hook), make these changes:
    1. In frmSample1
    -- no changes from your version of the form, leave oSubClasser As ITskrSubclass & oHook As ITskrWinHook

    2. In clsThunks.CreateTasker_Hook, make these changes
    -- change my original method to return ITskrWinHook
    Code:
     replace: Set CreateTasker_Hook = oIUnk 
     with these 2 lines:
            thunkCopyMemory CreateTasker_Hook, oIUnk, 4
            thunkCopyMemory oIUnk, 0&, 4
    3. In clsThunks.CreateTasker_Subclass, make these changes
    -- change my original method to return ITskrSubclass
    Code:
     replace: Set CreateTasker_Subclass = oIUnk 
     with these 2 lines:
            thunkCopyMemory CreateTasker_Subclass, oIUnk, 4
            thunkCopyMemory oIUnk, 0&, 4
    Now run the first sample. It should work as you expect. If happy with it, update the other clsThunks tasker methods using the same logic. What we are doing is a bit sneaky. We are creating the IDispatch (no change) and before we leave the tasker creation, we release IDispatch. But before that, we CopyMemory the tasker method's IUnknown onto your TLB tasker. If they have exactly the same methods, same order, same parameters, all should be good -- I'll leave that to you to verify. Now, even though the IDispatch was released, ASM doesn't release code until its IUnknown count decrements to zero. That won't happen until the returned TLB tasker goes out of scope or set to nothing.

    Another bonus besides being an easy tweak is that it appears we keep IDE safety/anti-crashing in tact too. You'll want to test these tweaks compiled also to ensure successful tweaks. The downside to this is that I already have an updated version of this class but have not yet posted it. When I do, your TLB will need to be tweaked a bit, including new GUIDs probably, to use the new class.
    Last edited by LaVolpe; Mar 18th, 2020 at 04:05 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}

  28. #28
    New Member
    Join Date
    Aug 2019
    Posts
    10

    Re: [vb6] IDE-Safety Thunks: A new breed

    Quote Originally Posted by LaVolpe View Post
    Good news next. Allow the object to be created, including the IDispatch. However, creative use of CopyMemory can get what you want with only 3 modifications per tasker creation method.

    Important: In the sample code below, I'm using my original clsThunks, not the one you modified. But it is using your TLB. You are familiar with my original class but I'm not familiar with all your modifications, so defaulting to my class is common ground.

    Using the 1st project sample (subclass and hook), make these changes:
    1. In frmSample1
    -- no changes from your version of the form, leave oSubClasser As ITskrSubclass & oHook As ITskrWinHook

    2. In clsThunks.CreateTasker_Hook, make these changes
    -- change my original method to return ITskrWinHook
    Code:
     replace: Set CreateTasker_Hook = oIUnk 
     with these 2 lines:
            thunkCopyMemory CreateTasker_Hook, oIUnk, 4
            thunkCopyMemory oIUnk, 0&, 4
    3. In clsThunks.CreateTasker_Subclass, make these changes
    -- change my original method to return ITskrSubclass
    Code:
     replace: Set CreateTasker_Subclass = oIUnk 
     with these 2 lines:
            thunkCopyMemory CreateTasker_Subclass, oIUnk, 4
            thunkCopyMemory oIUnk, 0&, 4
    Now run the first sample. It should work as you expect. If happy with it, update the other clsThunks tasker methods using the same logic. What we are doing is a bit sneaky. We are creating the IDispatch (no change) and before we leave the tasker creation, we release IDispatch. But before that, we CopyMemory the tasker method's IUnknown onto your TLB tasker. If they have exactly the same methods, same order, same parameters, all should be good -- I'll leave that to you to verify. Now, even though the IDispatch was released, ASM doesn't release code until its IUnknown count decrements to zero. That won't happen until the returned TLB tasker goes out of scope or set to nothing.

    Another bonus besides being an easy tweak is that it appears we keep IDE safety/anti-crashing in tact too. You'll want to test these tweaks compiled also to ensure successful tweaks.
    well that is basically what i did in the attached test

    i replaced this:
    Code:
    thunkCopyMemory oIUnk, hData, 4             ' create Tasker's IUnknown
    with this:
    Code:
    thunkCopyMemory CreateTasker_Subclass, hData, 4             ' create Tasker's IUnknown
    but the problem with TaskerObject in CallbackProc still remains, the IDispatch is send not the objects VTable.
    so i can't replace TaskerObject As Object with TaskerObject As ITskrSubclass for example.


    Quote Originally Posted by LaVolpe View Post
    Attempting to modify the ASM would snowball into significant more work. Offsets within the compiled ASM would change, requiring the data in the clsThunks methods to be rewritten.
    i have very limited ASM knowledge, can you instruct me to do it ?
    or can't we just NOP the IDispatch part of ASM without changing the Offsets of it ?

    PS:
    WinMerge is very useful, you can easily compare two files and see the changes.

  29. #29

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    18,652

    Re: [vb6] IDE-Safety Thunks: A new breed

    I'll try to answer your question at the end. But first. You said you wanted to create the TLB to make the thunks early-bound, intellisense-capable. Ok, a good exercise I suppose. But you do realize (I think you do), that I added in post #2, sample wrappers to imitate early bound thunks. Also, inside each of those wrappers explains how to modify the callback TaskerObject so it can also use intellisense. I anticipated this type of question.

    Now, to your latest question. Each thunk's ASM, has a routine titled: _GetObject. That routine determines what gets sent as TaskerObject to any callback methods. As currently coded, it is either a custom object you supplied with a call to the thunk object's WrapperObject method or it is the thunk object/IDispatch itself. In any case, it is an object, i.e., IDispatch. Your TLB interfaces do not implement IDispatch. The ASM was written to be owned indirectly by an IDispatch interface that also supports ITypeInfo. The correct answer to your question is: the ASM needs to be reworked to support your VTable-only interfaces, by GUID, and remove all logic that refers to any other interfaces: IDispatch, ITypeInfo.

    Howver, if you do not need to use that parameter in any callbacks (just want to kinda disable it), try adding the host's ObjPtr via WrapperObject method. I see you did not include that method in your TLB. So if you try this, you'll need to set that inside the clsThunks tasker creation methods before they exit.

    I am not volunteering to help you rewrite portions of the ASMs. I gave users a way to imitate/use intellisense in their projects (post #2).
    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}

  30. #30
    Addicted Member
    Join Date
    Jan 2015
    Posts
    201

    Re: [vb6] IDE-Safety Thunks: A new breed

    i use timer thunk in office 2007 x86
    did i use it wrong?
    Code:
    Dim c As ITskrTimer
    
    Private Sub UserForm_Initialize()
        Set c = New ITskrTimer
    End Sub
    
    Private Sub UserForm_Click()
        c.CreateTasker_Timer Me, 1, 1000, True
    End Sub
    
    
    Private Sub UserForm_Terminate()
        c.Pause
        Set c = Nothing
    End Sub
    
    Private Function myTimerProc(ByVal TaskerObject As Object, _
                    ByVal uTickCount As Long) As Long
        Debug.Print uTickCount
    End Function

  31. #31

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    18,652

    Re: [vb6] IDE-Safety Thunks: A new breed

    @loquat. What is ITskerTimer? If it is from my wrappers zip file in post #2, looks ok at first glance -- something wrong? does c return as Nothing? However, I am not saying the IDE safety within the thunks are guaranteed with Office, i.e., VBA. These thunks were designed for VB. IDE safety relies on a known API associated with VB and known code structure of compiled VB code. I do not know whether those knowns apply to VBA. I'd almost want to say, do not make that assumption and opt for no IDE safety if using these thunks in VBA. Otherwise, test it well by purposely placing STOP commands or breakpoints within your VBA code to see how the thunks perform when your code is paused.
    Last edited by LaVolpe; Mar 20th, 2020 at 08:01 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}

  32. #32
    Addicted Member
    Join Date
    Jan 2015
    Posts
    201

    Re: [vb6] IDE-Safety Thunks: A new breed

    Quote Originally Posted by LaVolpe View Post
    @loquat. What is ITskerTimer? If it is from my wrappers zip file in post #2, looks ok at first glance -- something wrong? does c return as Nothing? However, I am not saying the IDE safety within the thunks are guaranteed with Office, i.e., VBA. These thunks were designed for VB. IDE safety relies on a known API associated with VB and known code structure of compiled VB code. I do not know whether those knowns apply to VBA. I'd almost want to say, do not make that assumption and opt for no IDE safety if using these thunks in VBA. Otherwise, test it well by purposely placing STOP commands or breakpoints within your VBA code to see how the thunks perform when your code is paused.
    the ITskerTimer is from yours, as well as clsThunk, and c return Not Nothing
    You guess right, i m using it in vba, it is clearly not working on my office vba environment.

  33. #33
    New Member
    Join Date
    Aug 2019
    Posts
    10

    Re: [vb6] IDE-Safety Thunks: A new breed

    Quote Originally Posted by LaVolpe View Post
    You said you wanted to create the TLB to make the thunks early-bound, intellisense-capable. Ok, a good exercise I suppose. But you do realize (I think you do), that I added in post #2, sample wrappers to imitate early bound thunks. Also, inside each of those wrappers explains how to modify the callback TaskerObject so it can also use intellisense. I anticipated this type of question.
    early-bound, intellisense-capable, faster and smaller.


    first thing, i really appreciate your work, it's very great and i like it very much.
    lately i had to optimize my project for speed and for that, i learned some tricks and habits in coding.
    i reviewed your Thunks to replace my aged Paul Caton Subclass, and saw it can use some of that improvements which mostly involved the TLB.
    i tried to contribute some help so that you implement it in your next version.

    the core of your Thunks is the COM VTable, but to use it in VB you had to create the IDispatch (which is slow and adds to the size of your code), and for creating the IDispatch you had to create the ITypeInfo (which adds to the size of your code), and since IDispatch is not intellisense-capable you created the Wrappers (which again is slow and adds to the size of your code).

    with TLB interfaces you create a shortcut and tell VB how to access the VTable directly, and your Thunks will become early-bound, intellisense-capable, faster and smaller.
    also the APIs declared in TLB are faster and more flexible than VB declare and without the API declare your Thunks will be more portable, also you probably can remove pvInitFactory.


    English is not my native language, sorry if what i said seemed rude or offensive.

  34. #34

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    18,652

    Re: [vb6] IDE-Safety Thunks: A new breed

    Quote Originally Posted by loquat View Post
    You guess right, i m using it in vba, it is clearly not working on my office vba environment.
    I took a closer look. These thunks cannot work with VBA. One of the things the thunks do is to store information on VB's hidden owner window. VBA doesn't have that owner window. I don't plan on making these compatible with VBA. There are other solutions for using timers and thunks with VBA, so you do have options. Thanks for the interest.
    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}

  35. #35

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    18,652

    Re: [vb6] IDE-Safety Thunks: A new breed

    Quote Originally Posted by HosseinMoradi View Post
    English is not my native language, sorry if what i said seemed rude or offensive.
    Nothing you said was offensive. I understand what you are saying. For most cases, late-bound objects are not going to cause any significant code slow-down. About the only exception I can think of is when a late-bound object is used within a lengthy loop. In order to use this with VTable-only TLB interfaces, the ASM will require significant work. Any shortcuts are likely to cause problems.

    P.S. Want speed? Don't use thunks. Use standard subclassing directly within a module. Not IDE safe, but fast.
    Last edited by LaVolpe; Mar 20th, 2020 at 07:33 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}

  36. #36
    Addicted Member
    Join Date
    Jan 2015
    Posts
    201

    Re: [vb6] IDE-Safety Thunks: A new breed

    Quote Originally Posted by LaVolpe View Post
    There are other solutions for using timers and thunks with VBA, so you do have options. Thanks for the interest.
    yes right, such as the trick and paul caton did, and even we can make a timer control for vba by using vb6 timer control

  37. #37
    New Member
    Join Date
    Aug 2019
    Posts
    10

    Re: [vb6] IDE-Safety Thunks: A new breed

    Quote Originally Posted by LaVolpe View Post
    P.S. Want speed? Don't use thunks. Use standard subclassing directly within a module. Not IDE safe, but fast.
    yes but it's a nightmare in developing and debuging.


    Quote Originally Posted by LaVolpe View Post
    In order to use this with VTable-only TLB interfaces, the ASM will require significant work. Any shortcuts are likely to cause problems.
    so keep this in mind for your next major version whenever you have time.


    Quote Originally Posted by LaVolpe View Post
    The downside to this is that I already have an updated version of this class but have not yet posted it. When I do, your TLB will need to be tweaked a bit, including new GUIDs probably, to use the new class.
    when will you post your updated version ?

  38. #38

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    18,652

    Re: [vb6] IDE-Safety Thunks: A new breed

    Quote Originally Posted by HosseinMoradi View Post
    when will you post your updated version ?
    Done. The updates will allow use of TLB VTable-only interfaces. One can use the TLB you provided in post #26 or their own.

    The documentation included in the downloads addresses the ability to use only TLB VTable-only interfaces, completely removing the dynamically created IDispatch and ITypeInfo objects that would be otherwise required. That is FYI for anyone else that may be interested.

    For all. Unless you are going to use TLB interfaces, the update doesn't need to be applied. If your current version is working fine, no need to upgrade. The test project in the downloads did not change, so it wasn't replaced.
    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
  •  



Featured


Click Here to Expand Forum to Full Width