See the question and my original answer on StackOverflow

Your code doesn't work because you're implicitly opening the stream as read-only. To open it for write operations, you must pass a binding context, something like this:

IBindCtx* ctx;
CreateBindCtx(0, &ctx);

BIND_OPTS options = {};
options.cbStruct = sizeof(BIND_OPTS);
options.grfMode = STGM_WRITE;
ctx->SetBindOptions(&options);

...
pShellfolder->BindToStorage(pidlRelative, ctx, IID_IStream, (void**)&pStream);
...

Otherwise, when you work with COM objects, you should smart pointers to avoid COM reference leaks. For example, below, I use ATL that comes with Visual Studio, but there's also WRL and C++/WinRT (which can do some basic COM stuff too)

Also, for Shell objects it's much easier to work with IShellItem and friends and all ("Item") APIs that come with it, like this (error checks omitted here but you should test every single HRESULT for error) and avoid the old IShellFolder:

CComPtr<IShellItem> item;
SHCreateItemFromParsingName(fileName.c_str(), nullptr, IID_PPV_ARGS(&item));

CComPtr<IBindCtx> ctx;
CreateBindCtx(0, &ctx);

BIND_OPTS options = {};
options.cbStruct = sizeof(BIND_OPTS);
options.grfMode = STGM_WRITE;
ctx->SetBindOptions(&options);

CComPtr<IStream> stream;
item->BindToHandler(ctx, BHID_Stream, IID_PPV_ARGS(&stream));

stream->Write("Test-test-test-test", 19, nullptr);