2016-04-22 74 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; 
     } 
    } 
} 

和C++代码

#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

你没有返回一个字符串,所以没有任何可以释放的字符串。如果你创建一个返回一个字符串的新方法(在'idl'定义中定义为'[out,retval]'参数),它符合标准的COM规则,并且通常你必须通过'SysFreeString' API来释放它例如,如果你使用原始呼叫)。然而,'#import'也会生成一个'smart'包装器,它会返回一个'bstr_t',它会为你取消分配它,所以如果你使用这个方法,就没有任何东西可以被释放。 –