diff --git a/PInvoke/Shared/FunctionHelper.cs b/PInvoke/Shared/FunctionHelper.cs index 4a4977aa..a77fcc96 100644 --- a/PInvoke/Shared/FunctionHelper.cs +++ b/PInvoke/Shared/FunctionHelper.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Text; using Vanara.Extensions; using Vanara.InteropServices; @@ -8,6 +9,8 @@ namespace Vanara.PInvoke /// Generic functions to help with standard function patterns like getting a string from a method. public static class FunctionHelper { + private static readonly List buffErrs = new List { Win32Error.ERROR_MORE_DATA, Win32Error.ERROR_INSUFFICIENT_BUFFER, Win32Error.ERROR_BUFFER_OVERFLOW }; + /// Delegate to get the size of memory allocated to a pointer. /// The type of the size result. This is usually or . /// The pointer to the memory in question. @@ -44,7 +47,7 @@ namespace Vanara.PInvoke /// On input, the size of the capacity. On output, the number of characters written. /// The error. /// true if buffer size is good; otherwise false. - public static bool ChkGoodBuf(TSize sz, TRet err) where TSize : struct where TRet : IErrorProvider, IConvertible => !sz.Equals(default(TSize)) && (err.ToHRESULT() == (HRESULT)(Win32Error)Win32Error.ERROR_MORE_DATA || err.ToHRESULT() == (HRESULT)(Win32Error)Win32Error.ERROR_INSUFFICIENT_BUFFER); + public static bool ChkGoodBuf(TSize sz, TRet err) where TSize : struct where TRet : IErrorProvider, IConvertible => !sz.Equals(default(TSize)) && buffErrs.ConvertAll(e => (HRESULT)e).Contains(err.ToHRESULT()); /// Calls a method with and gets the resulting string or error. /// The type of the size result. This is usually or . @@ -87,20 +90,25 @@ namespace Vanara.PInvoke return ret; } - /// Calls a method with buffer for a type and gets the result or error. + /// + /// Calls a method with buffer for a type and gets the result or error. + /// /// The return type. - /// The type of the size result. This is usually or . + /// The type of the size result. This is usually or . /// Method to get the size of the buffer. /// The lambda or method to call into. - /// The resulting value of . - /// An optional method to convert the pointer to the type specified by . By default, this will marshal the pointer to the structure. - /// Resulting error or on success. - public static Win32Error CallMethodWithTypedBuf(SizeFunc getSize, PtrFunc method, out TOut result, Func outConverter = null) where TSize : struct, IConvertible + /// The resulting value of . + /// An optional method to convert the pointer to the type specified by . By default, this will marshal the pointer to the structure. + /// The optional error returns when the buffer size is insufficient. If left , then a list of well known errors will be used. + /// + /// Resulting error or on success. + /// + public static Win32Error CallMethodWithTypedBuf(SizeFunc getSize, PtrFunc method, out TOut result, Func outConverter = null, Win32Error? bufErr = null) where TSize : struct, IConvertible { TSize sz = default; result = default; var err = (getSize ?? GetSize)(ref sz); - if (err.Failed) return err; + if (err.Failed && (bufErr == null || bufErr.Value != err) && !buffErrs.Contains(err)) return err; using (var buf = new SafeHGlobalHandle(sz.ToInt32(null))) { var ret = method(buf.DangerousGetHandle(), ref sz); @@ -108,7 +116,7 @@ namespace Vanara.PInvoke return ret; } - Win32Error GetSize(ref TSize sz1) { var serr = method(IntPtr.Zero, ref sz1); return serr == Win32Error.ERROR_INSUFFICIENT_BUFFER || serr == Win32Error.ERROR_MORE_DATA ? Win32Error.ERROR_SUCCESS : serr; } + Win32Error GetSize(ref TSize sz1) => method(IntPtr.Zero, ref sz1); TOut Conv(IntPtr p, TSize s) => p.ToStructure(); } @@ -118,10 +126,11 @@ namespace Vanara.PInvoke /// The lambda or method to call into. /// Method to get the size of the buffer. /// An optional method to convert the pointer to the type specified by . By default, this will marshal the pointer to the structure. + /// The optional error returns when the buffer size is insufficient. If left , then a list of well known errors will be used. /// The resulting value of . - public static TOut CallMethodWithTypedBuf(PtrFunc method, SizeFunc getSize = null, Func outConverter = null) where TSize : struct, IConvertible + public static TOut CallMethodWithTypedBuf(PtrFunc method, SizeFunc getSize = null, Func outConverter = null, Win32Error? bufErr = null) where TSize : struct, IConvertible { - CallMethodWithTypedBuf(getSize, method, out var res, outConverter).ThrowIfFailed(); + CallMethodWithTypedBuf(getSize, method, out var res, outConverter, bufErr).ThrowIfFailed(); return res; } }