Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/259.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/google-apps-script/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 当从针对任何CPU的C项目调用时,为什么此代码会抛出System.AccessViolationException?_C#_C++_.net_Com_Pinvoke - Fatal编程技术网

C# 当从针对任何CPU的C项目调用时,为什么此代码会抛出System.AccessViolationException?

C# 当从针对任何CPU的C项目调用时,为什么此代码会抛出System.AccessViolationException?,c#,c++,.net,com,pinvoke,C#,C++,.net,Com,Pinvoke,我的ATL项目中有此IDL: [ object, uuid(61B0BFF7-E9DF-4D7E-AFE6-49CC67245257), dual, nonextensible, pointer_default(unique) ] interface ICrappyCOMService : IDispatch { typedef [ uuid(C65F8DE6-EDEF-479C-BD3B-17EC3F9E4

我的ATL项目中有此IDL:

[
    object,
    uuid(61B0BFF7-E9DF-4D7E-AFE6-49CC67245257),
    dual,
    nonextensible,
    pointer_default(unique)
]
interface ICrappyCOMService : IDispatch {
    typedef
        [
            uuid(C65F8DE6-EDEF-479C-BD3B-17EC3F9E4A3E),
            version(1.0)
        ]
    struct CrapStructure {
        INT ErrorCode;
        BSTR ErrorMessage;
    } CrapStructure;
    [id(1)] HRESULT TestCrap([in] INT errorCode, [in] BSTR errorMessage, [in, out] CrapStructure *crapStructure);
};
[
    uuid(763B8CA0-16DD-48C8-BB31-3ECD9B9DE441),
    version(1.0),
]
library CrappyCOMLib
{
    importlib("stdole2.tlb");
    [
        uuid(F7375DA4-2C1E-400D-88F3-FF816BB21177)      
    ]
    coclass CrappyCOMService
    {
        [default] interface ICrappyCOMService;
    };
};
这是我在C++中的实现:

STDMETHODIMP CCrappyCOMService::InterfaceSupportsErrorInfo(REFIID riid)
{
    static const IID* const arr[] = {
        &IID_ICrappyCOMService
    };
    for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) {
        if (InlineIsEqualGUID(*arr[i], riid))
            return S_OK;
    }
    return S_FALSE;
}

STDMETHODIMP CCrappyCOMService::TestCrap(INT errorCode, BSTR errorMessage, CrapStructure *crapStructure) {
    memset(crapStructure, 0, sizeof(CrapStructure));
    crapStructure->ErrorCode = errorCode;
    crapStructure->ErrorMessage = errorMessage;
    CComPtr<ICreateErrorInfo> x;
    ICreateErrorInfo* pCreateErrorInfo;
    CreateErrorInfo(&pCreateErrorInfo);
    pCreateErrorInfo->AddRef();
    pCreateErrorInfo->SetDescription(errorMessage);
    pCreateErrorInfo->SetGUID(IID_ICrappyCOMService);
    pCreateErrorInfo->SetSource(L"Component.TestCrap");
    IErrorInfo* pErrorInfo;
    pCreateErrorInfo->QueryInterface(IID_IErrorInfo, (void**)&pErrorInfo);
    pErrorInfo->AddRef();
    SetErrorInfo(0, pErrorInfo);
    pErrorInfo->Release();
    pCreateErrorInfo->Release();
    printf("Going to return %d...\n", errorCode);
    return errorCode;
}
如果我从一个以x64为目标的C项目运行代码,那么一切都正常。问题是,当我从一个针对C中任何CPU的项目调用TestCrap方法时,它抛出System.AccessViolationException。为什么呢?我可以验证当它抛出System.AccessViolationException时,它仍然打印返回-1。。。到控制台窗口

编辑:我已经缩小了复制步骤。对不起,我忘了把这个加进去。这似乎是在使用x64编译代码时发生的:目标为x64的ATL项目和目标为任何CPU的C测试项目,然后转换回目标为Win32的ATL项目和目标为任何CPU的C测试项目

编辑:我把错误缩小了一点。首先,任何CPU C项目似乎总是使用我的COM对象的x64版本,因此需要首先编译ATL项目的verion,以便传播任何代码,因为x64系统上的任何CPU都将在x64上下文中运行。此外,它看起来像一行,crapStructure->ErrorMessage=ErrorMessage;正在导致System.AccessViolationException异常。它将在COM世界中执行代码,但在返回到C世界时,它会将异常抛出

编辑:C++中,Prtff%D\n,sieFoFrAcpRead;结果16例。在C中,Console.WriteLineMarshal.SizeOftypeofCrapStructure;结果也是16。但是,唉,再多读一读,这是一张无用的支票,正如汉斯在这里的回答所提到的:


编辑:我尝试从我的任何以CPU为目标的C项目中执行tlbimp crapycom.dll/out:crapycomx86managed.dll并使用crapycomx86managed.dll,但它再次抛出System.AccessViolationException。我认为这是因为它再次进入系统上注册的x64 COM对象,所以我使用regsvr32注销x64 COM对象。再次运行代码并注册x86 COM对象后,它抱怨检索CLSID为{F7375DA4-2C1E-400D-88F3-FF816BB21177}的组件的COM类工厂失败,原因是以下错误:80040154类未注册HRESULT异常:0x80040154 REGDB_E_CLASSNOTREG。我找到的唯一方法是将我的C项目的构建目标修改为x86,然后代码用于测试我的x86 COM对象,因此,对我来说,这似乎是一个没有实际意义的问题,因为我希望任何CPU都能专门针对我的x86 COM对象或具有正确结构大小的x64 COM对象。COM在C中是一场灾难。

可能发生的情况是,对于x64和x86版本,您隐式使用了相同的类型库.TLB或包含.TLB的DLL

问题是TLB定义了一个非托管结构,并且此结构布局在32位和64位模式大小、偏移量等方面会有所不同

在.NET中,您希望确保在使用不同的处理器体系结构编译时,没有引用通过隐式tlbimp COM引用从TLB生成的相同的互操作程序集

使用标准的VisualStudio工具进行正确操作可能很棘手


如果您仍然想使用这样的结构(这在自动化领域有点奇怪),我建议您自己使用tlbimp.exe构建互操作程序集,并像普通的.NET程序集一样引用这些互操作程序集,但是,取决于比特,您将能够调整在.CSPROJ中使用“条件”属性而不是直接使用COM引用。

您可以尝试通过日志和指针检查来缩小它的C++代码,以查看哪一个调用正好引起异常。这是一个复杂的结构@格里芬我更新了我的问题,因为我把它缩小了一点。另外,不能使用ref作为自动生成的代理存根类,因为它在IDL中标记为[in,out]。为此分配内存是不正确的。在C代码中输入并传递变量。@Griffin如何为C世界中的字符串分配内存?嘿,Simon,我编辑了我的问题,因为我把它缩小了一点。它似乎在调用我的COM对象的x64版本。问题是crapStructure->ErrorMessage=ErrorMessage;是导致这种异常的原因,但我不知道为什么——尽管我想知道你的建议是否有助于纠正这种情况。你有什么想法吗?如果它调用我的COM方法的x64版本,它会为其结构设置正确的大小,或者不是这样,因为它针对的是任何CPU?是的,x86与x64中的结构布局有问题。如果您使用的是cx64,那么您必须使用基于x64版本的TLB的互操作程序集,以便正确描述该结构
哦我明白你的意思了。你是说我应该测试在使用tlbimp.exe在C中生成两个版本的代理存根后会发生什么。伙计,我真是太感谢你了。一次又一次,在StackOverflow上,你帮了我很多忙!我希望我能和你这样的人一起工作,向你学习更多。嘿,西蒙,我刚刚编辑了这个问题。如果我的C项目被设置为以任何CPU为目标,您知道有没有办法以x86版本的COM对象为目标?尽管我试图使用tlbimp.exe使用x86 COM对象的输出DLL,但它似乎一直希望使用x64实现。正如我所说,工具是很棘手的:-使用此结构选择一个危险的路径,因为这意味着TLB对位敏感,这有点不寻常。最简单的方法是停止这样做,继续使用纯自动化类型。否则,请确保删除COM引用,并在interop/per-bitness/tlbimp生成的.NET程序集上保持标准.NET引用,就像上次编辑时一样。Marshal.SizeofCrapStructure在x86中为8,在x64中为16。使用C中的IntPtr.Size确定位数。取消选中C项目道具中的“首选32位”,对于您的测试,不要使用任何CPU。
static void Main(string[] args)
{
    var service = new CrappyCOMService();
    var crapStructure = new CrapStructure();
    try
    {
        service.TestCrap(-1, "This is bananas.", ref crapStructure);
    }
    catch (COMException exception)
    {
        Console.WriteLine(exception.ErrorCode);
        Console.WriteLine(exception.Message);
    }
    Console.WriteLine(crapStructure.ErrorCode);
    Console.WriteLine(crapStructure.ErrorMessage);
}