解释什么问题可能有这个功能(如果有的话)
Explain what problems could have this function (if any)
场景
当 P/Invoking 时,我认为通过设计调用该函数的通用函数来 simplify/reduct 大量代码可能是个好主意,然后它会检查 GetLastWin32Error
我正在使用此代码:
''' <summary>
''' Invokes the specified encapsulated function, trying to provide a higher safety level for error-handling.
''' If the function that was called using platform invoke has the <see cref="DllImportAttribute.SetLastError"/>,
''' then it checks the exit code returned by the function, and, if is not a success code, throws a <see cref="Win32Exception"/>.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <typeparam name="T"></typeparam>
'''
''' <param name="expr">
''' The encapsulated function.
''' </param>
''' ----------------------------------------------------------------------------------------------------
''' <returns>
''' The type of the return value depends on the function definition.
''' </returns>
''' ----------------------------------------------------------------------------------------------------
''' <exception cref="Win32Exception">
''' Function 'X' thrown an unmanaged Win32 exception with error code 'X'.
''' </exception>
''' ----------------------------------------------------------------------------------------------------
<DebuggerStepThrough>
Private Shared Function SafePInvoke(Of T)(ByVal expr As Expression(Of Func(Of T))) As T
Dim result As T = expr.Compile.Invoke()
Dim method As MethodInfo =
CType(expr.Body, MethodCallExpression).Method
Dim isSetLastError As Boolean =
method.GetCustomAttributes(inherit:=False).
OfType(Of DllImportAttribute)().FirstOrDefault.SetLastError
If isSetLastError Then
Dim exitCode As Integer = Marshal.GetLastWin32Error
If exitCode <> 0 Then
Throw New Win32Exception([error]:=exitCode,
message:=String.Format("Function '{0}' thrown an unmanaged Win32 exception with error code '{1}'.",
method.Name, CStr(exitCode)))
End If
End If
Return result
End Function
我认为使这个高效的事情应该是 API 函数应该能够设置最后一个错误,并且,当函数能够做到这一点时,我应该设置 SetLastError
属性为 True,当然如果函数自然不设置最后一个错误,SetLastError=True
将被忽略,所以不管我使用哪种函数'll pass to this generic SafePinvoke
function, it will not give a "false positive", or at least I think not.
那么,一个用法示例应该是这样的:
首先,我们寻找一个 API 管理最后一个错误的函数,例如 FindWindow
其次,我们在代码中添加定义,在签名中设置SetLastError
属性。
<DllImport("user32.dll", SetLastError:=True)>
Private Shared Function FindWindow(
ByVal lpClassName As String,
ByVal zero As IntPtr
) As IntPtr
End Function
终于用上了
Dim lpszParentClass As String = "Notepad"
Dim parenthWnd As IntPtr =
SafePInvoke(Function() FindWindow(lpszParentClass, IntPtr.Zero))
If parenthWnd = IntPtr.Zero Then
MessageBox.Show(String.Format("Window found with HWND: {0}", CStr(parenthWnd)))
Else
MessageBox.Show("Window not found.")
End If
此时我们可以看到一切似乎都按预期工作,如果找到 window 它将 return 一个非零 Intptr,如果未找到 window,它将 return 一个 Intptr.Zero,并且,如果该函数因空字符串而失败,它将抛出一个 Win32Exception
错误代码 123 指的是:
ERROR_INVALID_NAME
123 (0x7B)
The filename, directory name, or volume label syntax is incorrect.
一切正常。
问题
我需要说这个来论证我的问题的原因,我不会造成任何负面影响,但事实是一些非常有经验的程序员说我的函数不安全,因为我错了很多关于 GetLastWin32Error 的事情,在这个线程中:
我的本意是从我的错误中吸取教训,但是为此,我首先应该遇到错误的证据,但我没有找到。
我想改进或在需要的情况下完全删除并重新考虑上面通用函数 SafePinvoke
的方法,如果它确实无法在 "X" 情况下按预期工作,只是我想看看并了解可能是什么情况,通过提供一个可以测试的真实代码示例来演示 error/conflict,那么,我的问题是:
有人可以用 API 函数的真实代码示例来说明,当通过上面的 SafePinvoke
函数时,它可能会给出 "false positive" 错误或其他类型的错误冲突?
如果 SafePinvoke
函数真的安全,或者不安全,或者它是否可以改进,那么有人可以指导我并解释我吗?提供一个可以测试的代码示例.
我将非常感谢所有可以帮助我改进这种方法的信息,或者了解这种方法在某些情况下确实行不通的信息,但请提供一个代码示例来证明它。
来自 GetLastError
的文档:
The Return Value section of the documentation for each function that sets the last-error code notes the conditions under which the function sets the last-error code. Most functions that set the thread's last-error code set it when they fail. However, some functions also set the last-error code when they succeed. If the function is not documented to set the last-error code, the value returned by this function is simply the most recent last-error code to have been set; some functions set the last-error code to 0 on success and others do not.
换句话说,无条件调用GetLastError
是错误的。 GetLastError
returns 非零值并不表示最近的 API 调用失败。此外,GetLastError
返回零不表示成功。
场景
当 P/Invoking 时,我认为通过设计调用该函数的通用函数来 simplify/reduct 大量代码可能是个好主意,然后它会检查 GetLastWin32Error
我正在使用此代码:
''' <summary>
''' Invokes the specified encapsulated function, trying to provide a higher safety level for error-handling.
''' If the function that was called using platform invoke has the <see cref="DllImportAttribute.SetLastError"/>,
''' then it checks the exit code returned by the function, and, if is not a success code, throws a <see cref="Win32Exception"/>.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <typeparam name="T"></typeparam>
'''
''' <param name="expr">
''' The encapsulated function.
''' </param>
''' ----------------------------------------------------------------------------------------------------
''' <returns>
''' The type of the return value depends on the function definition.
''' </returns>
''' ----------------------------------------------------------------------------------------------------
''' <exception cref="Win32Exception">
''' Function 'X' thrown an unmanaged Win32 exception with error code 'X'.
''' </exception>
''' ----------------------------------------------------------------------------------------------------
<DebuggerStepThrough>
Private Shared Function SafePInvoke(Of T)(ByVal expr As Expression(Of Func(Of T))) As T
Dim result As T = expr.Compile.Invoke()
Dim method As MethodInfo =
CType(expr.Body, MethodCallExpression).Method
Dim isSetLastError As Boolean =
method.GetCustomAttributes(inherit:=False).
OfType(Of DllImportAttribute)().FirstOrDefault.SetLastError
If isSetLastError Then
Dim exitCode As Integer = Marshal.GetLastWin32Error
If exitCode <> 0 Then
Throw New Win32Exception([error]:=exitCode,
message:=String.Format("Function '{0}' thrown an unmanaged Win32 exception with error code '{1}'.",
method.Name, CStr(exitCode)))
End If
End If
Return result
End Function
我认为使这个高效的事情应该是 API 函数应该能够设置最后一个错误,并且,当函数能够做到这一点时,我应该设置 SetLastError
属性为 True,当然如果函数自然不设置最后一个错误,SetLastError=True
将被忽略,所以不管我使用哪种函数'll pass to this generic SafePinvoke
function, it will not give a "false positive", or at least I think not.
那么,一个用法示例应该是这样的:
首先,我们寻找一个 API 管理最后一个错误的函数,例如 FindWindow
其次,我们在代码中添加定义,在签名中设置
SetLastError
属性。<DllImport("user32.dll", SetLastError:=True)> Private Shared Function FindWindow( ByVal lpClassName As String, ByVal zero As IntPtr ) As IntPtr End Function
终于用上了
Dim lpszParentClass As String = "Notepad" Dim parenthWnd As IntPtr = SafePInvoke(Function() FindWindow(lpszParentClass, IntPtr.Zero)) If parenthWnd = IntPtr.Zero Then MessageBox.Show(String.Format("Window found with HWND: {0}", CStr(parenthWnd))) Else MessageBox.Show("Window not found.") End If
此时我们可以看到一切似乎都按预期工作,如果找到 window 它将 return 一个非零 Intptr,如果未找到 window,它将 return 一个 Intptr.Zero,并且,如果该函数因空字符串而失败,它将抛出一个 Win32Exception
错误代码 123 指的是:
ERROR_INVALID_NAME
123 (0x7B) The filename, directory name, or volume label syntax is incorrect.
一切正常。
问题
我需要说这个来论证我的问题的原因,我不会造成任何负面影响,但事实是一些非常有经验的程序员说我的函数不安全,因为我错了很多关于 GetLastWin32Error 的事情,在这个线程中:
我的本意是从我的错误中吸取教训,但是为此,我首先应该遇到错误的证据,但我没有找到。
我想改进或在需要的情况下完全删除并重新考虑上面通用函数 SafePinvoke
的方法,如果它确实无法在 "X" 情况下按预期工作,只是我想看看并了解可能是什么情况,通过提供一个可以测试的真实代码示例来演示 error/conflict,那么,我的问题是:
有人可以用 API 函数的真实代码示例来说明,当通过上面的 SafePinvoke
函数时,它可能会给出 "false positive" 错误或其他类型的错误冲突?
如果 SafePinvoke
函数真的安全,或者不安全,或者它是否可以改进,那么有人可以指导我并解释我吗?提供一个可以测试的代码示例.
我将非常感谢所有可以帮助我改进这种方法的信息,或者了解这种方法在某些情况下确实行不通的信息,但请提供一个代码示例来证明它。
来自 GetLastError
的文档:
The Return Value section of the documentation for each function that sets the last-error code notes the conditions under which the function sets the last-error code. Most functions that set the thread's last-error code set it when they fail. However, some functions also set the last-error code when they succeed. If the function is not documented to set the last-error code, the value returned by this function is simply the most recent last-error code to have been set; some functions set the last-error code to 0 on success and others do not.
换句话说,无条件调用GetLastError
是错误的。 GetLastError
returns 非零值并不表示最近的 API 调用失败。此外,GetLastError
返回零不表示成功。