COM-интерфейс Маршалинг из C ++ в C # иногда дает сбой - PullRequest
0 голосов
/ 01 ноября 2019

У меня есть DLL, написанная на C ++. У меня есть интерфейс IRaster, который наследуется от интерфейса IUnknown, и класс Raster, который реализует интерфейс IRaster. Я также экспортирую функцию ReadRaster для возврата указателя на IRaster.

В C # у меня есть соответствующее определение интерфейса IRaster и объявление функции для ReadRaster. Это обычно работает очень хорошо для меня, чтобы использовать IRaster в C #. Однако функция ReadRaster занимает много времени, и мне нужно использовать интерфейс в фоновом потоке. Пока я вызываю ReadRaster в фоновом потоке, я могу использовать возвращенный IRaster без каких-либо проблем. Иногда мне также нужно использовать интерфейс в основном потоке пользовательского интерфейса. Поскольку это включает передачу интерфейса COM между двумя потоками, это не работает. Один из способов - попробовать маршалинг с перекрестными потоками, который я пробовал немного без какого-либо успеха.

Я также попробовал другой способ избежать перекрестного маршалинга COM-интерфейса. Я экспортирую функцию ReadRasterAsPtr и ConvertRasterPtrToRaster в C ++. В фоновом потоке я вызываю ReadRasterPtr, а затем вызываю ConvertRasterPtrToRaster в основном потоке пользовательского интерфейса. Этот трюк работает большую часть времени. Однако иногда происходит сбой, что означает, что функция ConvertRasterPtrToRaster не может вернуть действительный интерфейс IRaster в C #. Когда это терпит неудачу, неожиданно, и эта проблема беспокоила меня в течение долгого времени.

Спасибо за помощь!

Некоторые коды относятся к проблеме:

В C ++,

interface IRaster:public IUnknown
{
  virtual void _stdcall delete()=0;
};

class Raster: public IRaster
{
   HRESULT __stdcall QueryInterface(const IID& riid,void **ppvObject) {
   if (riid == IID_IUnknown || riid==IID_Raster) {
        *ppvObject =(IRaster*)this;
        return S_OK;
    }
    *ppvObject = NULL ;
    return E_NOINTERFACE ;
   }

    ULONG __stdcall AddRef() {
       return 1;
    }
    ULONG __stdcall Release() {
      return 1;  //I am not using the COM reference counting mechanism and I 
             delete the COM class manually
    }
    virtual void _stdcall delete(){
       delete this;
    }

}

extern "C"  __declspec(dllexport) IRaster* __stdcall ReadRaster()
{
IRaster* pRaster=new Raster();
return pRaster;
}

extern "C"  __declspec(dllexport) void* __stdcall ReadRasterAsPtr(const char* path)
{
IRaster* pRaster=new Raster();
return (void*)pRaster;
}

extern "C"  __declspec(dllexport)IRaster* __stdcall ConvertRasterPtrToRaster (void* pRaster) {
    return (IRaster*) pRaster;
}

В C #,

[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("2B95F084-ACCB-4642-BC12-E116C00814F9")]
public interface IRaster
{
    [PreserveSig]
    void Delete();
}

public class Utils{
    [DllImport("Base.dll")]
    [SecurityPermission(SecurityAction.Assert, Unrestricted = true)]
    public extern static IRaster ReadRaster();

    [DllImport("Base.dll")]
    [SecurityPermission(SecurityAction.Assert, Unrestricted = true)]
    public extern static IntPtr ReadRasterAsPtr();

    [DllImport("Base.dll")]
    [SecurityPermission(SecurityAction.Assert, Unrestricted = true)]
    public extern static IRaster ConvertRasterPtrToRaster(IntPtr grdPtr);
 }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...