СЦЕНАРИЙ
При P/Invoking я подумал, что было бы неплохо упростить/сократить тонны кода, разработав универсальную функцию, которая вызывает функцию, а затем проверяет 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
будет проигнорирован, если функция, естественно, не установит последнюю ошибку, поэтому в любом случае, независимо от того, какую функцию я перейду к этой общей функции SafePinvoke
, она не даст «ложное срабатывание» или по крайней мере я так думаю.
Тогда пример использования должен быть таким:
Во-первых, мы ищем функцию 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
На данный момент мы видим, что все работает, как и ожидалось, если окно найдено, оно вернет ненулевой Intptr, если окно не найдено, оно вернет Intptr.Zero , и, если функция не работает из-за пустой строки, она выдаст Win32Exception
с кодом ошибки 123, который относится к:
ОШИБКА_INVALID_NAME
123 (0x7B) The filename, directory name, or volume label syntax is incorrect.
Все кажется в порядке.
ВОПРОС
Мне нужно сказать это, чтобы аргументировать причину моего вопроса, я не буду вызывать ничего негативного, но случилось так, что некоторые очень опытные программисты сказали, что моя функция небезопасна, потому что я ошибаюсь во многих вещах о GetLastWin32Error, в эта тема:
Я намерен учиться на своих ошибках, но для этого я должен сначала найти доказательства этих ошибок, а я их не нашел.
Я хотел бы улучшить или, в случае необходимости, полностью удалить и переосмыслить подход универсальной функции SafePinvoke
выше, если он действительно не мог работать должным образом в обстоятельствах «X», просто я хотел бы увидеть и узнать, какие обстоятельства могут быть что, предоставив реальный образец кода, который можно протестировать для демонстрации ошибки/конфликта, мой вопрос:
Кто-нибудь может проиллюстрировать на реальном примере кода API-функции, что при передаче через функцию SafePinvoke
, описанную выше, она может давать «ложноположительную» ошибку или конфликт другого рода?
Кто-нибудь мог бы направить меня и объяснить, действительно ли функция SafePinvoke
безопасна или небезопасна, или ее можно улучшить, и что?, предоставив пример кода, который можно протестировать?.
Я буду очень признателен за любую информацию, которая может помочь мне улучшить этот подход или узнать, что этот подход действительно не будет работать в некоторых обстоятельствах, но, пожалуйста, приведите пример кода, демонстрирующий это.
DllImportAttribute.SetLastError
, чтобы среда выполнения .NET могла выдатьWin32Exception
с кодом ошибки, если он был установлен? То есть, разве среда выполнения .NET с помощью этого флага пользовательского атрибута уже не делает именно то, что вы делаете в своем методеSafePInvoke
? - person stakx - no longer contributing   schedule 17.06.2015GetLastError
сразу после возврата внешней функции. Этот статус ошибки отмечается и затем возвращаетсяGetLastWin32Error
. - person David Heffernan   schedule 17.06.2015HRESULTs
, указывающую на состояние ошибки, вComException
s. Я полагал, что CLR будет делать что-то подобное для вызовов платформы, отличной от COM.) - person stakx - no longer contributing   schedule 17.06.2015exitCode <> 0
, клиентскому коду необходимо использовать Try/Catch. Это не облегчает PInvoke, ИМО. Затем вам нужно быть абсолютно уверенным, чтоexitCode
верен, чтобы это было полезно, а вы нет, иначе вы бы не опубликовали это. Далее,result
иногда является данными (например, hwnd или text len), иногда это код ошибки T/F. Каждая функция WinAPI определяет свой собственный возврат, но этот универсальный метод не учитывает этого. Перечитайте комментарии Антона Тихого, связанные с, - person Ňɏssa Pøngjǣrdenlarp   schedule 17.06.2015