Реализация COM-приемника в управляемом (C#) коде
У меня есть устаревший элемент управления COM (Core), который принимает IUnknown
в раковину. Цель состоит в том, чтобы позволить ядру считывать / записывать данные через этот интерфейс приемника. Указатели Core/Sink в настоящее время используются в устаревших системах и не могут быть легко изменены.
У меня проблема, когда я пытаюсь вызвать ядро из управляемого кода и передать объект, который (пытается) реализовать приемник в управляемом коде. Я отладил ядро до такой степени, что оно готовится вызвать сток. До (не после) звонка я получаю сообщение, похожее на:
Ошибка проверки времени выполнения #0 - значение ESP не было должным образом сохранено при вызове функции...
Я видел и работал с ними в чистом унаследованном коде, но введение управляемого кода меня озадачило.
Вот самые маленькие представления двух интерфейсов, которые, я считаю, необходимы.
interface ICore : IDispatch
{
[id(1), helpstring("method Init")] HRESULT Init([in] IUnknown *pDataManSink);
HRESULT FireOnImport([in] LPCOLESTR pszFormName, [in] LPCOLESTR pszTagName, [in] VARIANT pszData);
... more methods
}
"Поток" доступа к данным из IDL (упрощен для упрощения демонстрации проблемы)
interface IDataManagerSinkEx : IUnknown
{
[helpstring("method ReadData")] HRESULT ReadData([in] LPCTSTR pszDataKey, [out, retval] BSTR* pbsData);
[helpstring("method WriteData")] HRESULT WriteData([in] LPCTSTR pszDataKey, [in] LPCTSTR pszData);
[helpstring("method ReadDataEx")] HRESULT ReadTagEx([in] LPCTSTR pszDataKey, [out] short *pwExtraInfoOut, [out, retval] BSTR *pbsData);
[helpstring("method WriteDataEx")] HRESULT WriteTagEx([in] LPCTSTR pszDataKey, [in] short wExtraInfo, [in] LPCTSTR pszData);
}
Я пробовал различные реализации приемника в C#, но безрезультатно или изменил условия ошибки. Вот самая последняя реализация, и да, я вручную написал определение интерфейса, так как использование одного из типов lib не сработало. (та же проблема)
[ComImport]
[Guid( "AB79770E-8143-45E6-B082-E985E6DFA5CB" )]
[InterfaceType( ComInterfaceType.InterfaceIsIUnknown )]
public interface IMyDataManagerSinkEx
{
[PreserveSig]
int ReadData( [MarshalAs( UnmanagedType.LPStr )]string pszDataKey, out string data );
[PreserveSig]
int WriteTag( [MarshalAs( UnmanagedType.LPStr )]string pszDataKey, [MarshalAs( UnmanagedType.LPStr )]string pszData );
[PreserveSig]
int ReadTagEx( [MarshalAs( UnmanagedType.LPStr )]string pszDataKey, out short pwExraInfoOut, out string dataOut );
[PreserveSig]
int WriteTagEx( [MarshalAs( UnmanagedType.LPStr )]string pszDataKey, short wExtraInfo, [MarshalAs( UnmanagedType.LPStr )]string pszData );
}
class public SinkImpl : IMyDataManagerSinkEx
{
[PreserveSig]
public int ReadData( [MarshalAs( UnmanagedType.LPStr )]string pszDataKey, out string data )
{
throw new NotImplementedException();
}
[PreserveSig]
public int WriteTag( [MarshalAs( UnmanagedType.LPStr )]string pszDataKey, [MarshalAs( UnmanagedType.LPStr )]string pszData )
{
throw new NotImplementedException();
}
[PreserveSig]
public int ReadTagEx( [MarshalAs( UnmanagedType.LPStr )]string pszDataKey, out short pwExraInfoOut, out string dataOut )
{
throw new NotImplementedException();
}
[PreserveSig]
public int WriteTagEx( [MarshalAs( UnmanagedType.LPStr )]string pszDataKey, short wExtraInfo, [MarshalAs( UnmanagedType.LPStr )]string pszData )
{
throw new NotImplementedException();
}
}
1 ответ
Эта проблема ESP обычно означает, что у вас есть какая-то путаница между библиотеками времени выполнения ваших DLL. Например, в нашей кодовой базе есть много COM-объектов, если текущая регистрация COM некоторых из этих объектов происходит из отладочной сборки, а другие - из релизных версий, вы получите ошибку ESP при вызове методов интерфейсы, которые предоставляют эти объекты.
У меня есть скрипт, который регистрирует все известные COM-объекты, которые находятся в нашей кодовой базе.