从非托管 C++ 调用 WCF 服务会导致访问冲突

Posted

技术标签:

【中文标题】从非托管 C++ 调用 WCF 服务会导致访问冲突【英文标题】:Call to WCF-service from unmanaged c++ causes access violation 【发布时间】:2012-07-25 09:14:09 【问题描述】:

我想从非托管代码访问 wcf 服务。 该服务只是连接到字符串并返回它们,以保持简单。

public class Stringconcat : IStringconcat

        public string stringconcat(string a, string b)
        
            return b + a;
        


[ServiceContract]
public interface IStringconcat

    [OperationContract]
    string stringconcat(string a, string b);

我使用引用该服务的 .dll 的 c# 控制台应用程序托管该服务。 并公开服务的端点。 在 Main() 中:

using (ServiceHost host = new ServiceHost(typeof(stringconcatservice.Stringconcat)))

    host.Open();
    Console.WriteLine("Press <ENTER> to terminate the host application");
    Console.ReadLine();

主机配置如下:

<?xml version="1.0" encoding="utf-8" ?>
    <configuration>
        <system.serviceModel>
            <behaviors>
                <serviceBehaviors>
                    <behavior name="serviceBehavior">
                        <serviceDebug includeExceptionDetailInFaults="true"/>
                        <serviceMetadata />
                    </behavior>
                </serviceBehaviors>
            </behaviors>
            <services>
                <service behaviorConfiguration="serviceBehavior"
                name="stringconcatservice.Stringconcat" >
                    <endpoint address="stringconcat" binding="basicHttpBinding"
                    name="basicHttp" contract="stringconcatservice.IStringconcat" />
                    <endpoint binding="mexHttpBinding" name="mex"
                    contract="IMetadataExchange" />
                    <host>
                        <baseAddresses>
                         <add baseAddress="http://localhost:8000/stringconcatService" />
                        </baseAddresses>
                    </host>
                </service>
            </services>
        </system.serviceModel>
    </configuration>

如果我从用于服务引用基地址的 .net 客户端调用服务,现在一切正常。

StringconcatClient proxy = new StringconcatClient();

string a = " string a ";
string b = " string b ";
string c = proxy.stringconcat(a, b);

Console.WriteLine(c);
Console.WriteLine("Press <ENTER> to terminate Client.");
Console.ReadKey();

现在我遇到的问题。 因为我想从非托管 c++ 代码访问服务。 为此,我使用了一个 .dll,它注册了 com 互操作,并且还使用了正在运行的主机的服务引用。

[Guid("E4435D3B-CBC3-4D41-B4A5-D8116B394195")]
[ClassInterface(ClassInterfaceType.None)]
[ComVisible(true)]
public class Stringconcat_IAMCOM : IStringconcat_IAMCOM

    public string stringconcat(string a, string b)
    
        StringconcatClient client = new StringconcatClient();
        return client.stringconcat(a, b);
    

[Guid("E130F97E-1844-4C8B-9E57-AF42632A2557")]
[ComVisible(true)]
public interface IStringconcat_IAMCOM

    [DispId(1)]
    string stringconcat(string a, string b);

现在,当我尝试使用 c++ 通过中间 .dll 访问服务时...

#import "..\stringconcatInteropSvcClient\bin\Debug\stringconcatInteropSvcClient.tlb" 
#include <iostream>
#include <stdio.h>
using namespace stringconcatInteropSvcClient;
int main(int argc, const char* argv[])

    HRESULT hr = CoInitialize(NULL);
    BSTR a =  L" string a ";
    BSTR b =  L" string b ";
    IStringconcat_IAMCOM* q;
    hr = CoCreateInstance(__uuidof(Stringconcat_IAMCOM), NULL, CLSCTX_INPROC_SERVER,
    __uuidof(IStringconcat_IAMCOM), (void**)&q );
    std::cout << q->stringconcat(a, b);

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

...我在 stringconcatinteropsvcclient.tli 中遇到异常,例如:

“xyz.exe 中 0x75... 处未处理的异常:Microsoft C++ 异常:_com_error at memory location 0x...”

然后我可以继续并在 strlen.asm 中获取下一个异常:

“xyz.exe 中 0x5d... (msvcr100d.dll) 处的未处理异常:0xC0...:访问冲突读取位置 0x00...”

在此异常停止后。 也许有人对此问题有解决方案,或者知道错误可能出在哪里。我只是用这个例子来保持简单。我正在从事的项目使用相同的结构。它还使用 wcf 服务,这些服务将从非托管 c++ 中调用。

【问题讨论】:

嗨,你能确认 q 不是 NULL 吗?所以 CoCreateInstance 返回指向请求接口的有效指针?我在代码中看不到任何验证,所以这就是我要问的原因。不应该是 __uuidof(IStringconcat_IAMCOM) 吗? 你是对的 q 是 NULL。所以它不会返回一个有效的指针。我尝试使用 __uuidof(IStringconcat_IAMCOM),也返回一个空指针,好的,所以我得到一个空指针异常。 尝试将 [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] 添加到您的界面 好吧,我试过了,但还是一样。 我更改了 c++ 代码以捕获空指针和 hr 结果。所以我得到一个 hr 结果 0x80040154,类未注册。但是我已经使用 regasm 注册了 dll,并且我还检查了 vs 2010 项目属性的 Build 选项卡中的 Register for COM interop 框。 【参考方案1】:

刚刚创建了一个小测试项目,它正在工作:

namespace ComTest

    [Guid("E4435D3B-CBC3-4D41-B4A5-D8116B394195")]
    [ClassInterface(ClassInterfaceType.None)]
    [ComVisible(true)]
    public class Stringconcat_IAMCOM : IStringconcat_IAMCOM
    
        public string stringconcat(string a, string b)
                    
            return a + b;
        
    
    [Guid("E130F97E-1844-4C8B-9E57-AF42632A2557")]
    [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
    public interface IStringconcat_IAMCOM
    
        [DispId(1)]
        string stringconcat(string a, string b);
    

和客户:

#import "C:\Users\rst\Documents\Visual Studio 2008\Projects\ComTest\ComTest\bin\Debug\ComTest.tlb" 
#include <iostream>
#include <stdio.h>
#include <windows.h>

using namespace ComTest;

    int main(int argc, const char* argv[])
    

        HRESULT hr = CoInitialize(NULL);
        BSTR a =  L" string a ";
        BSTR b =  L" string b ";
        IStringconcat_IAMCOM* q;
        hr = CoCreateInstance(__uuidof(Stringconcat_IAMCOM), NULL, CLSCTX_INPROC_SERVER,
        __uuidof(IStringconcat_IAMCOM), (void**)&q );
        std::cout << q->stringconcat(a, b);

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

我的程序集名称是 ComTest.dll,所以我使用以下方式注册它:

regasm Comtest.dll /CodeBase

【讨论】:

【参考方案2】:

c++代码出错,错误调用CoCreateInstance(...),谢谢zilog的帮助。

IStringconcat_IAMCOM* q;
hr = CoCreateInstance(__uuidof(Stringconcat_IAMCOM), NULL, CLSCTX_INPROC_SERVER, __uuidof(IStringconcat_IAMCOM), (void**)&q );

并且在调用 serviceproxy 时也出现了错误。 我必须将端点属性 address="stringconcat" 添加到基地址。 地址应该是这样的:

http://localhost:8000/stringconcatService/stringconcat

我现在以这种方式创建服务代理:

[Guid("E4435D3B-CBC3-4D41-B4A5-D8116B394195")]
[ClassInterface(ClassInterfaceType.None)]
[ComVisible(true)]
public class Stringconcat_IAMCOM : IStringconcat_IAMCOM

    public string stringconcat(string a, string b)
      
        EndpointAddress ep = new EndpointAddress("http://localhost:8000/stringconcatService/stringconcat");
        proxy = ChannelFactory<IStringconcat>.CreateChannel(new BasicHttpBinding(), ep);
        proxy.stringconcat(string a, string b);
    


[Guid("E130F97E-1844-4C8B-9E57-AF42632A2557")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IStringconcat_IAMCOM

    [DispId(1)]
    string stringconcat(string a, string b);

现在我可以从 c++ 调用 WCF-Services,太棒了!

【讨论】:

以上是关于从非托管 C++ 调用 WCF 服务会导致访问冲突的主要内容,如果未能解决你的问题,请参考以下文章

有时调用 Microsoft Azure 托管的 WCF 服务会导致“SSL/TLS 的信任关系”问题

WPF 应用程序托管 WCF 访问冲突

调试从非托管 C++ 调用的托管 .NET 代码

从非托管 c++ 调用托管 c# 函数

从非托管 c++ 调用托管 c# 函数

运行使用 /clr 构建的 DLL 的本机 C++ 应用程序时访问冲突