I don't trust your error code.
There are two functions that provide error information: GetLastError and GetLastWin32Error.
The former returns the latest Win32 error, but that might be associated to something other than your explicit Win32 p/invoke operation (e.g. when another thread intervenes and somehow calls Win32).
The latter returns the error code from the most recent Win32 call that had
the DllImport attribute
Since you didn't use the attribute, the error code returned does not belong to your Win32 call.
Using GetLastError (which often gives the right error code) is better than using GetLastWin32Error on a Win32 that was declared without the attribute (as that always returns wrong error codes). However GetLastWin32Error with the attribute clearly is best.
For more info, see e.g. If you are going to call Marshal.GetLastWin32Error, the function whose error you're retrieving had better have SetLastError=true - The Old New Thing
You did not show the code that assigns some value to
; chances are that is where the problem is.
You did not show the creation of
; it should have a preallocated size ("capacity") equal to (or exceeding) whatever value nChars has.
(2)+(3) = whatever is wrong sits just before the code you have shown us!