Page 1 of 2 12 LastLast
Results 1 to 40 of 46

Thread: [RESOLVED] Problem with Public UDT: 'Only public user defined types......

  1. #1

    Thread Starter
    Frenzied Member some1uk03's Avatar
    Join Date
    Jun 2006
    Location
    London, UK
    Posts
    1,664

    Resolved [RESOLVED] Problem with Public UDT: 'Only public user defined types......

    Hi Guys, Having a problem with a UDT. I have the following :

    Code:
    Public Type mUdtObjInfo
        A    as string
        B    as string
        C    as string
        D    as string
    End Type
    
    Public Type myInfo
        ObjInfo    as mUdtObjInfo
        PosX       As Integer
        PosY       As Integer
    End Type
    Ok these work fine and are declared in a Module. However, when I try and access/Pass them through a Custom User Control, such as:

    Code:
    Public Function EditCurrent() As myInfo
    EditCurrent = theOne(m_Selected)
    End Function
    I get an error:
    "Only public user defined types defined in public object modules can be used as parameters or return types for public procedures of class modules or as fields of public user defined types"

    I've searched around and have tried Declaring it as a Friend instead of Public, but still no result. I've tried putting all of this in a Class and still same.
    I read that you could get away if you add these in a .TLB or ActiveX/Dll:

    Check this link:

    Any ideas?
    _____________________________________________________________________

    ----If this post has helped you. Please take time to Rate it.
    ----If you've solved your problem, then please mark it as RESOLVED from Thread Tools.



  2. #2
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: Problem with Public UDT: 'Only public user defined types......

    The easiest "fix" is to use Classes instead of UDTs.

    What makes you think you want UDTs for this?

  3. #3

    Thread Starter
    Frenzied Member some1uk03's Avatar
    Join Date
    Jun 2006
    Location
    London, UK
    Posts
    1,664

    Re: Problem with Public UDT: 'Only public user defined types......

    Quote Originally Posted by dilettante View Post
    The easiest "fix" is to use Classes instead of UDTs.

    What makes you think you want UDTs for this?

    I guess UDT's are easier/faster to deal with.
    _____________________________________________________________________

    ----If this post has helped you. Please take time to Rate it.
    ----If you've solved your problem, then please mark it as RESOLVED from Thread Tools.



  4. #4
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: Problem with Public UDT: 'Only public user defined types......

    Oh, ok. I thought maybe you were using them to mimic structs for API calls or something.

    The only way to use UDTs for this is to create and register an ActiveX DLL or TLB defining them. In VB6 it is possible to create such a DLL, but to make the necessary TLB requires the use of other tools.

    Using Classes instead saves all of this extra work. Simple value Classes are trivial to create, though each one needs its own module:
    Code:
    Public A As String
    Public B As String
    Public C As String
    Public D As String

  5. #5

    Thread Starter
    Frenzied Member some1uk03's Avatar
    Join Date
    Jun 2006
    Location
    London, UK
    Posts
    1,664

    Re: Problem with Public UDT: 'Only public user defined types......

    I would see it working with Classes but would require a few Classes, which would kind of enlarge needlessly the project. I just need a few UDT's.

    Any ideas on creating a TLB?
    _____________________________________________________________________

    ----If this post has helped you. Please take time to Rate it.
    ----If you've solved your problem, then please mark it as RESOLVED from Thread Tools.



  6. #6
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: Problem with Public UDT: 'Only public user defined types......

    You might start here: How To Pass Array of UDTs with Variable Length Strings to C/C++.

    I haven't seen anything in the way of a cookbook for creating TLBs just to define public UDTs though.

  7. #7
    PowerPoster RhinoBull's Avatar
    Join Date
    Mar 2004
    Location
    New Amsterdam
    Posts
    24,132

    Re: Problem with Public UDT: 'Only public user defined types......

    I would also recommend musing classes however if its too much to change then try using ordinary array instead - each item will have all values delimited by some character (pipe perhaps).
    You can also use collections and/or dictionary object (this one is collection on steroids).
    Here is a quick sample project that uses dictionary object (ms scripting runtime library is required).
    Attached Files Attached Files

  8. #8

    Thread Starter
    Frenzied Member some1uk03's Avatar
    Join Date
    Jun 2006
    Location
    London, UK
    Posts
    1,664

    Re: Problem with Public UDT: 'Only public user defined types......

    I think I've gone too much to change everything again now and I'm also trying to avoid 3rd party .dll's etc.. so the MS Scripting Runtime library, I'm not too keen on.

    It seems i need C++ in order to generate/create this .TLB having looked at that link, but I don't have or understand C++.

    Could anyone with knowledge of C++ give me a hand? All i need is a few declared UDT's and that's it. No functions, subs etc... only UDT's.

    Thanks
    _____________________________________________________________________

    ----If this post has helped you. Please take time to Rate it.
    ----If you've solved your problem, then please mark it as RESOLVED from Thread Tools.



  9. #9
    PowerPoster RhinoBull's Avatar
    Join Date
    Mar 2004
    Location
    New Amsterdam
    Posts
    24,132

    Re: Problem with Public UDT: 'Only public user defined types......

    Quote Originally Posted by some1uk03 View Post
    I think I've gone too much to change everything again now and I'm also trying to avoid 3rd party .dll's etc.. so the MS Scripting Runtime library, I'm not too keen on.
    It's a major Windows component since Windows 98 (late 90's) so it's always available without addition effort meaning that you can use late bindings (CreateObject) practically on any Windows OS.
    Sometimes we takes approach that has no way out so it's necessary to think it through before hitting the keyboard... But I understand your concern...

  10. #10
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: Problem with Public UDT: 'Only public user defined types......

    You don't need C++, you should be able to "compile" a typelib definition using tools like MkTypLib. This means manually generating UUIDs of course.

    Another drawback of this is that using a TLB in this way usually means it must be deployed and registered with the program. See the ancient (2003) Declaring UDT in .TLB: is it really a dead end?

    Seriously, just use Classes and be done with it.

    Generic objects like Collection or Dictionary are just going to be slow and bulky if you need to beat on a lot of these. Internal Classes are lighter by quite a large margin.

  11. #11
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: Problem with Public UDT: 'Only public user defined types......

    To avoid painting yourself into such a corner in the future always remember that UDTs are a last resort. They are only left as a vestige in VB6 so they can be used for the rare random I/O (also obsolete) or as surrogates for structs when calling APIs.

  12. #12
    Fanatic Member DrUnicode's Avatar
    Join Date
    Mar 2008
    Location
    Natal, Brazil
    Posts
    631

    Re: Problem with Public UDT: 'Only public user defined types......

    I wouldn't go the TLB route either but if you want to play with it here is an easy way to create a TLB right from VB.

    1. Create a new class and add your UDTs (use Public Type).
    2. In Project/Properties/Component Tab check the box for Remote Server Files.
    3. Compile the project and you will get both a DLL and TLB.
    4. Open the TLB in OleView.exe and you will see the UDTs.


  13. #13
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: Problem with Public UDT: 'Only public user defined types......

    That makes sense. You'd need the TLB for marshalling data to and from the remote server.

  14. #14

    Thread Starter
    Frenzied Member some1uk03's Avatar
    Join Date
    Jun 2006
    Location
    London, UK
    Posts
    1,664

    Re: Problem with Public UDT: 'Only public user defined types......

    Hi doc,

    Ok I did it that way and generated the .DLL and with it came the .TLB too.
    I can view the contents with OleView.exe and seem ok. But when I try and add a reference to it in VB, it wants the .DLL too.
    How do i get rid of the .dll?
    _____________________________________________________________________

    ----If this post has helped you. Please take time to Rate it.
    ----If you've solved your problem, then please mark it as RESOLVED from Thread Tools.



  15. #15
    PowerPoster
    Join Date
    Feb 2002
    Location
    Canada, Toronto
    Posts
    5,802

    Re: Problem with Public UDT: 'Only public user defined types......

    Maybe it's better to convert your UDT array to binary array, pass the array (or pointer to array), then convert back to UDT at destination.

  16. #16
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: Problem with Public UDT: 'Only public user defined types......

    You'll probably want to unregister the DLL after creation (clean up registry pollution) though this isn't necessary if you reinstall Windows a lot anyway.

    To use the typelib you set a reference to the TLB, not the DLL.

  17. #17

    Thread Starter
    Frenzied Member some1uk03's Avatar
    Join Date
    Jun 2006
    Location
    London, UK
    Posts
    1,664

    Re: Problem with Public UDT: 'Only public user defined types......

    Quote Originally Posted by dilettante View Post
    .... To use the typelib you set a reference to the TLB, not the DLL.
    Yes, but the problem is, only the .DLL is referenced in the LIST and If i try and BROWSE for the .TLB and Add it, nothing seems to happen or get added to the list !?
    _____________________________________________________________________

    ----If this post has helped you. Please take time to Rate it.
    ----If you've solved your problem, then please mark it as RESOLVED from Thread Tools.



  18. #18
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: Problem with Public UDT: 'Only public user defined types......

    I see what you mean.

    When you set a reference to TLB the IDE seems to register the DLL. I compiled the DLL project, unregistered the DLL, then created a new project and set a reference to the TLB. After compiling the new project my DLL was registered again.

    I do just see the TLB reference if I list the VBP file, and it shows in the References dialog as well. But without that DLL registered the program won't run.

  19. #19

    Thread Starter
    Frenzied Member some1uk03's Avatar
    Join Date
    Jun 2006
    Location
    London, UK
    Posts
    1,664

    Re: Problem with Public UDT: 'Only public user defined types......

    Any other ideas/clues?
    _____________________________________________________________________

    ----If this post has helped you. Please take time to Rate it.
    ----If you've solved your problem, then please mark it as RESOLVED from Thread Tools.



  20. #20
    New Member
    Join Date
    Sep 2010
    Posts
    8

    Re: Problem with Public UDT: 'Only public user defined types......

    I need more informations about your problem....
    try this:
    Create a module and put this declarations

    Public Enum SELECTION: A = 0: B = 1: End Enum
    Public Type mUdtObjInfo: A As String: B As String: End Type

    Public Type myInfo
    ObjInfo As mUdtObjInfo
    PosX As Integer
    PosY As Integer
    End Type

    Public m_Selected As SELECTION
    Public OneUDT As myInfo
    ------------------------------------------------------------
    Now create a form by default and past this code:

    02 CommandButton = Caption: cmdSelection (index 0 and 1)

    Dim OnemUdtObjInfo(1) As mUdtObjInfo

    Public Function EditCurrent() As myInfo '<< MSG = Only public user defined types defined in public ... first msg
    EditCurrent = theOne(m_Selected)
    End Function

    Public Function theOne(ByVal SelectedItem As SELECTION) As myInfo '<< MSG = Only public user defined types defined in public ... secound msg
    theOne.ObjInfo = OnemUdtObjInfo(SelectedItem) 'pass the UDT to UDT
    End Function

    Private Sub cmdSelection_Click(Index As Integer) 'Two commandbutton index 0 and 1
    Me.Cls
    m_Selected = Index
    OneUDT = EditCurrent
    MsgBox "String A: " & OneUDT.ObjInfo.A & vbCr & "String B: " & OneUDT.ObjInfo.B
    End Sub

    Private Sub Form_Load()
    OnemUdtObjInfo(0).A = "Selected Command 01"
    OnemUdtObjInfo(0).B = "XXXXXXXXXXXXXXXXXXX"
    OnemUdtObjInfo(1).A = "XXXXXXXXXXXXXXXXXXX"
    OnemUdtObjInfo(1).B = "Selected Command 02"
    End Sub


    press F5 and ....

    change Public Function EditCurrent() As myInfo to Private and try again ....
    change Public Function theOne(ByVal SelectedItem As SELECTION) As myInfo to private...

    modules (BAS) are defined to public declarations and Class or forms are private
    A UDT delared same public in a module can't be declared public in private

    I'm sorry... my English is not good

  21. #21

    Thread Starter
    Frenzied Member some1uk03's Avatar
    Join Date
    Jun 2006
    Location
    London, UK
    Posts
    1,664

    Re: Problem with Public UDT: 'Only public user defined types......

    Hi MarMo,

    Ok I've tried your suggestion. Changing them from Public to Private doesn't return any errors, BUT
    I need them to be Public, because I'm actually trying to pass info from a UserControl:
    i.e myUC.EditCurrent
    _____________________________________________________________________

    ----If this post has helped you. Please take time to Rate it.
    ----If you've solved your problem, then please mark it as RESOLVED from Thread Tools.



  22. #22
    New Member
    Join Date
    Sep 2010
    Posts
    8

    Re: Problem with Public UDT: 'Only public user defined types......

    Hello! excuse the delay in responding, I was traveling ... If you still need help with the problem of UDT let me know. I developed an OCX that shares UDT and I can post here.

  23. #23

    Thread Starter
    Frenzied Member some1uk03's Avatar
    Join Date
    Jun 2006
    Location
    London, UK
    Posts
    1,664

    Re: Problem with Public UDT: 'Only public user defined types......

    Hi Marmo,

    Yes still have same prob.
    _____________________________________________________________________

    ----If this post has helped you. Please take time to Rate it.
    ----If you've solved your problem, then please mark it as RESOLVED from Thread Tools.



  24. #24
    New Member
    Join Date
    Sep 2010
    Posts
    8

    Re: Problem with Public UDT: 'Only public user defined types......

    Here is the project which contains a OCX and a EXE for demostrar methods,
    properties and events. Is not fully completed because the little time to
    create but demonstrates how to work with UDT. Open the project OcxPassUDT and ative with F5 before use. Save and complile after open FormPassUDT and insert the OCX created.
    I hope that will help
    Attached Files Attached Files

  25. #25

    Thread Starter
    Frenzied Member some1uk03's Avatar
    Join Date
    Jun 2006
    Location
    London, UK
    Posts
    1,664

    Re: Problem with Public UDT: 'Only public user defined types......

    Hi Marmo,

    Thanks, I appreciate your contribution, but this would require me to deploy the .OCX too.
    My .EXE is currently deployed as a portable .exe without an installation, which is why I'm trying to avoid any extra files / .dll / ocx files.
    _____________________________________________________________________

    ----If this post has helped you. Please take time to Rate it.
    ----If you've solved your problem, then please mark it as RESOLVED from Thread Tools.



  26. #26
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,936

    Re: Problem with Public UDT: 'Only public user defined types......

    I know I'm years late with a response but I just stumbled across this thread and didn't see the obvious answer. VB6 class modules allow a "Friend" declaration of variables and procedures (in addition to "Public" and "Private"). When a procedure is declared as "Friend", you can use UDTs as arguments. No need for all the above rigmarole. It's really that easy. Again, sorry it took me almost 4 years to give you the answer. In a standard .EXE project, this is the only distinction between a "Public" and "Friend" declaration. These "Friend" declarations are still exposed to the entire project. Good luck, if you happen to get this.

  27. #27

    Thread Starter
    Frenzied Member some1uk03's Avatar
    Join Date
    Jun 2006
    Location
    London, UK
    Posts
    1,664

    Lightbulb Re: Problem with Public UDT: 'Only public user defined types......

    Quote Originally Posted by Elroy View Post
    I know I'm years late with a response but I just stumbled across this thread and didn't see the obvious answer. VB6 class modules allow a "Friend" declaration of variables and procedures (in addition to "Public" and "Private"). When a procedure is declared as "Friend", you can use UDTs as arguments. No need for all the above rigmarole. It's really that easy. Again, sorry it took me almost 4 years to give you the answer. In a standard .EXE project, this is the only distinction between a "Public" and "Friend" declaration. These "Friend" declarations are still exposed to the entire project. Good luck, if you happen to get this.
    Hi Elroy,

    Only 4 yrs late on a reply but thanks for your input.

    I think i ended up using classes not sure, can't even remember
    Although havent now tested but you're saying it was as easy as changing a Public scope to a Friend

    Will definitely remember & try it next time.
    _____________________________________________________________________

    ----If this post has helped you. Please take time to Rate it.
    ----If you've solved your problem, then please mark it as RESOLVED from Thread Tools.



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

    Re: Problem with Public UDT: 'Only public user defined types......

    Since you are replying to your own thread so many years later, here's another one:

    Declare them as UDTs, no biggie. The catch if you want to call it that:

    In the usercontrol project.
    1. Create a class and name it whatever you want, maybe something like GizmoGlobals
    2. Change the class Instancing property to: GlobalMultiUse
    3. Declare your UDTs in that class as Public

    Now they can be declared within any project that hosts the usercontrol
    Tip: This global class is also a good place to add custom public functions that apply to any of the usercontrol instances. Whatever is in the global is public to the customer and they do not have to declare that public class. If you were to look at your user control in the object browser (F2), you would see those UDTs and other stuff on the left side when viewing the usercontrol
    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}

  29. #29
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,936

    Re: Problem with Public UDT: 'Only public user defined types......

    *laughs* Yep, sorry I didn't see your question years ago. I still do a substantial amount of coding in VB6. Probably know about every nook and cranny there is to know about it. I just love that you can create an EXE file that needs absolutely no installation. My primary application runs on 100s of networked computers. They just find the EXE on the network and double-click it from there. I love it. And updates are a total snap too (other than getting everyone out of the application).

    For new installations, I even use the .RES (resource file) feature to wrap .manifest and the core .ocx files into the compiled EXE. The first time it runs, it unloads these out of its internal resource file (in the EXE) and sets them out into the EXE's folder and then re-executes itself. I even put a blank database and other core startup files in the .RES file that gets wrapped into the EXE upon compilation.

    I've even got all the Unicode worked out as well, with full unicode controls. That one was a bit tricky because the actual FRM files (that ultimately contain all the properties) are ASCII, but, if you put the unicode in the property bag as a byte array, it'll go into the FRX file instead. *smiles and shakes head* Just some of the old VB6 tricks of the trade.

    But back to "Friend vs Public" for a sec. Yeah, the "Friend" procedure is really better than "Public". It can be used in both forms and classes (but not BAS modules). These will then be seen by the entire project, but NOT outside of the project. VB6 has the ability to "expose" entry points (primarily for when you are creating DLLs), but the "Friend" declaration does not expose these entry points. Therefore, you circumvent any need to register your UDTs (for "automation" purposes), and you can pass them around anywhere you like. The actual UDT declaration (Type statement) will still need to be in a BAS module, but I suspect you already knew that.

    Take care,
    Elroy

  30. #30
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,936

    Re: Problem with Public UDT: 'Only public user defined types......

    Ok, let me respond to LaVolpe as well. He/she brings up a good point. User controls can get a bit tricky. I just love them, but I've gotten totally away from anything but the core set of controls and controls I've written myself. Let me list the standard control sets I use: comdlg32.ocx, mscomctl.ocx, mscomct2.ocx richtx32.ocx, & tabctl32.ocx. I've also used the grid control at times. I found that all those third-party controls that were all the rage a decade or so were all crap.

    I have written a handful of controls on my own. For instance, the unicode controls I mentioned above. I also have a degree slider control, a multi-select combobox control, and a few others for specific uses. However, because I wrote these (and have the source code), I just throw them right into my project, and don't compile them as separate OCX files. This sort of circumvents the issues you were discussing.

    However, there is still an issue regarding the "Friend" vs "Public" declaration when dealing with user controls. Specifically, I have two user control that have external forms that's sort of part of the controls. These forms come up when you "Edit" the controls while in design mode. They're sophisticated controls for putting rich text (and even pictures) on buttons and labels. A little word processor with image insert pops up in the IDE when you edit these controls. However, since these controls are compiled actually at design time (and not when you actually say to compile), any calls that are made from these user controls into other forms (or classes) must be made to "Public" procedures and not "Friend" procedures. So this is one (but rather esoteric) exception to "Friend" being better than "Public".

    Hey, most of my stuff is open source these days, so if you think I've mentioned something useful, let me know and I'll shoot it to you. My email is elroysullivan@gmail.com. (that's elroy sullivan @ gmail dot com (with no spaces), in case it gets deleted by the parser).

    Take Care,
    Elroy

  31. #31
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,936

    Re: Problem with Public UDT: 'Only public user defined types......

    Ok, one last point, and I'm done for the day. There is another spot where "Friend" won't work (even though it will compile). If you make an API call that has a call-back into one of your BAS modules, that call-back procedure can NOT make calls into "Friend" class (or form) procedures. You'll get a GPF if you try it. Again, this is rather esoteric, and also a case where you're not (strictly speaking) staying confined within your program. 99% of the time, "Friend" is the way to go though, and you get your UDTs passed in and out of class modules (and forms, which are just class modules with interfaces).

  32. #32
    Default Member Bonnie West's Avatar
    Join Date
    Jun 2012
    Location
    InIDE
    Posts
    4,060

    Re: Problem with Public UDT: 'Only public user defined types......

    Quote Originally Posted by Elroy View Post
    When a procedure is declared as "Friend", you can use UDTs as arguments. No need for all the above rigmarole. It's really that easy.
    Quote Originally Posted by some1uk03 View Post
    ... have tried Declaring it as a Friend instead of Public, but still no result.
    It appears that merely changing the scope of a procedure in a UserControl from Public to Friend isn't enough (at least in a Standard EXE). The following example shows one way of making it work correctly:

    Code:
    Option Explicit                     'In Form1.frm
    
    Private Sub Form_Load()
        Dim MI As MyInfo
    
       'MI = UserControl11.EditCurrent  '<-- Compile error: Method or data member not found
    
    
        Dim UC1 As UserControl1         'Declare an object variable
    
        Set UC1 = UserControl11         'and set it to the target UserControl
        MI = UC1.EditCurrent            'The UserControl's Friend procedures/
    End Sub                             'properties will now become accessible
    Code:
    Option Explicit                     'In Module1.bas
    
    Public Type mUdtObjInfo
        A As String
        B As String
        C As String
        D As String
    End Type
    
    Public Type MyInfo
        ObjInfo As mUdtObjInfo
        PosX    As Integer
        PosY    As Integer
    End Type
    Code:
    Option Explicit                     'In UserControl1.ctl
    
    Private m_Selected As Long
    Private theOne(0)  As MyInfo
    
    Friend Function EditCurrent() As MyInfo
        EditCurrent = theOne(m_Selected)
    End Function
    Quote Originally Posted by Elroy View Post
    I've even got all the Unicode worked out as well, with full unicode controls.
    You might be interested in checking this out.

    Quote Originally Posted by Elroy View Post
    There is another spot where "Friend" won't work (even though it will compile). If you make an API call that has a call-back into one of your BAS modules, that call-back procedure can NOT make calls into "Friend" class (or form) procedures. You'll get a GPF if you try it.
    Maybe you were doing it wrong? The attached project here demonstrates that it's possible to have Friend callback procedures.
    On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
    Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)

  33. #33
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,936

    Re: Problem with Public UDT: 'Only public user defined types......

    Hmmm, yeah, I took a look at the project you recommended, VBForms team. The CTL user control and the callback were two separate issues for me. For the callback, I was hooking the mouse system-wide, and then calling a procedure in a loaded form. Here's a bit of the callback code (which is obviously in a BAS module):

    Code:
    Private Function SystemWideMouseMove(ByVal ncode As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
        If ncode = HC_ACTION Then
            Call CopyMemory(SystemMouseStruct, ByVal lParam, Len(SystemMouseStruct))
            SystemMouseWParam = wParam
            frmMouseHookingForm.SystemMouseEvent
        End If
        SystemWideMouseMove = CallNextHookEx(pLastMouseHook, ncode, wParam, lParam)
    End Function
    It's interesting that the actual callback function can be private, but the callback was set in the same module so I guess VB could "see" the procedure address to tell Windows about. But it's that "frmMouseHookingForm.SystemMouseEvent" piece that I'm talking about. The "SystemMouseEvent" MUST be Public (not Friend) in the form, or I get GPFs. It's sort of interesting though. It works on speedy computers but not on slower ones, so maybe it's some kind of timing issue. I do my development on an i7 gamers computer, but the software has to run on older WindowsXP computers. The frmMouseHookingForm was actually a small form that you would drag around on the desktop and drop onto another form or control. That's why it had to be system wide. On the slower computers, it would start to work, and then crash. I changed the SystemMouseEvent procedure in the form to Public, and all problems go away. I'm not sure why. I just assumed that the callback procedure (shown above) couldn't correctly "see" the Friend address.

    I'm certainly willing to listen to a better explanation of what's happening though. I just have a big comment on the procedure to not make it Friend.

    Elroy

  34. #34
    Default Member Bonnie West's Avatar
    Join Date
    Jun 2012
    Location
    InIDE
    Posts
    4,060

    Re: Problem with Public UDT: 'Only public user defined types......

    Quote Originally Posted by Elroy View Post
    It's interesting that the actual callback function can be private, ...
    Yes, the scope of a callback function (or any other kind of procedure for that matter) isn't really important because in compiled code, there is no such distinction. What matters (to external codes) is the address of a function.

    Quote Originally Posted by Elroy View Post
    I changed the SystemMouseEvent procedure in the form to Public, and all problems go away. I'm not sure why. I just assumed that the callback procedure (shown above) couldn't correctly "see" the Friend address.
    Sorry, but I fail to see why too. Maybe you could provide a sample project that exhibits the issue(s) you're having so we can take a closer look.

    Quote Originally Posted by Elroy View Post
    I'm certainly willing to listen to a better explanation of what's happening though. I just have a big comment on the procedure to not make it Friend.
    I believe we are getting a bit off-topic so if you don't mind, could you please start a new thread that discusses your issue(s) in more detail? As I've mentioned above, it would really be helpful if you could attach a small project demonstrating the problem(s). Thank you.


    BTW, you shouldn't publish your email address in a forum such as this, unless you like receiving spam. It isn't too late yet to edit your post #30.
    On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
    Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)

  35. #35
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,936

    Re: Problem with Public UDT: 'Only public user defined types......

    Hi Bonnie,

    If it's okay, I'll just pull it back on topic and post here. In the above, I do an API CopyMemory into a UDT. There's really no way to avoid the CopyMemory, but it would be nice if the UDT could have been declared in the procedure and then passed in the call to frmMouseHookingForm.SystemMouseEvent. However, being required to declare frmMouseHookingForm.SystemMouseEvent as Public, this wasn't possible. Upon further reflection, I bet I know why the Friend declaration won't work. Some of the machines the program runs on are a bit short on memory. My development machine has hoards. I bet VB6 feels free to move the program code of Friend procedures, whereas Public procedures must maintain a fairly consistent memory address. This would explain the relative intermittent performance when the frmMouseHookingForm.SystemMouseEvent procedure is declared as Friend.

    I've cut out the smallest project I can to illustrate the problem, as you've requested. I'll post all the necessary code segments here, and also try and attach it as a ZIP file.

    This first bit of code is a FRM. I've included all of it, so just save it as FRM in notepad:

    Code:
    VERSION 5.00
    Begin VB.Form frmDragText 
       BackColor       =   &H00C0FFFF&
       BorderStyle     =   1  'Fixed Single
       ClientHeight    =   885
       ClientLeft      =   12045
       ClientTop       =   4140
       ClientWidth     =   2790
       ClipControls    =   0   'False
       ControlBox      =   0   'False
       HasDC           =   0   'False
       LinkTopic       =   "Form2"
       MaxButton       =   0   'False
       MinButton       =   0   'False
       ScaleHeight     =   885
       ScaleWidth      =   2790
       ShowInTaskbar   =   0   'False
       Begin VB.Timer tmr 
          Enabled         =   0   'False
          Interval        =   50
          Left            =   1080
          Top             =   60
       End
       Begin VB.Label lblDragText 
          Alignment       =   2  'Center
          BackColor       =   &H00C0FFFF&
          Caption         =   "Drag Text"
          Height          =   195
          Left            =   60
          TabIndex        =   0
          Top             =   0
          Width           =   900
       End
    End
    Attribute VB_Name = "frmDragText"
    Attribute VB_GlobalNameSpace = False
    Attribute VB_Creatable = False
    Attribute VB_PredeclaredId = True
    Attribute VB_Exposed = False
    Option Explicit
    '
    Private Type POINTAPI
        X As Long
        Y As Long
    End Type
    '
    Private Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
    Private Declare Function GetKeyState Lib "user32" (ByVal nVirtKey As Long) As Integer
    Private Declare Function WindowFromPointXY Lib "user32" Alias "WindowFromPoint" (ByVal xPoint As Long, ByVal yPoint As Long) As Long
    '
    Private Const VK_LBUTTON = &H1
    Private Const VK_RBUTTON = &H2
    '
    Dim pt32 As POINTAPI
    Dim frm As Form
    '
    
    Friend Sub Drag(frmIn As Form, sText As String)
        Set frm = frmIn
        lblDragText.Caption = sText
        lblDragText.Left = -30
        lblDragText.Top = 0
        lblDragText.Height = 240
        lblDragText.Width = Me.TextWidth(lblDragText.Caption) + 180
        Me.Width = lblDragText.Width
        Me.Height = 240
        '
        GetCursorPos pt32
        Me.Left = (pt32.X + 5) * Screen.TwipsPerPixelX - (Me.Width \ 2) - 90
        Me.Top = (pt32.Y + 5) * Screen.TwipsPerPixelY - Me.Height - 60
        Me.Show
    End Sub
    
    Private Sub Form_Load()
        SetSystemWideMouseHook Me
    End Sub
    
    Private Sub Form_Unload(Cancel As Integer)
        UnSetSystemWideMouseHook
    End Sub
    
    Public Sub SystemMouseEvent() ' THIS MUST STAY PUBLIC!!!!!!!!!!!!!!!! (NOT FRIEND)
        ' Now see if we are ready to drop the text.
        If Not ((GetKeyState(VK_LBUTTON) >= 0) And (GetKeyState(VK_RBUTTON) >= 0)) Then
            Me.Left = (SystemMouseStruct.X + 5) * Screen.TwipsPerPixelX - (Me.Width \ 2) - 90
            Me.Top = (SystemMouseStruct.Y + 5) * Screen.TwipsPerPixelY - Me.Height - 60
        Else
            Unload Me
        End If
    End Sub
    This next segment is just a form to test it:
    Code:
    VERSION 5.00
    Begin VB.Form Form1 
       Caption         =   "Form1"
       ClientHeight    =   5475
       ClientLeft      =   780
       ClientTop       =   2340
       ClientWidth     =   6585
       LinkTopic       =   "Form1"
       ScaleHeight     =   5475
       ScaleWidth      =   6585
    End
    Attribute VB_Name = "Form1"
    Attribute VB_GlobalNameSpace = False
    Attribute VB_Creatable = False
    Attribute VB_PredeclaredId = True
    Attribute VB_Exposed = False
    Option Explicit
    
    Private Sub Form_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
        frmDragText.Drag Me, "Dragging"
    End Sub
    The next segment is the hooking and callback BAS module:

    Code:
    Attribute VB_Name = "Module1"
    Option Explicit
    '
    Private Type MSLLHOOKSTRUCT
        X As Long
        Y As Long
        MouseData As Long
        flags As Long
        Time As Long
        dwExtraInfo As Long
    End Type
    '
    Private Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, ByVal hmod As Long, ByVal dwThreadId As Long) As Long
    Private Declare Function UnhookWindowsHookEx Lib "user32" (ByVal hHook As Long) As Long
    Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDest As Any, pSource As Any, ByVal cbLength As Long)
    Private Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Long, ByVal ncode As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    '
    Public SystemMouseStruct As MSLLHOOKSTRUCT
    Public SystemMouseWParam As Long
    '
    Private pLastMouseHook As Long
    Private frmMouseHookingForm As Form
    '
    Private Const WH_MOUSE_LL = 14&         ' Hook Flag
    Private Const HC_ACTION = 0&            ' Mouse Process Message
    '
    
    Public Sub SetSystemWideMouseHook(frm As Form)
        If pLastMouseHook = 0 Then
            pLastMouseHook = SetWindowsHookEx(WH_MOUSE_LL, AddressOf SystemWideMouseMove, App.hInstance, 0&)
            Set frmMouseHookingForm = frm
        End If
    End Sub
    
    Public Sub UnSetSystemWideMouseHook()
        If pLastMouseHook <> 0 Then
            UnhookWindowsHookEx pLastMouseHook
            pLastMouseHook = 0
            Set frmMouseHookingForm = Nothing
        End If
    End Sub
    
    Private Function SystemWideMouseMove(ByVal ncode As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
        If ncode = HC_ACTION Then
            Call CopyMemory(SystemMouseStruct, ByVal lParam, Len(SystemMouseStruct))
            SystemMouseWParam = wParam
            frmMouseHookingForm.SystemMouseEvent
        End If
        SystemWideMouseMove = CallNextHookEx(pLastMouseHook, ncode, wParam, lParam)
    End Function
    And lastly, here's the VBP project to test it all. Just run it, and drag anywhere on the test form, and you'll see how it's suppose to work.

    Code:
    Type=Exe
    Form=Form1.frm
    Reference=*\G{00020430-0000-0000-C000-000000000046}#2.0#0#..\..\..\..\Windows\SysWow64\stdole2.tlb#OLE Automation
    Form=DragText.frm
    Module=Module1; Module1.bas
    IconForm="Form1"
    Startup="Form1"
    Command32=""
    Name="Project1"
    HelpContextID="0"
    CompatibleMode="0"
    MajorVer=1
    MinorVer=0
    RevisionVer=0
    AutoIncrementVer=0
    ServerSupportFiles=0
    VersionCompanyName="Test"
    CompilationType=0
    OptimizationType=0
    FavorPentiumPro(tm)=0
    CodeViewDebugInfo=0
    NoAliasing=0
    BoundsCheck=0
    OverflowCheck=0
    FlPointCheck=0
    FDIVCheck=0
    UnroundedFP=0
    StartMode=0
    Unattended=0
    Retained=0
    ThreadPerObject=0
    MaxNumberOfThreads=1

    To make it intermittently fail, with GPF faults and/or other bizarre errors, just declare the SystemMouseEvent in the frmDragText as Friend, and you'll get errors on slower machines with limited memory.

    FriendVsPublicTest.zip

  36. #36
    Frenzied Member yrwyddfa's Avatar
    Join Date
    Aug 2001
    Location
    England
    Posts
    1,253

    Re: Problem with Public UDT: 'Only public user defined types......

    Serialising UDT's is a little more tricky than a straight CopyMemory.

    Here's my code from 8 years ago (!!) that will serialise most UDT's: some restrictions, however ...

    http://www.vbforums.com/showthread.p...t=yrwyddfa+udt
    "As far as the laws of mathematics refer to reality, they are not certain; and as far as they are certain, they do not refer to reality." - Albert Einstein

    It's turtles! And it's all the way down

  37. #37
    Default Member Bonnie West's Avatar
    Join Date
    Jun 2012
    Location
    InIDE
    Posts
    4,060

    Re: Problem with Public UDT: 'Only public user defined types......

    Quote Originally Posted by Elroy View Post
    I bet VB6 feels free to move the program code of Friend procedures, whereas Public procedures must maintain a fairly consistent memory address.
    I doubt VB6 does something like that. I don't know the low-level details though, so I could be wrong.

    Quote Originally Posted by Elroy View Post
    I've cut out the smallest project I can to illustrate the problem, as you've requested. I'll post all the necessary code segments here, and also try and attach it as a ZIP file.
    Thanks a lot!

    Quote Originally Posted by Elroy View Post
    To make it intermittently fail, with GPF faults and/or other bizarre errors, just declare the SystemMouseEvent in the frmDragText as Friend, and you'll get errors on slower machines with limited memory.
    After changing SystemMouseEvent's scope to Friend, the EXE crashed immediately when I tried dragging the Form's client area.

    I think the problem is because the public variable frmMouseHookingForm was dimensioned as the generic Form type. If you'll notice in the demo project I've linked to above, the object variables that point to an instance of their respective object modules were dimensioned as that specific object type. By doing it that way, the SystemMouseEvent procedure now appears in the IntelliSense list, which means that calls to that procedure won't be late bound (remember, Friend procedures can't be late bound). Sure enough, when I amended the declaration of frmMouseHookingForm to frmDragText, it worked! The program didn't self-destruct anymore.
    On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
    Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)

  38. #38
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,936

    Re: Problem with Public UDT: 'Only public user defined types......

    Oh WOW, good information Bonnie. )) That hooking code is used in a couple of different places, but I don't mind making copies of it for each form that uses it. Also, it's just good to know how things work. ) You take care, and thanks for your diligence on this. Maybe some others will get some benefit from all of this as well.

  39. #39
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,936

    Re: Problem with Public UDT: 'Only public user defined types......

    Hi Bonnie, and all:

    I've done further testing and you are exactly right. All the problems I mentioned above have to do with "Friend" procedures being in "Late Bound" objects. So long as they are "Early Bound", all works fine. It turns out the MSDN Library actually states this. I had just never completely recorded it in my head because you quickly get a run-time error in most cases. However, apparently, in certain callback and User-Defined-Control situations, the error checking doesn't catch the late binding, and the program just crashes badly. What's even most interesting is that I believe you actually answered Frenzied's original question. He mentioned that he tried dimensioning as "Friend" and it didn't work. The only reason I can think of that it wouldn't work is late binding.

    Ok, I'm officially out'a here. This has been fun, and I actually learned something.

    Regards,
    Elroy

  40. #40
    Member
    Join Date
    Apr 2009
    Posts
    48

    Re: Problem with Public UDT: 'Only public user defined types......

    Quote Originally Posted by LaVolpe View Post
    In the usercontrol project.
    1. Create a class and name it whatever you want, maybe something like GizmoGlobals
    2. Change the class Instancing property to: GlobalMultiUse
    3. Declare your UDTs in that class as Public
    How do you do do #2? I see no class instancing property for a class. Did you mean usercontrol not class?

    I just want to make 2 functions for adding and removing items for a UDT array, so I don't have to remake the 2 functions for every UDT array. Passing UDTs into a collection would work too
    Last edited by neotechni; Sep 15th, 2016 at 08:07 PM.

Page 1 of 2 12 LastLast

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