Search code examples
c#pointerswinapipinvoke

Is it allowed to return a dereferenced pointer of a blittable struct in C#


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.


Solution

  • 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.