diff --git a/PInvoke/Shared/FunctionHelper.cs b/PInvoke/Shared/FunctionHelper.cs index 64f3c34e..2590041a 100644 --- a/PInvoke/Shared/FunctionHelper.cs +++ b/PInvoke/Shared/FunctionHelper.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Text; -using Vanara.Extensions; using Vanara.InteropServices; namespace Vanara.PInvoke @@ -9,7 +8,7 @@ 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 }; + private static readonly List buffErrs = new() { 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 . @@ -18,9 +17,7 @@ namespace Vanara.PInvoke /// Resulting error or on success. public delegate Win32Error PtrFunc(IntPtr ptr, ref TSize sz) where TSize : struct, IConvertible; - /// - /// Delegate that takes and StringBuilder and initial size and returns a result. - /// + /// Delegate that takes and StringBuilder and initial size and returns a result. /// The type of the size result. This is usually or . /// The return type. /// The value. @@ -28,6 +25,28 @@ namespace Vanara.PInvoke /// The return value. Often this is an error. public delegate TRet SBFunc(StringBuilder sb, ref TSize sz) where TSize : struct, IConvertible; + /// Delegate that takes and StringBuilder and initial size and returns a result. + /// The type of the first parameter. + /// The type of the size result. This is usually or . + /// The return type. + /// The first parameter. + /// The value. + /// On input, the size of the capacity. On output, the number of characters written. + /// The return value. Often this is an error. + public delegate TRet SBFunc(T1 arg1, StringBuilder sb, ref TSize sz) where TSize : struct, IConvertible; + + /// Delegate that takes and StringBuilder and initial size and returns a result. + /// The type of the first parameter. + /// The type of the second parameter. + /// The type of the size result. This is usually or . + /// The return type. + /// The first parameter. + /// The second parameter. + /// The value. + /// On input, the size of the capacity. On output, the number of characters written. + /// The return value. Often this is an error. + public delegate TRet SBFunc(T1 arg1, T2 arg2, StringBuilder sb, ref TSize sz) where TSize : struct, IConvertible; + /// Gets a size and returns an error. /// The type of the size result. This is usually or . /// On input, the size of the capacity. On output, the number of characters written. @@ -39,16 +58,6 @@ namespace Vanara.PInvoke /// Resulting error or on success. public static Win32Error BoolToLastErr(bool result) => result ? Win32Error.ERROR_SUCCESS : Win32Error.GetLastError(); - /// - /// Checks to see if size is not 0 and if the error is requesting a larger buffer. - /// - /// The type of the size result. This is usually or . - /// The error provider return type. - /// 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)) && 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 . /// The return type. @@ -71,8 +80,62 @@ namespace Vanara.PInvoke var ret = method(sb, ref sz); result = sb.ToString(); return ret; + } - bool IsNotDef(TSize _sz, TRet _ret) => !_sz.Equals(default(TSize)); + /// Calls a method with and gets the resulting string or error. + /// The type of the first parameter. + /// The type of the size result. This is usually or . + /// The return type. + /// The lambda or method to call into. + /// The first parameter. + /// The resulting string value. + /// An optional method to determine if a valid size was retrieved by . + /// The return value of . + public static TRet CallMethodWithStrBuf(SBFunc method, T1 arg1, out string result, + Func gotGoodSize = null) where TSize : struct, IConvertible + { + TSize sz = default; + var ret0 = method(arg1, null, ref sz); + if (!(gotGoodSize ?? IsNotDef)(sz, ret0)) + { + result = null; + return ret0; + } + var len = sz.ToInt32(null) + 1; + var sb = new StringBuilder(len, len); + sz = (TSize)Convert.ChangeType(len, typeof(TSize)); + var ret = method(arg1, sb, ref sz); + result = sb.ToString(); + return ret; + } + + /// Calls a method with and gets the resulting string or error. + /// The type of the first parameter. + /// The type of the second parameter. + /// The type of the size result. This is usually or . + /// The return type. + /// The lambda or method to call into. + /// The first parameter. + /// The second parameter. + /// The resulting string value. + /// An optional method to determine if a valid size was retrieved by . + /// The return value of . + public static TRet CallMethodWithStrBuf(SBFunc method, T1 arg1, T2 arg2, out string result, + Func gotGoodSize = null) where TSize : struct, IConvertible + { + TSize sz = default; + var ret0 = method(arg1, arg2, null, ref sz); + if (!(gotGoodSize ?? IsNotDef)(sz, ret0)) + { + result = null; + return ret0; + } + var len = sz.ToInt32(null) + 1; + var sb = new StringBuilder(len, len); + sz = (TSize)Convert.ChangeType(len, typeof(TSize)); + var ret = method(arg1, arg2, sb, ref sz); + result = sb.ToString(); + return ret; } /// Calls a method with and gets the resulting string or error. @@ -91,20 +154,23 @@ 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. - /// 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 + /// 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; @@ -128,13 +194,49 @@ namespace Vanara.PInvoke /// The type of the size result. This is usually or . /// 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. + /// + /// 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, Win32Error? bufErr = 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, bufErr).ThrowIfFailed(); return res; } + + /// Checks to see if size is not 0 and if the error is requesting a larger buffer. + /// The type of the size result. This is usually or . + /// The error provider return type. + /// 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)) && buffErrs.ConvertAll(e => (HRESULT)e).Contains(err.ToHRESULT()); + + private static bool IsNotDef(TSize _sz, TRet _ret) where TSize : struct, IConvertible => !_sz.Equals(default(TSize)); + + /* + public delegate TRet P0QI(in Guid iid, out object ppv) where TRet : IErrorProvider, IConvertible; + public delegate TRet P1QI(TIn1 p1, in Guid iid, out object ppv) where TRet : IErrorProvider, IConvertible; + public delegate TRet P1IQI(in TIn1 p1, in Guid iid, out object ppv) where TIn1 : struct where TRet : IErrorProvider, IConvertible; + public delegate TRet P2QI(TIn1 p1, TIn2 p2, in Guid iid, out object ppv) where TRet : IErrorProvider, IConvertible; + + public static TIntf QueryInterface(P0QI f) => f0(typeof(TIntf).GUID, out object ppv).Succeeded ? (TIntf)ppv : throw new InvalidCastException(); + public static TIntf QueryInterface(P1QI f, TIn1 p1) => QueryInterface(f1, p1, hr => hr.Succeeded); + public static TIntf QueryInterface(P1IQI f, in TIn1 p1) where TIn1 : struct => QueryInterface(f1, in p1, hr => hr.Succeeded); + + private void Test() + { + static HRESULT GetObj(uint f, in Guid iid, out object ppv); + + X x = QueryInterface(GetObj, 3U); + } + */ } } \ No newline at end of file