QB64.org Forum

Active Forums => QB64 Discussion => Topic started by: SpriggsySpriggs on September 26, 2020, 11:07:10 pm

Title: Issue with string buffer in Shell32 WinAPI
Post by: SpriggsySpriggs on September 26, 2020, 11:07:10 pm
I need help from someone on the forum who is used to dealing with WinAPI. I'm trying this code out and it keeps truncating values even though my buffer would definitely be able to hold the path for the variable. The max path in Windows 10 is 260 and no matter what I use, I see truncated strings. This code allows for more than one Environment variable and so this screenshot shows me trying two at the same time:

  [ This attachment cannot be displayed inline in 'Print Page' view ]  

And my code:
Code: QB64: [Select]
  1.     FUNCTION EnvironmentVariable& ALIAS DoEnvironmentSubstA (BYVAL pszSrc AS _OFFSET, BYVAL cchSrc AS _UNSIGNED INTEGER)
  2.  
  3. PRINT EnvVariable("%userprofile% %homepath%")
  4.  
  5. FUNCTION EnvVariable$ (variable AS STRING)
  6.     DIM size AS _UNSIGNED INTEGER
  7.     variable = variable + CHR$(0)
  8.     size = 1024
  9.     DIM a AS LONG
  10.     a = EnvironmentVariable(_OFFSET(variable), size)
  11.     EnvVariable = variable

I've tried this code in both 64 and 32 bit QB64. I'm using v1.4 on Windows 10.
Title: Re: Issue with string buffer in Shell32 WinAPI
Post by: SpriggsySpriggs on September 26, 2020, 11:12:58 pm
I think I might have just fixed it. I'll keep testing.
Title: Re: Issue with string buffer in Shell32 WinAPI
Post by: FellippeHeitor on September 26, 2020, 11:13:30 pm
There's http://www.qb64.org/wiki/ENVIRON$ (http://www.qb64.org/wiki/ENVIRON$).
Title: Re: Issue with string buffer in Shell32 WinAPI
Post by: SpriggsySpriggs on September 26, 2020, 11:22:37 pm
There's http://www.qb64.org/wiki/ENVIRON$ (http://www.qb64.org/wiki/ENVIRON$).
@FellippeHeitor
Good grief..... I forgot all about that functionality in QB64..... Question: Does this work with User defined environment variables or ones added by programs?
Dang..... I spent all that time trying to figure out what was wrong and it exists in QB64 already. The only thing different with the WinAPI one is that it allows for multiple variables at the same time.
Title: Re: Issue with string buffer in Shell32 WinAPI
Post by: SpriggsySpriggs on September 26, 2020, 11:34:28 pm
The main thing I see is a speed difference and the ENVIRON$ is not returning the username when I use the USERNAME variable. The WinAPI version does and completes listing the basic list of environment variables twice as fast as the built in ENVIRON$ function. HMMMM..... There are drawbacks to both, I reckon. One allows for multiple variables at once, one doesn't. One is accurate each time I run it, one misses the USERNAME variable (if I run ENVIRON$("USERNAME") own it works just fine.... I don't get it) . One is twice as fast. Oh well. I'll still put it in my API collection zip as a demo, I guess.
Title: Re: Issue with string buffer in Shell32 WinAPI
Post by: FellippeHeitor on September 26, 2020, 11:52:45 pm
ENVIRON$ uses C++'s getenv() internally.
Title: Re: Issue with string buffer in Shell32 WinAPI
Post by: SpriggsySpriggs on September 27, 2020, 12:04:51 am
ENVIRON$ uses C++'s getenv() internally.
I see. It will just depend on the program whether or not I end up using the one I wrote or the one already there. It wasn't a total loss, I suppose. I learned a bit more about how to do that string buffer properly.
Title: Re: Issue with string buffer in Shell32 WinAPI
Post by: luke on September 27, 2020, 12:05:46 am
For the record, the proper way to call DoEnvironmentSubstA is like this:
Code: [Select]
DEFLNG A-Z
DECLARE DYNAMIC LIBRARY "Shell32"
    FUNCTION EnvironmentVariable& ALIAS DoEnvironmentSubstA (pszSrc$, BYVAL cchSrc AS _UNSIGNED LONG)
END DECLARE

PRINT EnvVariable("%os%")

FUNCTION EnvVariable$ (template$)
    DIM size AS _UNSIGNED LONG
    size = 256
    IF LEN(template$) > size THEN size = LEN(template$)
    DO
        buf$ = SPACE$(size)
        LSET buf$ = template$ + CHR$(0)
        result = EnvironmentVariable(buf$, size)
        size = size * 2
    LOOP UNTIL _SHR(result, 16)
    EnvVariable$ = LEFT$(buf$, (result AND &HFFFF&) - 1)
END FUNCTION
and even then I should really be making sure `size` doesn't overflow.

ENVIRON$ is obviously the better way to do this, but note that DoEnvironmentSubstA is deprecated in favour of ExpandEnvironmentStringsA anyway. Thankfully the latter has a far more sensible calling convention, with separate input and output buffers.


EDIT And here's an example of calling the much more sensible ExpandEnvironmentStringsA:
Code: [Select]
DEFLNG A-Z
DECLARE DYNAMIC LIBRARY "Kernel32"
    FUNCTION EnvironmentVariable& ALIAS ExpandEnvironmentStringsA (src$, dest$, BYVAL size AS _UNSIGNED LONG)
END DECLARE

PRINT EnvVariable("%os%")

FUNCTION EnvVariable$ (template$)
    templatez$ = template$ + CHR$(0)
    size = 256
    buf$ = SPACE$(size)
    result = EnvironmentVariable(templatez$, buf$, size)
    IF result = 0 THEN ERROR 5
    IF result > size THEN
        size = result
        buf$ = SPACE$(size)
        result = EnvironmentVariable(templatez$, buf$, size)
    END IF
    IF result = 0 OR result > size THEN ERROR 5
    EnvVariable$ = LEFT$(buf$, result - 1)
END FUNCTION
Title: Re: Issue with string buffer in Shell32 WinAPI
Post by: SpriggsySpriggs on September 27, 2020, 12:30:10 am
@luke Oh well. I didn't see the newer version of that function out there when I was doing that or else I would have for sure used that one. I don't like using the deprecated ones if I can find the updated versions. When I check the MSDN documentation it says that the pszSrc variable is a pointer to a string, not a string. In your snippet you have it as a string. I guess it doesn't matter since I tested your snippet and it worked. Huh. I always thought it was strict on those things. That's cool that it didn't care.