Is it possible/allowed to return a dereferenced pointer of an struct from C# pinvoke code like that. The struct is blittable. The Pinvoke code and the struct are generated with CsWin32. Thanks for any help related to that :)
internal static unsafe IEnumerable<ENUM_SERVICE_STATUS_PROCESSW> GetAllServices(this CloseServiceHandleSafeHandle serviceManagerHandle, string? group)
{
ArgumentNullException.ThrowIfNull(serviceManagerHandle);
var data = new List<ENUM_SERVICE_STATUS_PROCESSW>();
var serviceManagerHandleAddRef = false;
try
{
serviceManagerHandle.DangerousAddRef(ref serviceManagerHandleAddRef);
bool moreData;
uint bytesNeeded = 0, resumeHandle = 0, servicesReturned = 0;
do
{
moreData = false;
var bufferData = new byte[bytesNeeded];
fixed (byte* ptrBufferData = bufferData)
{
fixed (char* ptrGroup = group)
{
if (!PInvokeCore.EnumServicesStatusEx((SC_HANDLE)serviceManagerHandle.DangerousGetHandle(), SC_ENUM_TYPE.SC_ENUM_PROCESS_INFO, ENUM_SERVICE_TYPE.SERVICE_WIN32_OWN_PROCESS, ENUM_SERVICE_STATE.SERVICE_STATE_ALL, ptrBufferData, (uint)bufferData.Length, &bytesNeeded, &servicesReturned, &resumeHandle, ptrGroup))
{
if (Marshal.GetLastPInvokeError() != (uint)WIN32_ERROR.ERROR_MORE_DATA)
throw new Exception($"Could not enumerate services. {Marshal.GetLastPInvokeErrorMessage()}");
else
moreData = true;
}
}
for (var i = 0; i < servicesReturned; i++)
{
ENUM_SERVICE_STATUS_PROCESSW element = ((ENUM_SERVICE_STATUS_PROCESSW*)ptrBufferData)[i];
data.Add(element);
}
}
} while (moreData);
}
finally
{
if (serviceManagerHandleAddRef)
serviceManagerHandle.DangerousRelease();
}
return data;
}
It works but I'm not sure if that is an illegal operation.
The answer is no it is not save to return the struct. The struct itself is a copy so it it safe to return but in the struct is a PWSTR aka a char* and that pointer points to an area in the byte* (just after the array of structs) which is not valid after the function returns.