Разработка DLL на языке С++, страница 10

Рассмотрим второй способ устранения препятствий, вызванных декорацией имен. Для того, чтобы реализовать его надо возвратиться к серверному проекту MyDLL, вставить в нужные места описатель extern "C" (именно он отменяет декорацию имен) и построить DLL заново. Кроме отмены декораций, этот описатель заменяет способ передачи параметров, вместо __cdecl он становится __stdcall. При этом прежний клиент (на языке С++) перестанет работать. Клиентское приложение тоже придется перестроить, введя исправления, то есть вставить в нужные места описатели extern "C".

Подведем итог, вы открываете проект MyDLL и либо вставляете много описателей extern "C", например,

extern "C" __declspec(dllexport) void AllocMatrix (double**& a, int ny, int nx)

{

// Код функции AllocMatrix

}

extern "C" __declspec(dllexport) void ClearMatrix (double**& a, int n)

{

// и т.д. перед каждой экспортируемой сущностью либо заключаете все экспортируемые сущности в один большой блок:

extern "C"

{

// Здесь расположены все экспортируемые сущности

}

Это надо сделать как в серверном проекте, так и в клиентском проекте на языке С++ (если вы хотите, чтобы он продолжал работать). В проекте на языке C# надо вернуться к первому способу вызова функций (по именам). После этого все проекты должны работать. Трудно проделать все это без ошибок, но делать все равно надо, хотя бы для того, чтобы убедиться в своей квалификации (или в том, что перед тем как принять важное архитектурное решение, надо очень тщательно продумать все детали). Мне не нравятся все эти заплаты, но я понимаю, что их необходимость была заложена давно и из хороших побуждений.

Characteristic

COM Model

.NET Framework Model

Coding model

Interface based

Object based

Identity

GUIDs

Strong names

Type compatibility

Binary standard

Type standard

Type definition

Type library

Metadata

Type safety

Not type-safe

Optionally safe

Error-handling mechanism

HResults

Exceptions

Object-lifetime management

Reference counting

Garbage collection

Versioning

Immutable

Resilient

Strong names consist of a unique assembly name in addition to a type name. Because the assembly name uniquely identifies the type, you can reuse a type name across multiple assemblies. An assembly also introduces publisher key, version, and location information to a managed type.

¨  In COM Model type information is stored only for public types. Moreover, a type library is optional.

¨  In .NET Framework Model type information is stored as metadata (which is embedded inside assemblies) and is mandatory for all types.

¨  COM interfaces are immutable. If you change an interface, you must rename it with a new GUID.

¨  Versioning in .NET Framework Model is resilient — managed types can evolve, retaining the same name.

The CLR enables managed code to call COM objects through a proxy called the Runtime Callable Wrapper (RCW). When a .NET Client loads a COM object, a runtime callable wrapper (RCW) is created. The runtime creates exactly one RCW for each COM object, regardless of the number of references that exist on that object. This ensures that a single object identity is shared between the RCW and the COM object. The RCW is a managed object and subject to garbage collection. The primary goal of the RCW is to hide the differences between the managed and unmanaged programming models. .NET-based applications can bind to COM classes in an early or late bound fashion. Early binding requires complete type information for the COM class at compile-time and requires the underlying COM class to support early binding as well. COM type definitions usually reside in a type library. To use COM types in managed code, you must generate metadata from type libraries.