6
votes

Documentation of WinHttpGetIEProxyConfigForCurrentUser says:

The caller must free the lpszProxy, lpszProxyBypass and lpszAutoConfigUrl strings in the WINHTTP_CURRENT_USER_IE_PROXY_CONFIG structure if they are non-NULL. Use GlobalFree to free the strings.

I wrote the following code (Delphi 10.3.2):

var
  VConfig: TWinHttpCurrentUserIEProxyConfig;
begin
  FillChar(VConfig, SizeOf(VConfig), 0);

  if not WinHttpGetIEProxyConfigForCurrentUser(VConfig) then begin
    RaiseLastOSError;
  end;
  ...

  if VConfig.lpszAutoConfigUrl <> nil then begin
    GlobalFree(VConfig.lpszAutoConfigUrl);        // <-- Error
  end;

and got an error:

[dcc32 Error] E2010 Incompatible types: 'NativeUInt' and 'PWideChar'

Questions:

  • should I type-cast PWideChar to NativeUInt?

  • can I use GlobafFreePtr instead of GlobafFree (it accepts PWideChar and works fine in my tests)?

1
GlobalFreePtr calls GlobalHandle to get an HGLOBAL from a pointer, then GlobalUnlock to unlock that handle, then GlobalFree. All the examples I see online call GlobalFree directly on the pointer. My guess is that, these days at least, GlobalHandle returns its input value directly, in other words the HGLOBAL is the same thing as the pointer. My suggestion is that you call GlobalFree directly, and hence cast the pointer to HGLOBAL. GlobalFree(HGLOBAL(...)) - David Heffernan
@DavidHeffernan I found this: Memory objects allocated with GMEM_FIXED always have a lock count of zero. For these objects, the value of the returned pointer is equal to the value of the specified handle. i.e. in some cases it's not safe to cast pointer, but GlobalFreePtr should be used. So, I think it would be safer to use GlobalFreePtr in all cases. - zed
The excellent answer from @Anders tells you that you are wrong, and justifies why - David Heffernan

1 Answers

8
votes

When MSDN tells you to free with a specific function then doing just that is your best bet.

Parts of the Windows API is written in C and (some parts even without STRICT defined?) and other languages with better type checking will require casts in some places.

In the case of HGLOBALs you have the GlobalFlags function that can help you out. In your case the low byte of flags is zero indicating that there are no locks. If the strings had been allocated as movable the documentation would have to tell you to lock before accessing the memory and it does not.

The final nail in the coffin is to debug the function and if you do that you will see that it calls GlobalAlloc with flags set to 0x40 (GPTR) and should therefore be passed to GlobalFree without unlocking. If your compiler complains then you must cast to the appropriate type:

GlobalFree(HGLOBAL(VConfig.lpszAutoConfigUrl));