Я недавно унаследовал проект, который создает и реализует COM-класс / интерфейс COM в DLL. Эта COM DLL используется приложением, которое применяет графический интерфейс к интерфейсу класса COM. Это единственное приложение, которое использует COM DLL. Я новичок в работе с COM, и найти хорошую документацию сложно.
Часть моей задачи включает добавление некоторых методов / свойств (а также удаление некоторых ненужных) в интерфейс. Я узнал, что мне нужно изменить IDL для достижения этой цели. Прямо сейчас я просто добавил свои новые методы и свойства в конец интерфейса, и кажется, что все работает хорошо. Однако, когда я удаляю одно из свойств (например), все быстро ухудшается при запуске приложения.
interface IMyComInterface : IDispatch
{
[id(1), helpstring("method CheckMessage")] HRESULT CheckMessage([in] VARIANT vMsg);
[id(2), helpstring("method CheckFolder")] HRESULT CheckFolder([in] VARIANT Folder, [out] VARIANT *pCount, [out, retval] VARIANT *pErrorCount);
//[propget, id(3), helpstring("property Flags")] HRESULT Flags([out, retval] VARIANT *pVal);
//[propput, id(3), helpstring("property Flags")] HRESULT Flags([in] VARIANT newVal);
[propget, id(4), helpstring("property MessageStore")] HRESULT MessageStore([out, retval] VARIANT *pVal);
[propput, id(4), helpstring("property MessageStore")] HRESULT MessageStore([in] VARIANT newVal);
[propget, id(5), helpstring("property Directory")] HRESULT Directory([out, retval] VARIANT *pVal);
[propput, id(5), helpstring("property Directory")] HRESULT Directory([in] VARIANT newVal);
}
Я предполагаю, что это связано с разбитой последовательностью идентификационных номеров. Я полагаю, я мог бы сдвинуть все под это, и все будет работать. Но мне любопытно, как правильно все это делать.
Большое спасибо.
Если графический интерфейс использует IDispatch::Invoke
чтобы вызывать ваши методы, он должен быть устойчивым к изменениям в интерфейсе (если вы сохраняете идентификаторы одинаковыми), поскольку вызовы методов разрешаются во время выполнения (позднее связывание). Обычно программы VB6 и языки сценариев работают таким образом.
Однако, если графический интерфейс скомпилирован непосредственно IMyComInterface
(что наиболее вероятно, если это приложение на C ++ или C #), важен точный порядок методов в интерфейсе. Вызовы метода разрешаются во время компиляции (раннее связывание), а индекс метода в интерфейсе сохраняется в COM-клиенте. Если вы удалите метод из IDL, все вызовы функций из клиента будут отключены одним. Вот почему добавление нового метода в конце работает, а удаление методов в середине — нет.
Самый простой способ обойти все эти проблемы (поскольку вы управляете как DLL-библиотекой COM, так и графическим интерфейсом) — убедиться, что вы перекомпилировали все после изменения IDL. В общем случае, однако, вы должны рассматривать каждый интерфейс как «неизменный контракт функциональной группы методов» (источник), и никогда не изменяйте интерфейс COM после того, как он был выпущен в мир.
Если COM-клиент — C ++, он, вероятно, будет использовать раннее связывание (что означает, что он полагается на неизменный макет интерфейса) вместо позднего связывания. В этом случае не имеет значения, что такое DISPID, потому что DISPID используются для позднего связывания, а не для раннего связывания. Вот почему удаление методов / свойств из интерфейса сломает клиент, если вы не перекомпилируете его. Вот почему не рекомендуется менять COM-интерфейсы, а вместо этого добавлять новые интерфейсы, которые наследуются от старого, и добавлять новые функциональные возможности:
interface IMyComInterface : IDispatch
{
// existing methods/properties
}
interface IMyComInterface2 : IMyComInterface
{
// new methods/properties
}