Skip to content

Friendly overloads for NativeOverlapped not working #1066

Description

@Tratcher

Actual behavior

Generated APIs that take [In] NativeOverlapped object don't work, causing null refs in the callbacks when trying to retrieve the original state.

Expected behavior

We've (@AaronRobinsonMSFT) found that NativeOverlapped parameters need to be passed by ref (NativeOverlapped*) in both generated signatures so that the native call can correctly update the value.

Repro steps

  1. NativeMethods.txt content:
HttpReceiveHttpRequest

Generated API:

internal static unsafe uint HttpReceiveHttpRequest(SafeHandle RequestQueueHandle, ulong RequestId, winmdroot.Networking.HttpServer.HTTP_RECEIVE_HTTP_REQUEST_FLAGS Flags, out winmdroot.Networking.HttpServer.HTTP_REQUEST_V2 RequestBuffer, uint RequestBufferLength, uint* BytesReturned, global::System.Threading.NativeOverlapped? Overlapped)
{
	bool RequestQueueHandleAddRef = false;
	try
	{
		fixed (winmdroot.Networking.HttpServer.HTTP_REQUEST_V2* RequestBufferLocal = &RequestBuffer)
		{
			winmdroot.Foundation.HANDLE RequestQueueHandleLocal;
			if (RequestQueueHandle is object)
			{
				RequestQueueHandle.DangerousAddRef(ref RequestQueueHandleAddRef);
				RequestQueueHandleLocal = (winmdroot.Foundation.HANDLE)RequestQueueHandle.DangerousGetHandle();
			}
			else
throw new ArgumentNullException(nameof(RequestQueueHandle));
			global::System.Threading.NativeOverlapped OverlappedLocal = Overlapped ?? default(global::System.Threading.NativeOverlapped);
			uint __result = PInvoke.HttpReceiveHttpRequest(RequestQueueHandleLocal, RequestId, Flags, RequestBufferLocal, RequestBufferLength, BytesReturned, Overlapped.HasValue ? &OverlappedLocal : null);
			return __result;
		}
	}
	finally
	{
		if (RequestQueueHandleAddRef)
			RequestQueueHandle.DangerousRelease();
	}
}

internal static extern unsafe uint HttpReceiveHttpRequest(winmdroot.Foundation.HANDLE RequestQueueHandle, ulong RequestId, winmdroot.Networking.HttpServer.HTTP_RECEIVE_HTTP_REQUEST_FLAGS Flags, winmdroot.Networking.HttpServer.HTTP_REQUEST_V2* RequestBuffer, uint RequestBufferLength, [Optional] uint* BytesReturned, [Optional] global::System.Threading.NativeOverlapped* Overlapped);

// From
HTTPAPI_LINKAGE ULONG HttpReceiveHttpRequest(
  [in]            HANDLE          RequestQueueHandle,
  [in]            HTTP_REQUEST_ID RequestId,
  [in]            ULONG           Flags,
  [out]           PHTTP_REQUEST   RequestBuffer,
  [in]            ULONG           RequestBufferLength,
  [out, optional] PULONG          BytesReturned,
  [in, optional]  LPOVERLAPPED    Overlapped
);

When I copy and modify the generated code as follows it works:

[SupportedOSPlatform("windows6.0.6000")]
internal static unsafe uint HttpReceiveHttpRequest(SafeHandle RequestQueueHandle, ulong RequestId, winmdroot.Networking.HttpServer.HTTP_RECEIVE_HTTP_REQUEST_FLAGS Flags, out winmdroot.Networking.HttpServer.HTTP_REQUEST_V2 RequestBuffer, uint RequestBufferLength, uint* BytesReturned, global::System.Threading.NativeOverlapped* Overlapped)
{
    bool RequestQueueHandleAddRef = false;
    try
    {
        fixed (winmdroot.Networking.HttpServer.HTTP_REQUEST_V2* RequestBufferLocal = &RequestBuffer)
        {
            winmdroot.Foundation.HANDLE RequestQueueHandleLocal;
            if (RequestQueueHandle is object)
            {
                RequestQueueHandle.DangerousAddRef(ref RequestQueueHandleAddRef);
                RequestQueueHandleLocal = (winmdroot.Foundation.HANDLE)RequestQueueHandle.DangerousGetHandle();
            }
            else
                throw new ArgumentNullException(nameof(RequestQueueHandle));
                
            uint __result = PInvoke.HttpReceiveHttpRequest(RequestQueueHandleLocal, RequestId, Flags, RequestBufferLocal, RequestBufferLength, BytesReturned, Overlapped);
            return __result;
        }
    }
    finally
    {
        if (RequestQueueHandleAddRef)
            RequestQueueHandle.DangerousRelease();
    }
}

I found #545 which first introduced NativeOverlapped support for ReadFile and I see that NativeOverlapped* is generated correctly there.

internal static unsafe winmdroot.Foundation.BOOL ReadFile(SafeHandle hFile, Span<byte> lpBuffer, uint* lpNumberOfBytesRead, global::System.Threading.NativeOverlapped* lpOverlapped) { ... }

// From
BOOL ReadFile(
  [in]                HANDLE       hFile,
  [out]               LPVOID       lpBuffer,
  [in]                DWORD        nNumberOfBytesToRead,
  [out, optional]     LPDWORD      lpNumberOfBytesRead,
  [in, out, optional] LPOVERLAPPED lpOverlapped
);
  1. Any of your own code that should be shared?
    Use generated PInvokes and exchange types dotnet/aspnetcore#50685

Context

  • CsWin32 version: 0.3.18-beta
  • Target Framework: net9.0
  • LangVersion preview

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions