2009-05-13 5 views
2

Я обнаружил, что когда я добавляю новые события в существующий интерфейс COM/IDL, я иногда сталкиваюсь с непонятными проблемами, если они не добавлены в конец интерфейса.Зачем нужно добавлять новые события в * конец * интерфейса IDL?

Например, у меня есть следующий интерфейс:

interface IMyEvents 
{ 
    HRESULT FooCallback(
     [in] long MyParam1, 
     [in] long MyParam2, 
     [in] long MyParam3); 

    HRESULT BarCallback(
     [in] long MyParam1, 
     [in] BSTR MyParam2, 
     [in] BSTR MyParam3); 
}; 

Теперь давайте скажем, я хочу, чтобы добавить новое событие обратного вызова, NewCallback. Если добавить это так, я, как правило, не имеют каких-либо проблем, когда событие вызывается через COM:

interface IMyEvents 
{ 
    HRESULT FooCallback(
     [in] long MyParam1, 
     [in] long MyParam2, 
     [in] long MyParam3); 

    HRESULT BarCallback(
     [in] long MyParam1, 
     [in] BSTR MyParam2, 
     [in] BSTR MyParam3); 

    /* New event added to the end */ 
    HRESULT NewCallback(
     [in] BSTR MyParam1, 
     [in] BSTR MyParam2, 
     [in] BSTR MyParam3); 
}; 

Но если я добавляю это так, я могу бежать во все виды проблем (например, переполнение буфера) при запуске события.

interface IMyEvents 
{ 
    HRESULT FooCallback(
     [in] long MyParam1, 
     [in] long MyParam2, 
     [in] long MyParam3); 

    /* New event added to the middle */ 
    HRESULT NewCallback(
     [in] BSTR MyParam1, 
     [in] BSTR MyParam2, 
     [in] BSTR MyParam3); 

    HRESULT BarCallback(
     [in] long MyParam1, 
     [in] BSTR MyParam2, 
     [in] BSTR MyParam3); 
}; 

Я предполагаю, что это как-то связано с точками входа в DLL, смещениями адресов или чем-то подобным. Или, может быть, это потому, что я не перестроил что-то должным образом, и добавление его до конца позволяет ему работать по чистой удаче.

Может ли кто-нибудь объяснить это поведение?

ответ

4

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

В результате существующие клиенты называют BarCallback длинным целым числом, но вместо этого получают NewCallback, который считает, что это длинное целое является BSTR. Результаты часто оказываются неприемлемыми.

У вас будут проблемы с добавлением новых функций в конце. У старого COM-объекта не реализована новая функция и, скорее всего, просто произойдет сбой при попытке вызвать его.

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

+0

Извините, я должен был четко понять свой первоначальный вопрос. Все клиенты моего COM-интерфейса находятся под контролем меня, поэтому я могу перестроить их против изменений. Нет клиентов (насколько мне известно), которые я не могу перекомпилировать. Это COM-интерфейс, который используется внутри различных компонентов программного обеспечения, над которым я работаю. – LeopardSkinPillBoxHat

+0

Я предполагаю, что у вас есть бинарный клиент или сервер, который не был должным образом обновлен или зарегистрирован. Я бы предложил сделать чистую сборку и проверку на чистой машине. – sterin

+0

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

0

Я не думаю, что это имеет какое-то отношение к добавлению кода в конце.

Я помню добавление функции в середине файла интерфейса.

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