Лучшие практики для организации.NET P/Invoke кодируют к API Win32

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

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

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

Мой instict должен организовать статический/общий Win32 P/Invoke класс API, который перечисляет все эти методы и связанные константы в одном файле... РЕДАКТИРОВАНИЕ Там является более чем 70 импортом в user32 DLL.

(Кодовая база составлена из более чем 20 проектов с большой передачей сообщений окон и вызовами перекрестного потока. Это - также проект VB.NET, обновленный от VB6, если это имеет значение.)

12
задан Paul Sasik 12 March 2010 в 17:11
поделиться

6 ответов

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

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

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

5
ответ дан 2 December 2019 в 20:16
поделиться

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

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

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

3
ответ дан 2 December 2019 в 20:16
поделиться

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

2
ответ дан 2 December 2019 в 20:16
поделиться

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

2
ответ дан 2 December 2019 в 20:16
поделиться

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

Расширение выше по просьбе.

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

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

2
ответ дан 2 December 2019 в 20:16
поделиться

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

2
ответ дан 2 December 2019 в 20:16
поделиться