Read WinINet INTERNET_OPTION_PROXY with a Sized C# Buffer
Retrieve INTERNET_OPTION_PROXY with a size query and correctly sized native buffer, matching the DWORD and pointer fields in C#.
INTERNET_PROXY_INFO contains a DWORD access type and two string pointers. The native query also needs enough buffer space for its proxy data; Marshal.SizeOf of a small managed structure is not a complete variable-length result buffer.
A desktop compatibility helper can use the ANSI entry point and copy the strings before releasing that query buffer:
static class WinInetProxy
{
[System.Runtime.InteropServices.StructLayout(
System.Runtime.InteropServices.LayoutKind.Sequential)]
struct ProxyInfo
{
public uint AccessType;
public IntPtr Proxy;
public IntPtr Bypass;
}
[System.Runtime.InteropServices.DllImport(
"wininet.dll", EntryPoint = "InternetQueryOptionA",
SetLastError = true)]
[return: System.Runtime.InteropServices.MarshalAs(
System.Runtime.InteropServices.UnmanagedType.Bool)]
static extern bool Query(
IntPtr handle, uint option, IntPtr buffer, ref uint size);
public static (uint Type, string Proxy, string Bypass) Read()
{
uint size = 0;
Query(IntPtr.Zero, 38, IntPtr.Zero, ref size);
int error = System.Runtime.InteropServices.Marshal.GetLastWin32Error();
if (error != 122 || size == 0)
throw new System.ComponentModel.Win32Exception(error);
IntPtr buffer = System.Runtime.InteropServices.Marshal
.AllocHGlobal(checked((int)size));
try
{
if (!Query(IntPtr.Zero, 38, buffer, ref size))
throw new System.ComponentModel.Win32Exception(
System.Runtime.InteropServices.Marshal.GetLastWin32Error());
var value = System.Runtime.InteropServices.Marshal
.PtrToStructure<ProxyInfo>(buffer);
return (value.AccessType,
System.Runtime.InteropServices.Marshal.PtrToStringAnsi(value.Proxy) ?? "",
System.Runtime.InteropServices.Marshal.PtrToStringAnsi(value.Bypass) ?? "");
}
finally
{
System.Runtime.InteropServices.Marshal.FreeHGlobal(buffer);
}
}
}
38 is INTERNET_OPTION_PROXY; 122 is ERROR_INSUFFICIENT_BUFFER. The first call obtains the required byte count, and the second fills that allocation. If the result grows between calls, the second failure is reported instead of reading an undersized buffer.
Keep AccessType as uint. It remains a 32-bit DWORD in a 64-bit process, while the pointer fields expand with the process architecture. Normal sequential layout supplies the corresponding alignment.
This example concerns option 38's result buffer. Do not apply its ownership pattern blindly to INTERNET_OPTION_PER_CONNECTION_OPTION, whose returned string options require their documented separate cleanup.
The result describes WinINet configuration at the selected handle scope. It is not a PAC decision for an arbitrary URL or a report of every browser's effective route. When the returned proxy string is a protocol-specific map, preserve that structure instead of treating it as one endpoint. WinINet is the desktop API; service applications need their supported WinHTTP arrangement.