title: CryptQueryObject fails with CRYPT_E_NO_MATCH error in managed code but works fine in unmanaged one
body: <p>I've been struggling with this bug for over a day and I appreciate if anyone could help me shed some light on it. It all started from <a href="https://stackoverflow.com/q/34281047/843732">this question</a>. My goal was to retrieve digital signature information on a signed <code>.js</code> file. (The file was originally signed by Microsoft's <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/aa387764(v=vs.85).aspx" rel="nofollow noreferrer">signtool</a>.)</p>
  
  <p>Since my managed code seemed to have failed, I decided to try an <a href="https://support.microsoft.com/en-us/kb/323809" rel="nofollow noreferrer">unmanaged approach</a>, in C++, which surprisingly worked just fine. So I decide to write a similar thing in C# using <code>PInvoke</code>. But no matter what I did in the managed code, that didn't work.</p>
  
  <p>So I did some digging and here's the part that seems to fail.</p>
  
  <p>If I do this from either 32-bit or 64-bit unmanaged C++ code, it works fine:</p>
  
  <pre><code>HCERTSTORE hStore = NULL;
  HCRYPTMSG hMsg = NULL; 
  DWORD dwEncoding = 0, dwContentType = 0, dwFormatType = 0;
  
  // Get message handle and store handle from the signed file.
  if(CryptQueryObject(CERT_QUERY_OBJECT_FILE,
                              L"D:\\Test\\DataStore\\Downloads\\en-US\\test02_1.js",
                              CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
                              CERT_QUERY_FORMAT_FLAG_BINARY,
                              0,
                              &amp;dwEncoding,
                              &amp;dwContentType,
                              &amp;dwFormatType,
                              &amp;hStore,
                              &amp;hMsg,
                              NULL))
  {
      //All good
      TRACE("Got it!\n");
  }
  else
  {
      //Failed
      TRACE("Error: 0x%x\n", ::GetLastError());
  }
  </code></pre>
  
  <p>But if I do the same from an ASP.NET web application written in C# (and running as a 64-bit process on a 64-bit Windows 8.1 OS) using PInvoke, it gives me the <code>0x80092009</code> error code, or <code>CRYPT_E_NO_MATCH</code>:</p>
  
  <pre><code>IntPtr hStore = IntPtr.Zero;
  IntPtr hMsg = IntPtr.Zero;
  
  IntPtr dwEncoding = IntPtr.Zero, dwContentType = IntPtr.Zero, dwFormatType = IntPtr.Zero;
  
  IntPtr DummyNull = IntPtr.Zero;
  
  // Get message handle and store handle from the signed file.
  if (!CryptQueryObject(CERT_QUERY_OBJECT_FILE,
      "D:\\Test\\DataStore\\Downloads\\en-US\\test02_1.js",
      CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
      CERT_QUERY_FORMAT_FLAG_BINARY,
      0,
      dwEncoding,
      dwContentType,
      dwFormatType,
      hStore,
      hMsg,
      ref DummyNull))
  {
      //Failed
      int nOSError = Marshal.GetLastWin32Error();
  
      throw new Exception("Failed with error " + nOSError);
  }
  </code></pre>
  
  <p>and these are <code>PInvoke</code> declarations for it:</p>
  
  <pre><code>        [DllImport("CRYPT32.DLL", EntryPoint = "CryptQueryObject", CharSet = CharSet.Auto, SetLastError = true)]
          private static extern Boolean CryptQueryObject(
              Int32 dwObjectType,
              [MarshalAs(UnmanagedType.LPWStr)]string pvObject,
              Int32 dwExpectedContentTypeFlags,
              Int32 dwExpectedFormatTypeFlags,
              Int32 dwFlags,
              IntPtr pdwMsgAndCertEncodingType,
              IntPtr pdwContentType,
              IntPtr pdwFormatType,
              IntPtr phCertStore,
              IntPtr phMsg,
              ref IntPtr ppvContext
          );
  
          [StructLayout(LayoutKind.Sequential)]
          private struct CRYPT_OBJID_BLOB
          {
              public uint cbData;
              [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)]
              public byte[] pbData;
          }
  
          [StructLayout(LayoutKind.Sequential)]
          private struct CRYPT_ALGORITHM_IDENTIFIER
          {
              [MarshalAs(UnmanagedType.LPStr)]
              public String pszObjId;
              public CRYPT_OBJID_BLOB Parameters;
          }
  
          [StructLayout(LayoutKind.Sequential)]
          private struct CRYPT_BIT_BLOB
          {
              public uint cbData;
              public IntPtr pbData;
              public uint cUnusedBits;
          }
  
          [StructLayout(LayoutKind.Sequential)]
          private struct CERT_PUBLIC_KEY_INFO
          {
              public CRYPT_ALGORITHM_IDENTIFIER Algorithm;
              public CRYPT_BIT_BLOB PublicKey;
          }
  
      #pragma warning disable 0618
          [StructLayout(LayoutKind.Sequential)]
          private struct CERT_INFO
          {
              public uint dwVersion;
              public CRYPT_OBJID_BLOB SerialNumber;
              public CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm;
              public CRYPT_OBJID_BLOB Issuer;
              public FILETIME NotBefore;
              public FILETIME NotAfter;
              public CRYPT_OBJID_BLOB Subject;
              public CERT_PUBLIC_KEY_INFO SubjectPublicKeyInfo;
              public CRYPT_OBJID_BLOB IssuerUniqueId;
              public CRYPT_OBJID_BLOB SubjectUniqueId;
              public uint cExtension;
              public IntPtr rgExtension;
          }
      #pragma warning restore 0618
  
          private const int CERT_QUERY_OBJECT_FILE = 0x00000001;
          private const int CERT_QUERY_OBJECT_BLOB = 0x00000002;
  
          private const int CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED = 10;
          private const int CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED = (1 &lt;&lt; CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED);
  
          private const int CERT_QUERY_FORMAT_BINARY = 1;
          private const int CERT_QUERY_FORMAT_FLAG_BINARY = (1 &lt;&lt; CERT_QUERY_FORMAT_BINARY);
  </code></pre>
  
  <p>Any idea why?</p>
  
  <p>PS. Note that if instead of a digitally signed <code>.js</code> file, I replace it with a digitally signed <code>.exe</code> file, both managed and unmanaged code seem to work fine. And that really puzzles me!</p>