【问题标题】:P/Invoke errors only on Windows Server 2008 R2 x64仅在 Windows Server 2008 R2 x64 上出现 P/Invoke 错误
【发布时间】:2012-06-05 16:47:30
【问题描述】:

我有 ASP.NET MVC3 应用程序,它使用 crypt32.dll 中的一些方法,使用 P/Invoke。在 Windows XP、Windows 7(32 位和 64 位)、Windows Server 2003(也是 32 位和 64 位)上一切正常,但是当我尝试在 Windows Server 2008 R2 x64 上设置应用程序时,我的麻烦就开始了。此外,当我尝试在同一台机器上从 VS2010 运行项目时,它工作正常。服务器已安装最新更新、IIS 7.5 和所有其他所需的东西。

应用程序没有给出任何错误,只是导致“页面不可用”或有时出现错误 503(停止应用程序池)。

这是我在事件查看器中得到的:

Faulting application name: w3wp.exe, version: 7.5.7601.17514, time stamp: 0x4ce7a5f8
Faulting module name: CRYPT32.dll, version: 6.1.7601.17514, time stamp: 0x4ce7b841
Exception code: 0xc0000005
Fault offset: 0x00010cf3
Faulting process id: 0xc4c
Faulting application start time: 0x01cd3f0fac5721fb
Faulting application path: C:\Windows\SysWOW64\inetsrv\w3wp.exe
Faulting module path: C:\Windows\syswow64\CRYPT32.dll
Report Id: ee39118a-ab02-11e1-8d06-000c297e9eda

应用程序池仅由该应用程序使用,它设置为启用 32 位应用程序、集成管道和正确的 .Net 版本。项目是为 x86 平台构建的(即使我尝试了所有其他可能性),我什至尝试将所需的 DLL 添加到项目中,将复制到输出目录设置为始终复制,但没有任何帮助。

使用日志我设法找出它在以下位置中断:

if (!CertGetCertificateContextProperty(pCertContext, CERT_KEY_PROV_INFO_PROP_ID, IntPtr.Zero, ref cbData))
{
    Marshal.ThrowExceptionForHR(Marshal.GetLastWin32Error());
}

DLL导入代码:

[DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool CertGetCertificateContextProperty(
    IntPtr pCertContext,
    uint dwPropId,
    IntPtr pvData,
    ref uint pcbData
);

有什么可能导致问题的想法吗?

下面是剩下的代码:

CERT_NAME_BLOB cnbCertificate;
CRYPT_DATA_BLOB certificate;
IntPtr hCertStore = IntPtr.Zero;
IntPtr pCertContext = IntPtr.Zero;
uint cbData = 0;

byte[] encoded = Encode(cert.Subject);

GCHandle pinnedArray = new GCHandle();
pinnedArray = GCHandle.Alloc(cBuffer, GCHandleType.Pinned);

certificate.cbData = cBuffer.Length;
certificate.pbData = pinnedArray.AddrOfPinnedObject();
pinnedArray.Free();
hCertStore = PFXImportCertStore(ref certificate, password, CRYPT_USER_KEYSET | CRYPT_EXPORTABLE);
cnbCertificate.cbData = (uint)encoded.Length;
GCHandle h1;

if (hCertStore != IntPtr.Zero)
{
    try
    {
        h1 = GCHandle.Alloc(encoded, GCHandleType.Pinned);
        cnbCertificate.pbData = h1.AddrOfPinnedObject();

        dataHandle = GCHandle.Alloc(cnbCertificate, GCHandleType.Pinned);
        pCertContext = CertFindCertificateInStore(hCertStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_SUBJECT_NAME, dataHandle.AddrOfPinnedObject(), IntPtr.Zero);
        if (h1 != null) h1.Free();
    }
    catch (Exception exp)
    {
        log.Error("Marshall error1: " + exp.Message + " " + Marshal.GetLastWin32Error());
    }
    finally
    {
    }
}

if (!CertGetCertificateContextProperty(pCertContext, CERT_KEY_PROV_INFO_PROP_ID, IntPtr.Zero, ref cbData))
{
    Marshal.ThrowExceptionForHR(Marshal.GetLastWin32Error());
}

【问题讨论】:

  • 您为什么使用 P/Invoke 而不是 msdn.microsoft.com/en-us/library/… 的 X509Certificate2 等内置证书类?
  • 使用 X508Certificate2 不是一个选项,原因有很多,其中一个是我需要 RC4 算法,.NET 框架不支持
  • RC4和证书有什么关系?无论如何,日志中的错误是什么?由于您自己抛出异常,您应该查看 CertGetCertificateContextProperty 和您正在使用的上下文,而不是 ASP.NET 或 P/Invoke。错误代码是什么?它是功能文档中提到的错误代码之一吗?还有什么?
  • 抱歉回答缓慢。什么日志?浏览器出现错误 101 (net::ERR_CONNECTION_RESET): Unknown Error,在我的日志文件中没有错误,我只从我已经发布的 IIS 中得到这个错误。对 CertGetCertificateContextProperty 的调用在 try-catch 子句中,但它没有进入 catch 部分,也不会到达 Marshal.ThrowExceptionForHR(Marshal.GetLastWin32Error());部分在 if 子句中。似乎它只是停止了 IIS。无论如何,感谢您的帮助,如果我解释得不好,对不起。同样,上下文必须良好,并且相同的代码适用于所有其他平台。
  • 请解释否决票,我真的认为这家伙有一个合法的 Q,你知道只是一个 DebugDiag 评论或什么的。

标签: c# asp.net .net asp.net-mvc-3 pinvoke


【解决方案1】:

我刚刚注意到日志中的异常代码:0xc0000005。这是访问冲突,这意味着您提供给该方法的指针引用了无效地址。指针本身可能为 null 或零,或者它应该指向的 CERT_CONTEXT 结构包含无效数据。

这与 ASP.NET 或 IIS 无关,代码或数据有错误。也许证书一开始就错了。

【讨论】:

  • 谢谢,我之前没有注意到异常代码:0xc0000005,但这并没有让我的生活变得更轻松。我正在使用我自己的日志来查看到底发生了什么,它似乎是第一次进入 CertGetCertificateContextProperty 然后无缘无故地进入同一个控制器的开始。当第二次来到同一个地方时,它会出现访问错误,这是有道理的,因为这次证书没有按应有的方式加载。这有什么意义吗?这可能是什么原因造成的。证书经过测试,可以正常工作。
  • 另外,当我尝试在同一台机器上使用相同的文件调试代码时,它工作正常。这就是让我认为它与 IIS 或 Win 2008 配置有关的原因。
  • 查找这些错误代码:microsoft.com/en-us/download/details.aspx?id=985 将 exe 放入您的 sys32 文件夹中,然后您可以从 cmd(无论位置如何)运行它,例如 cmd > err 0xc0000005 这将告诉您操作系统错误并且 google.com EM 比十六进制代码更容易,
  • 感谢 Jeremy,但我得到的错误似乎是由于我在之前的评论中描述的场景(两次输入相同的控制器)引起的。另外,我刚刚尝试在 Windows Server 2008 x64 上设置相同的应用程序,它工作正常,所以这个问题是 R2 版独有的......
  • 不,不是。它是您的代码独有的,使用特定机器上的特定数据。您有访问冲突,因为您传递了一个错误的指针。在这种情况下,操作系统会立即终止有问题的进程,因为进程内存已变得可疑。检查您传递给函数的数据结构或指向函数的指针。或者至少发布您正在创建结构的代码
猜你喜欢
  • 1970-01-01
  • 2011-12-14
  • 1970-01-01
  • 2011-09-04
  • 2023-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多