2016-04-22 8 views
0

Я пытаюсь вызвать код C# из C++. Поэтому я выбрал способ COM Interop. Теперь у меня есть C# код:вызов C# из C++, возвращаемое значение

namespace ToBeCalled 
{ 
    [Guid("9329feaf-b293-4093-a7d8-6128f52b30a6")] 
    [ComVisible(true)] 
    public interface IInterface 
    { 
     int Write(string toWrite); 
    } 
} 

namespace ToBeCalled 
{ 
    [Guid("e4105e40-2d6b-4b7c-ae42-d2f9c405a2a0")] 
    [ComVisible(true)] 
    public class ClassYouWantToUse : IInterface 
    { 
     public int Write(string toWrite) 
     { 
      System.Console.WriteLine(toWrite); 
      return 1; 
     } 
    } 
} 

и С ++ код

#import "...\\ToBeCalled.tlb" 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    // Initialize COM. 
    HRESULT hr = CoInitialize(NULL); 

    // Create the interface pointer. 
    ToBeCalled::IInterfacePtr piTest(__uuidof(ToBeCalled::ClassYouWantToUse)); 

    long lResult = 0; 

    // Call the Add method. 
    piTest->Write("hi", &lResult); 

    wprintf(L"The result is %d\n", lResult); 

    // Uninitialize COM. 
    CoUninitialize(); 
    return 0; 
} 

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

piTest->Write("hi"); 

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

+0

Я обнаружил, что нужно добавить параметр в C#, а затем я могу использовать второй аргумент для функции, которая будет иметь значение результата. Итак, для Int проблема решена, но как я могу отправить такую ​​строку? –

+0

Вы должны иметь возможность нормально возвращать значение, а не через параметр '[out]'. Что именно исключение? Вы отлаживали управляемый вызов? –

ответ

2

Ваш код сервера в порядке, и вам не нужно использовать параметр out.

клиентский код должен выглядеть просто так:

long result = piTest->Write("hi"); 

Если вы посмотрите внутрь генерироваться .tlh файл, вы увидите, что подпись что-то вроде:

long Write(_bstr_t toWrite); 

Это сгенерированный код обертки , и вы, вероятно, путаете его с сырым COM-вызовом, который также является частью файла tlh и выглядит так:

virtual HRESULT __stdcall raw_Write(BSTR toWrite, long* pRetVal) = 0; 

Обертка более удобна: она вызывает внутренний COM-вызов и обрабатывает возвращаемое значение - таким образом, возвращаемое значение обычно возвращается из функции (вместо аргумента [out, retval]), и если результат необработанного вызова обозначает ошибку (неудачно HRESULT) Исключение составляет _com_error.

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

+0

спасибо, я попробую. Да, я был спутан с HRESULT. Нужно ли здесь сделать некоторое освобождение, когда я возвращаю строку из C#? Если да, то как? –

+1

Вы не возвращаете строку, чтобы ничего не освобождать. Если вы создаете новый метод, который возвращает строку (определенную как '[out, retval]' аргумент в определении idl'), он соответствует стандартным правилам COM и, в общем, вам придется освободить его через API 'SysFreeString' (например, если вы используете необработанный вызов). Тем не менее, '# import' также создаст« умную »оболочку, которая вернет' bstr_t', которая позаботится об освобождении его от вас, поэтому, если вы используете этот метод, нечего освобождать. –