Лучшие практики для организации кода .NET P / Invoke в Win32 API - PullRequest
12 голосов
/ 12 марта 2010

Я занимаюсь рефакторингом большой и сложной базы кода в .NET, которая интенсивно использует P / Invoke для Win32 API. Структура проекта не самая лучшая, и я нахожу повсюду операторы DllImport, которые очень часто дублируются для одной и той же функции, а также объявляются различными способами:

Директивы и методы импорта иногда объявляются как публичные, иногда приватные, иногда как статические, а иногда как методы экземпляра. Меня беспокоит то, что рефакторинг может иметь непредвиденные последствия, но это может быть неизбежным.

Существуют ли задокументированные передовые практики, которым я могу следовать, которые могут мне помочь?

Мой инстинкт состоит в том, чтобы организовать статический / общий класс Win32 P / Invoke API, который перечисляет все эти методы и связанные с ними константы в одном файле ... EDIT Существует более 70 импортов в DLL-файл user32.

(База кода состоит из более чем 20 проектов с множеством оконных сообщений и межпотоковых вызовов. Это также проект VB.NET, обновленный с VB6, если это имеет значение.)

Ответы [ 6 ]

5 голосов
/ 12 марта 2010

Вы могли бы рассмотреть способ, которым это было сделано в .NET Framework. Он неизменно объявляет статический класс (модуль в VB.NET) с именем NativeMethods, который содержит объявления P / Invoke. Вы могли бы быть более организованным, чем программисты Microsoft, есть много повторяющихся объявлений. Разные команды работают над разными частями фреймворка.

Однако, если вы хотите поделиться этим среди всех проектов, вы должны объявить эти объявления Public вместо Friend. Что не здорово, это должна быть деталь реализации. Я думаю, что вы можете решить эту проблему, повторно используя файл исходного кода в каждом проекте, который в этом нуждается. Обычно это табу, но в этом случае все в порядке, я думаю.

Я лично объявляю их по мере необходимости в файле исходного кода, который нуждается в них, делая их конфиденциальными. Это также очень помогает, когда лжет о типах аргументов, особенно для SendMessage.

3 голосов
/ 12 марта 2010

Организуйте их в [Safe|Unsafe]NativeMethods класс . Отметьте класс как internal static. Если вам нужно выставить их для ваших собственных сборок, вы можете использовать InternalsVisibleTo - хотя было бы более уместно, если бы вы могли группировать связанные в каждой сборке.

Каждый метод должен быть static - я, честно говоря, не знал, что вы даже можете пометить методы экземпляра DllImport.

В качестве первого шага - я бы, вероятно, переместил все в сборку Core (если она у вас есть) или создал бы сборку Product.Native. Тогда вы сможете легко находить дубликаты и совпадения и искать управляемые эквиваленты. Если ваши p / вызывает беспорядок, я не подозреваю, что у вас есть много способов наслоения в других сборках, которые будут направлять вашу группировку.

2 голосов
/ 12 марта 2010

Рекомендуется использовать класс NativeMethods для каждой сборки со всеми методами DllImported с внутренней видимостью.Таким образом, вы всегда будете знать, где находится импортируемая функция, и избегаете дублирования объявлений.

2 голосов
/ 12 марта 2010

Ваш P / Invoke вызывает артефакт перехода с VB6? Я перенес 300 000 строк кода из VB6 в C # (Windows.Forms и System.EnterpriseServices) и исключил все, кроме нескольких вызовов P / Invokes - почти всегда существует управляемый эквивалент. Если вы проводите рефакторинг, возможно, вы захотите сделать что-то подобное. Полученный код должен быть проще в обслуживании.

2 голосов
/ 12 марта 2010

Почему бы не создать отдельный файл с именем Win32.vb и внутри него логически сгруппировать пинвоки в отдельные пространства имен, например, пространство имен GDI может использовать все пинвики GDI, пространство имен User32 может использовать все пинвоки, которые находятся в ядре User32, и так на .... это может быть болезненно на первый взгляд, но, по крайней мере, у вас будут централизованные пространства имен, содержащиеся в этом файле? Взгляните здесь , чтобы понять, что я имею в виду ... Что вы думаете?

2 голосов
/ 12 марта 2010

В этом случае я обычно стараюсь делать то, о чем вы говорите, создавать различные классы, статические или нет, которые предоставляют функциональность, таким образом, ее можно использовать повторно по мере необходимости. В зависимости от характера вызовов, я бы уклонился от реализации статического класса, но это будет зависеть от вашей конкретной реализации.

Расширение сверху по запросу.

Учитывая природу P / Invoke, особенно если требуется несколько вызовов и они имеют разные области реализации, я считаю, что лучше группировать подобные элементы вместе, таким образом, вы не тратите много других помех или другие библиотеки DLL импортируются, когда они не нужны.

Желание избежать статических методов связано с обращениями к неуправляемым ресурсам и возможностью утечек памяти и т. Д.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...