E_ACCESSDENIED error when IStream::Seek on Stream created using CreateStreamOnHGlobal on Windows 11 24H2 client

Robert Bui 0 Reputation points
2025-07-02T05:35:11.58+00:00

Hello all,

After days of debugging, I found I am getting E_ACCESSDENIED error on the server side (Windows Server 2022) when I try to seek to the beginning of a stream:

`ULARGE_INTEGER lPos;`
LARGE_INTEGER lZero;
lZero.QuadPart = 0;
auto hrTemp = pStream->Seek(lZero, STREAM_SEEK_SET, &lPos);

Where pStream is IStream* passing through from the client side (Windows 11 24H2):

IStream* pStream;
HRESULT hr = CreateStreamOnHGlobal(NULL, true, &pStream);

The first argument (ie hGlobal) is NULL so a new handle should be allocated.

If I run the same code client code on Windows 11 23H2, I got S_OK returned from pStream->Seek(....).

Has anyone came across this issue? If so, how did you resolve this?

Developer technologies | C++
{count} votes

1 answer

Sort by: Most helpful
  1. Varsha Dundigalla(INFOSYS LIMITED) 795 Reputation points Microsoft External Staff
    2025-07-08T10:15:35.83+00:00

    Thank you for reaching out. Please find the answer below.

    You're using CreateStreamOnHGlobal(NULL, TRUE, &pStream) on the client (Windows 11 24H2) to create an in-memory stream. When this stream is passed to a server (Windows Server 2022), the server tries to seek to the beginning of the stream using:

    LARGE_INTEGER lZero = {};
    ULARGE_INTEGER lPos;
    HRESULT hr = pStream->Seek(lZero, STREAM_SEEK_SET, &lPos);
    

    But this call fails with E_ACCESSDENIED. This issue does not occur when the client is running Windows 11 23H2.

    Why This Happens

    CreateStreamOnHGlobal creates a stream backed by global memory. When passed across processes or machines (e.g., via COM or RPC), the memory handle may not be valid or accessible on the receiving side. Windows 11 24H2 likely introduced stricter security or marshalling behavior, causing the stream to become inaccessible on the server.

    Recommended Solution

    Instead of using a memory-backed stream, use a file-backed stream. This is more reliable across process and machine boundaries.

    Working Example Using SHCreateStreamOnFileEx

    #include <windows.h>
    #include <shlwapi.h>
    #include <shlobj.h>
    #include <atlbase.h>  // For CComPtr
    
    #pragma comment(lib, "shlwapi.lib")
    
    int main() {
        CComPtr<IStream> pStream;
    
        // Create a file-backed stream
        HRESULT hr = SHCreateStreamOnFileEx(
            L"temp_stream.bin",                  // File name
            STGM_CREATE | STGM_READWRITE,       // Create and allow read/write
            FILE_ATTRIBUTE_NORMAL,              // File attributes
            TRUE,                                // Create file if it doesn't exist
            nullptr,                             // No template stream
            &pStream                             // Output stream
        );
    
        if (SUCCEEDED(hr)) {
            // Write data to the stream
            const char* data = "Hello, stream!";
            ULONG written = 0;
            pStream->Write(data, (ULONG)strlen(data), &written);
    
            // Seek back to the beginning
            LARGE_INTEGER liZero = {};
            ULARGE_INTEGER newPos;
            hr = pStream->Seek(liZero, STREAM_SEEK_SET, &newPos);
    
            if (SUCCEEDED(hr)) {
                char buffer[64] = {};
                ULONG read = 0;
                pStream->Read(buffer, written, &read);
                MessageBoxA(NULL, buffer, "Read from Stream", MB_OK);
            }
        }
    
        return 0;
    }
    

    This example creates a file-backed stream, writes data to it, seeks to the beginning, and reads it back. It avoids the E_ACCESSDENIED issue and works reliably across client-server boundaries.

    Let us know if the issue persists after following these steps. We’ll be happy to assist further if needed.


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.