Results 1 to 11 of 11

Thread: [RESOLVED] Variable Scope - What is the Compiler Really Doing?

  1. #1

    Thread Starter
    Fanatic Member
    Join Date
    Feb 2017
    Posts
    858

    Resolved [RESOLVED] Variable Scope - What is the Compiler Really Doing?

    We're all taught to declare variables at the lowest level possible -- ie local, module, global. This works well except I've always wondered about API declarations.

    Standard practice for me is if I need to declare an API more than twice, I make it global.

    We all know local variables are pushed and popped off the stack.

    But what about module variables? My last read on this subject indicated that the compiler brings in all modules and they remain throughout the App life. If this is correct, then there would appear to be a definite advantage to making the same API declaration global after a certain count.

    But the question arises as to what the compiler is really doing?

    For example, does it compare the API module declarations and take a count of each, and then automotically make a global declaration based on the count, ignoring all other same APIs
    -- or --
    are they actually declared multiple times
    -- or --
    is just one declaration made and then a pointer created to that declaration for any other same API?

  2. #2
    Smooth Moperator techgnome's Avatar
    Join Date
    May 2002
    Posts
    34,531

    Re: Variable Scope - What is the Compiler Really Doing?

    Here's how I've done it. I'll put the API Declare at the top of hte file where I need it. If it's in a form, that's where it goes. If I find that I need it somewhere else - either in a different form, or in a Module somewhere, I move it from the form and put it into a Module and make it public so I can get to it from anywhere in the App. I've also seen some people say "forget that" and put all of their API Declares in an APIDeclarations module right from the start. As for having multiple declares to the same API, I don't know exactly what happens because I try to avoid that situation right from the start. However, given that it's local scope first,then outward, I'd say that each declare gets its own address. Makes sense because in theory you can declare a function to one dll in one location, then in another file, declare that same function (by name) in a different dll... and it'll all work happily.

    -tg
    * I don't respond to private (PM) requests for help. It's not conducive to the general learning of others.*
    * I also don't respond to friend requests. Save a few bits and don't bother. I'll just end up rejecting anyways.*
    * How to get EFFECTIVE help: The Hitchhiker's Guide to Getting Help at VBF - Removing eels from your hovercraft *
    * How to Use Parameters * Create Disconnected ADO Recordset Clones * Set your VB6 ActiveX Compatibility * Get rid of those pesky VB Line Numbers * I swear I saved my data, where'd it run off to??? *

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

    Re: Variable Scope - What is the Compiler Really Doing?

    Hi vb6forever,

    I'd suspect someone like The Trick will know the "true" answer to this. Others often talk about compiler optimizations, but I have my doubts about that. My best guess is that the VB6 compiler does very little optimization of the type you're suggesting.

    Now, you've actually raised several points. Regarding API declarations, I go back and forth with this. For the most part, I've got all my API declarations in a very few general purpose modules. And, for the most part, all of those API declarations are Private. In 99% of the cases, I need a bit of a VB6 code wrapper for the API call anyway, so there's no need to make them Public.

    Having said that, there are a handful of API declarations that I do seem to use somewhat more frequently, and somewhat more globally. Some Examples are Sleep, CopyMemory(RtlMoveMemory), lstrlenA, lstrlenW, ShowWindow, SendMessage, and a few more. Those, I have declared Public in a special BAS module.

    Also, someone is going to bring up TypeLibs. I just know it. And yes, a TypeLib might be a good way to go with these API declarations, especially since you can stuff all kinds of things into them, and only the stuff used is pulled out during compilation and development. They're very nice in that respect. However, I just like being able to quickly reference the actual API declaration so I tend to not use them.

    Regarding variables, I wholeheartedly agree with your statement about staying as local as possible (so long as it really makes sense). Now, as far as my understanding, the only time a variable (or its address) is going to be popped-pushed from the stack is when it's passed as an argument. All other times, the compiler is just going to create a relocatable address for it.

    When talking about variables, we must consider both scope and lifetime, and these things "sort of" go together, but not necessarily. For instance a Static in a BAS procedure will have a very narrow scope (the procedure), but a lifetime for as long as the project is running. Module level variables in a CLS module (Public or Private) will have a lifetime as long as an instantiation of the CLS is referenced. The scope will differ depending on whether it's Public or Private. Statics in a CLS procedure will have procedure limited scope, and a lifetime as long as the instantiation.

    I'm thinking this actually makes sense to you. There are many other conceptualizations of the scope and lifetime of variables, and I won't go through them all here.

    Best Regards,
    Elroy
    Last edited by Elroy; Nov 9th, 2017 at 10:56 AM.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  4. #4

    Thread Starter
    Fanatic Member
    Join Date
    Feb 2017
    Posts
    858

    Re: Variable Scope - What is the Compiler Really Doing?

    Thanks tg and Elroy for your input.
    Unfortuantely for all of us, we can come up with a "logical" procedure for doing things -- which may or may not be the best way -- since the compiler is going to do what the compiler is going to do.
    In effect we're looking into a black box and hoping we get it right.

    Hopefully Trick will respond and have more insight.

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

    Re: Variable Scope - What is the Compiler Really Doing?

    Hi vb6forever,

    You're correct that it's a black box (except maybe for those like The Trick, and possibly others, who've taken the time to basically disassemble the entire VB6 compiler). However, hopefully, it's a black box that behaves in accordance with strict laws of logic. From that perspective, we can throw things at this black box (i.e., testing) toward understanding precisely how it's going to behave.

    From that perspective, I'm pretty comfortable with my understandings of the VB6 compiler.

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

  6. #6
    Fanatic Member
    Join Date
    Aug 2013
    Posts
    806

    Re: Variable Scope - What is the Compiler Really Doing?

    Quote Originally Posted by vb6forever View Post
    For example, does it compare the API module declarations and take a count of each, and then automotically make a global declaration based on the count, ignoring all other same APIs
    -- or --
    are they actually declared multiple times
    -- or --
    is just one declaration made and then a pointer created to that declaration for any other same API?
    Hi vb6forever. To answer your questions as best I know...

    - No
    - Yes
    - No

    Consider this: you can declare the same API in different ways, and you may even want to do this in the same project. For example, in one module maybe you want to do this:

    Code:
    Private Declare Sub RtlMoveMemory Lib "kernel32" (ByVal lpDst As Long, ByVal lpSrc As Long, ByVal numOfBytes As Long)
    ...while in another one you want to do this:

    Code:
    Private Declare Sub RtlMoveMemory Lib "kernel32" (ByRef lpDst As Any, ByRef lpSrc As Any, ByVal numOfBytes As Long)
    These are both valid ways to use the same underlying API, but VB has to perform different error-checking against each call. Calls that may work with the second declaration won't work with the first one, so VB has to handle them differently at run-time.

    Similarly, you can alias the same API call in multiple ways inside the same module - weird, right?

    Code:
    Private Declare Function SendMessage Lib "user32" Alias "SendMessageW" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByRef lParam As Any) As Long
    Private Declare Function SendMessage2 Lib "user32" Alias "SendMessageW" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    It's totally valid to place both aliases inside the same form or module.

    Note that the underlying DLL itself won't be loaded multiple times, but VB's flexibility with function declarations means that calls to a given declaration need to be uniquely handled at run-time.
    Check out PhotoDemon, a pro-grade photo editor written completely in VB6. (Full source available at GitHub.)

  7. #7

    Thread Starter
    Fanatic Member
    Join Date
    Feb 2017
    Posts
    858

    Re: Variable Scope - What is the Compiler Really Doing?

    Tanner_H:
    Thanks for your feedback.

    Your point of different declarations is well taken, and in if this was the case in any App I would
    always go Private versus Global.

    Of special note is:
    Note that the underlying DLL itself won't be loaded multiple times
    With your statement quoted, I'm assuming this applies to the same API declarations WITHIN the same module -- or -- different APIs that use the same DLL within that module. I would think that the same DLL would be loaded multiple times if used within different modules unless declared Globally.

    After doing some more reading overnight, I "kinda" came to the conclusion it is a mixed bag.
    Encapsulation versus Memory Usage (global) -- BUT -- this again is just a guess.
    Last edited by vb6forever; Nov 10th, 2017 at 12:19 PM.

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

    Re: Variable Scope - What is the Compiler Really Doing?

    No, a DLL is only loaded once.

  9. #9
    Addicted Member
    Join Date
    Feb 2004
    Posts
    145

    Re: Variable Scope - What is the Compiler Really Doing?

    Quote Originally Posted by dilettante View Post
    No, a DLL is only loaded once.
    so, is there any downside to declaring more than once?
    /Jimboat

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

    Re: Variable Scope - What is the Compiler Really Doing?

    Each declaration seems to cause the compiler (actually VB6.EXE, which is pass 1) to store a blob of data about the entrypoint declaration. The blob contests are sort of like typelib data. This is used at runtime to construct the actual call when you first "touch" a "Declared" call at runtime.

    So if you have a ton of these they probably make your program a little bigger and use a bit more memory.

  11. #11

    Thread Starter
    Fanatic Member
    Join Date
    Feb 2017
    Posts
    858

    Re: Variable Scope - What is the Compiler Really Doing?

    In summary (I've used quotes to make it stand out):

    ' My Understanding per mostly VB forum posts:

    '1) Each App loads any Dll only once. even though the API may be declared multiple times throughout the App
    '2) Microsoft may provide both ANSI versions of each API which are noted with an "A" at the end of the function (e.g. SendMessageA)
    ' and a Unicode version known as "wide character" whch are noted with a "W" at the end of the function (e.g. SendMessageW)
    ' While VB5/6 was designed for use with ANSI versions, "W" versions may be used in their place and as of this writing -- Windows 10 --
    ' the "W" version "supposedly" is preferred for new development.
    ''3) VB allows the User to "modify" the API declaration for their needs (assume similar to C++ function overriding)
    ' This modification can take place both in the API name (e.g. SendMessageLong, SendMessageStr instead of SendMessage)
    ' as well as how each parameter is declared (e.g. wParam As Long versus wParam As Any)
    '4) Declaring the Scope of the API is an interesting discussion.
    ' The best I've been able to come up with is there is a tradeoff between "Encapsulaiton" -- declaring at the module level --
    ' versus declaring it globally. Since computers have moved to more memory, encapsulation seems to be the preferred choice.
    ' This gives portability of modules and classes when coding instead of having to maintain a separate Global API module.
    ' However, there are some API's which will never be modified -- such as DC and Windows -- where a global declaration may be best if memory usage is a consideration.

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