2013-11-01 4 views
3

Мы разработали сборку .NET под названием XXadapter. Цель состоит в том, чтобы заставить XXadapter действовать как COM-объект для неуправляемых клиентов. Класс XXadapter реализует интерфейс C++ COM IDL. Объект C++ COM был добавлен в качестве ссылки на проект C#, таким образом предоставляя COM API через Interop. Поэтому интерфейс интерфейса класса _XXadapter был сгенерирован COM Interop и используется неуправляемыми клиентами.Интерфейс uuid и DispID интерфейса интерфейса изменяется при переходе с Visual Studio 2010 на 2012 год

Все было хорошо, пока я не попытался перенести проект XXadapter с VS2010 на VS2012 (обратите внимание, что нет изменений исходного кода). Ошибка uuid _XXadapter и часть DispID метода в _XXadapter были изменены.

Это свойство Класса XXadapter в:

[ComVisible(true)] 
[ComSourceInterfaces(typeof(_IBaseEvents))] 
[ClassInterface(ClassInterfaceType.AutoDual)] 
[Guid("class ID")] 
public partial class XXadapter : ICOMInterface 
{ 
... 
} 

Здесь вы _XXadapter определения в библиотеке типов (если смотреть на OLEView.exe) до миграции:

[ 
    odl, 
    uuid(E8******-****-****-****-************), 
    hidden, 
    dual, 
    nonextensible, 
    oleautomation, 
    custom(123456-1234-1234-1234-123456789012, CompanyName.XXadapter)  

] 
interface _XXadapter : IDispatch { 
    [id(00000000), propget, 
     custom(654321-4321-4321-4321-210987654321, 1)] 
    HRESULT ToString([out, retval] BSTR* pRetVal); 
    [id(0x60020001)] 
    HRESULT Equals(
        [in] VARIANT obj, 
        [out, retval] VARIANT_BOOL* pRetVal); 
    [id(0x60020002)] 
    HRESULT GetHashCode([out, retval] long* pRetVal); 
    [id(0x60020003)] 
    HRESULT GetType([out, retval] _Type** pRetVal); 
    [id(0x60020004)] 
    HRESULT GetVersion([out, retval] BSTR* pRetVal); 
    [id(0x60020005)] 
    HRESULT Method_one(...); 
    [id(0x60020006)] 
    HRESULT Method_two(...); 

    ... 

    [id(0x6002000e)] 
    HRESULT Method_three(...); 
    [id(0x6002000f)] 
    HRESULT Method_four(); 
    [id(0x60020010)] 
    HRESULT Method_five(...); 

    ... 
}; 

После перенастройки _XXadapter, определяемый как

[ 
    odl, 
    uuid(E6****-****-****-****-************), 
    hidden, 
    dual, 
    nonextensible, 
    oleautomation, 
    custom(123456-1234-1234-1234-123456789012, CompanyName.XXadapter)  

] 
interface _XXadapter : IDispatch { 
    [id(00000000), propget, 
     custom(654321-4321-4321-4321-210987654321, 1)] 
    HRESULT ToString([out, retval] BSTR* pRetVal); 
    [id(0x60020001)] 
    HRESULT Equals(
        [in] VARIANT obj, 
        [out, retval] VARIANT_BOOL* pRetVal); 
    [id(0x60020002)] 
    HRESULT GetHashCode([out, retval] long* pRetVal); 
    [id(0x60020003)] 
    HRESULT GetType([out, retval] _Type** pRetVal); 
    [id(0x60020004)] 
    HRESULT GetVersion([out, retval] BSTR* pRetVal); 
    [id(0x60020005)] 
    HRESULT Method_three(...); 
    [id(0x60020006)] 
    HRESULT Method_four(...); 
    [id(0x60020007)] 
    HRESULT Method_five(...); 
    [id(0x60020008)] 
    HRESULT Method_one(...); 
    [id(0x60020009)] 
    HRESULT Method_two(...); 

    ... 
}; 

Изменен не только uuid _XXadapter, но и DispID всех методов_XXXX().

В результате сборка _XXadapter утратила свою обратную совместимость со своими COM-клиентами.

Изучив и выполнив поиск по этой проблеме, я обнаружил, что переупорядочение Method_three/four/five() в библиотеке типов может быть вызвано этими тремя методами: partially declared в отдельном файле. Я попытался переместить объявление для всех видимых методов COM в один и тот же файл, эта проблема может быть решена. Однако это делает огромный файл, который мы изначально хотели избежать. Есть ли решение сохранить обратную совместимость, не перемещая COM видимые методы? Кто-нибудь знает основную причину переупорядочения методов? Огромное спасибо.

+0

Является ли ваш клиент COM ранним или поздним? Кроме того, можете ли вы показать некоторые (по крайней мере, заголовок) вашего класса C#? – Noseratio

+0

Спасибо Noseratio. Класс XXadapter частично определен со следующими атрибутами: '[ComVisible (true)] [ComSourceInterfaces (typeof (_IXXXEvents))] [ClassInterface (ClassInterfaceType.AutoDual)] [Guid (" 15 ****** - ** ** - **** - **** - ************ ")] Публичный частичный класс XXadapter: IXXVersion {...}' – Chloe

+0

Я [объяснил] (http : //stackoverflow.com/a/19777899/1768303), как вы могли бы попытаться имитировать бинарную совместимость, @Ivy. Стоит сделать снимок. – Noseratio

ответ

2

Вы показали слишком мало своего кода на C#, я не вижу, используете ли вы атрибуты [DispId] для общедоступных методов вашего класса. Кроме того, вы не ответили на мой вопрос в комментариях к COM client binding type. Какова природа вашего кода COM-клиента?

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

В случае раннего связывание (наиболее часто используется с C++ COM-клиентами), вы могли бы попытаться имитировать макет вашего старого, VS2010 сгенерированного класса интерфейса с новым, вручную определенным, тонко настроенным интерфейсом C# , чтобы сохранить двоичную совместимость (включая IID, макет методов и DispIds). В этом случае новый класс будет выглядеть следующим образом (обратите внимание на новый атрибут ComDefaultInterface(typeof(_XXadapter))):

[ComVisible(true)] 
[ClassInterface(ClassInterfaceType.None)] 
[ComDefaultInterface(typeof(_XXadapter))] 
[ComSourceInterfaces(typeof(_IXXXEvents))] 
[Guid("15******-****-****-****-************")] 
public partial class XXadapter: _XXadapter, ICOMInterface 
{ 
    // ... 
} 

Теперь новый интерфейс _XXadapter я говорю о том, будет выглядеть следующим образом:

// keep the IID and methods layout as generated by VS2010 for _XXadapter, 
// the way it appears in the IDL from OleView (interface _XXadapter) 

[ComVisible(true)] 
[InterfaceType(ComInterfaceType.InterfaceIsDual)] 
[Guid("E8****-****-****-****-************")] 
public interface _XXadapter { 
    [DispId(00000000)] 
    string ToString { get; } 

    [DispId(0x60020001)] 
    bool Equals([In] object obj); 

    // etc... 
} 

Этот Кстати, вы можете уйти без перекомпиляции вашего COM-клиента.

Кроме того, представляется, что класс XXadapter должен реализовать как интерфейсы _XXadapter, так и IComInterface, которые имеют те же имена методов. Это может быть сделано с помощью двух explicit implementations, разделяя общий код, т.е .:

public partial class XXadapter: _XXadapter, ICOMInterface 
{ 
    void _XXadapter.Method_one() { this.InternalMethodOne(); } 

    void ICOMInterface.Method_one() { this.InternalMethodOne(); } 

    private void InternalMethodOne() { /* the actual implementation */ } 
} 

Таким образом, метод InternalMethodOne будет содержать фактическую логику.

+0

Спасибо Noseratio. ** [DispID] ** не использовался для общедоступного метода в классе XXadapter. Я думаю, что тип привязки COM-клиента является ранним связыванием в нашем случае (извините, я пропустил этот вопрос). Вы правы, что _IXXXMethods (или _XXadapter, который был распознан COM-клиентами XXadapter) должен быть определен явно определенно, чтобы указать UUID и DispID. Однако, как я спросил Ганса, единственное, что у меня есть, это предупреждение, связанное с наследованием. – Chloe

+0

@ivy, это важная проблема. Вы разрешаете такие конфликты ** (явно реализуя) (http://msdn.microsoft.com/en-us/library/aa288461 (v = vs.71) .aspx) ** интерфейс. Например, внутри вашего класса: 'void _XXadapter.Method_one() {IComInterface.Method_one(); } ' – Noseratio

+0

Истоки интерфейсов (IComInterface), которые реализует XXadapter, находятся в устаревшем неуправляемом коде C++, поэтому сборка C# не является оригинальным создателем используемого интерфейса. Таким образом, невозможно вызвать 'IComInterface.Method_one();' при реализации 'void _XXadapter.Method_one().' На самом деле, XXadapter должен определить Method_one() по-своему. Это сообщение [link] (http://stackoverflow.com/questions/2952950/how-to-declare-and-implement-a-com-interface-on-c-sharp-that-inherits-from-anoth) может относиться к моей озабоченности. – Chloe

3

Направляющие имеют для изменения, требование к жестким требованиям в COM. Основная основная ошибка, которую вы сделали, - это демонстрация реализации класса. Видно, видя, как методы System.Object становятся доступными в вашем классе, например ToString, Equals и т. Д. Это подвергло вас риску перекомпоновки компилятором порядка методов, неопределенной детализации реализации.

Правильный способ сделать это - всегда делать реализацию невидимой. Пример:

[InterfaceType(ComInterfaceType.InterfaceIsDual)] 
[Guid("put the IID here")] 
public interface IXXadapter { 
    string ToString(); 
    bool Equals(object obj); 
    int GetHashCode(); 
    Type GetType(); 
    // etc... 
} 

[ClassInterface(ClassInterfaceType.None)] 
[Guid("put the CLSID here")] 
public class XXadapter : IXXadapter { 
    // etc.. 
} 

Примечание ClassInterfaceType.None, который скрывает внутренние элементы класса. COM-клиент видит только объявления интерфейса, они фиксированы и порядок предсказуем. Я включил 4 метода System.Object, которые вы изначально открыли, вам не нужно писать их реализацию. Это должно спасти вашу двоичную совместимость, просто убедитесь, что вы обновили атрибуты [Guid], чтобы они соответствовали старым.

+0

Я предполагаю, что исходный код, описанный выше, тот же, независимо от версии Visual Studio. Я не уверен, что у команд * есть *, чтобы изменить, просто потому, что код теперь скомпилирован с другой версией VS. Очевидно, объекты C++ COM не показывают эту проблему ... Не могли бы вы рассказать, Ганс? – alexg

+0

Версия VS не имеет значения, когда все сделано правильно. Как показано. При изменении интерфейса команды * должны * меняться *, жесткое правило COM. –

+0

Спасибо, Ханс, вы правы, что часть реализации класса XXadapter распространяется на его COM-клиентов. Кроме того, нет явного интерфейса для _XXadapter. Теперь мой вопрос заключается в том, что XXadapter наследуется от нескольких COM-интерфейсов, тогда, если я определяю _XXadapter и указываю ** [DispID()] **, чтобы сохранить обратную совместимость для этих методов, поддерживает ли этот новый определенный _XXadapter наследование? Я попытался, и компилятор попросил меня добавить ** новое ** ключевое слово, чтобы скрыть унаследованные элементы из-за предупреждения CS0108. – Chloe

 Смежные вопросы

  • Нет связанных вопросов^_^