title: Create .cat file with C#
body: <p>I'm trying to import and use CryptCATCDFEnumMembersByCDFTagEx in order to create .cat files using C#. The function is returning null and the parameters do not seem to be initialized. I wrote the corresponding code in C++ and that works fine. I'm guessing my structures are off.</p>
  
  <p>Any help would be appreciated. The code should create a Good.cat file in the working directory of the program, which should contain the hashes of the files specified below [CatalogFiles]. </p>
  
  <p>Catalog.cdf</p>
  
  <pre><code>[CatalogHeader]
  Name=Good.cat
  ResultDir=.\
  PublicVersion=0x0000001
  EncodingType=0x00010001
  CATATTR1=0x10010001:OSAttr:2:6.0
  [CatalogFiles]
  Notepad.exe=C:\Windows\Notepad.exe
  </code></pre>
  
  <p>C# sample program.</p>
  
  <pre><code>class Program
  {
      //https://msdn.microsoft.com/en-us/library/windows/desktop/bb427419%28v=vs.85%29.aspx
      [StructLayout(LayoutKind.Sequential)]
      public struct CRYPTCATCDF
      {
          uint    cbStruct;
          IntPtr  hFile;
          uint    dwCurFilePos;
          uint    dwLastMemberOffset;
          bool    fEOF;
          [MarshalAs(UnmanagedType.LPWStr)]
          string  pwszResultDir;
          IntPtr  hCATStore;
      }
  
      //https://msdn.microsoft.com/en-us/library/windows/desktop/aa381414%28v=vs.85%29.aspx
      [StructLayout(LayoutKind.Sequential)]
      public struct CRYPTOAPI_BLOB
      {
          public uint cbData; // UInt32 cbData;
          //[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)]
          public IntPtr pbData; //public byte[] pbData
      } // CRYPT_INTEGER_BLOB, CRYPT_ATTR_BLOB, CRYPT_OBJID_BLOB, CRYPT_HASH_BLOB
  
      //https://msdn.microsoft.com/en-us/library/windows/desktop/bb736433%28v=vs.85%29.aspx
      [StructLayout(LayoutKind.Sequential)]
      public struct SIP_INDIRECT_DATA
      {
          public CRYPT_ATTRIBUTE_TYPE_VALUE Data;
          public CRYPT_ALGORITHM_IDENTIFIER DigestAlgorithm;
          public CRYPTOAPI_BLOB Digest;
      }
  
      //https://msdn.microsoft.com/en-us/library/windows/desktop/aa381151%28v=vs.85%29.aspx
      [StructLayout(LayoutKind.Sequential)]
      public struct CRYPT_ATTRIBUTE_TYPE_VALUE {
          [MarshalAs(UnmanagedType.LPStr)] 
          public string pszObjId;
          public CRYPTOAPI_BLOB Value;
      }
  
      //https://msdn.microsoft.com/en-us/library/windows/desktop/aa381133%28v=vs.85%29.aspx
      [StructLayout(LayoutKind.Sequential)]
      public struct CRYPT_ALGORITHM_IDENTIFIER
      {
          [MarshalAs(UnmanagedType.LPStr)]
          public string pszObjId;
          public CRYPTOAPI_BLOB Parameters;
      }
  
      //https://msdn.microsoft.com/en-us/library/windows/desktop/aa373931%28v=vs.85%29.aspx
      [StructLayout(LayoutKind.Sequential)]
      public struct GUID
      {
          int     a;
          short   b;
          short   c;
          [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
          byte[]  d;
      }
  
      //https://msdn.microsoft.com/en-us/library/windows/desktop/aa379905%28v=vs.85%29.aspx
      [StructLayout(LayoutKind.Sequential)]
      public class CRYPTCATMEMBER
      {
          public uint cbStruct;
          [MarshalAs(UnmanagedType.LPWStr)]
          public string pwszReferenceTag;
          [MarshalAs(UnmanagedType.LPWStr)]
          public string pwszFileName;
          public GUID gSubjectType;
          public uint fdwMemberFlags;
          public IntPtr pIndirectData;    //struct SIP_INDIRECT_DATA_  *pIndirectData;
          public uint dwCertVersion;
          public uint dwReserved;
          public IntPtr hReserved;
          public CRYPTOAPI_BLOB sEncodedIndirectData;
          public CRYPTOAPI_BLOB sEncodedMemberInfo;
      }
  
      //https://msdn.microsoft.com/en-us/library/windows/desktop/bb410248%28v=vs.85%29.aspx
      [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
      public delegate void PFN_CDF_PARSE_ERROR_CALLBACK(
          [In] uint dwErrorArea,
          [In] uint dwLocalError,
          [In, MarshalAs(UnmanagedType.LPWStr)] string pwszLine
      );
  
      //https://msdn.microsoft.com/en-us/library/windows/desktop/bb427424%28v=vs.85%29.aspx
      [DllImport("wintrust.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Unicode)]
      static extern IntPtr CryptCATCDFOpen(
          [In, MarshalAs(UnmanagedType.LPWStr)] string pwszFilePath,
          [In, Optional] IntPtr pfnParseError
      );
  
      //https://msdn.microsoft.com/en-us/library/windows/desktop/bb427423%28v=vs.85%29.aspx
      [DllImport("wintrust.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Unicode)]
      static extern string CryptCATCDFEnumMembersByCDFTagEx(
          [In] IntPtr pCDF,
          [In, Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pwszPrevCDFTag,
          [In] IntPtr pfnParseError,
          [In] CRYPTCATMEMBER ppMember,
          [In] bool fContinueOnError,
          [In] IntPtr pvReserved
      );
  
      private static void ParseErrorCallback(uint u1, uint u2, string s)
      {
          Console.WriteLine(u1 + " " + u2 + " " + s);
      }
  
      static void Main(string[] args)
      {
          PFN_CDF_PARSE_ERROR_CALLBACK pfn = new PFN_CDF_PARSE_ERROR_CALLBACK(ParseErrorCallback);
          StringBuilder sb = new StringBuilder(256);
          string s = string.Empty;
  
          IntPtr cdfPtr = CryptCATCDFOpen("catalog.cdf", Marshal.GetFunctionPointerForDelegate(pfn));
          CRYPTCATCDF cdf = (CRYPTCATCDF)Marshal.PtrToStructure(cdfPtr, typeof(CRYPTCATCDF));
  
          CRYPTCATMEMBER ccm = new CRYPTCATMEMBER();
          ccm.pIndirectData = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SIP_INDIRECT_DATA)));
  
          do
          {
              s = CryptCATCDFEnumMembersByCDFTagEx(cdfPtr, sb, Marshal.GetFunctionPointerForDelegate(pfn), ccm, true, IntPtr.Zero);
              Console.WriteLine(s ?? "N/A");
          } while (s != null);
      }
  }
  </code></pre>
  
  <p>Working C++ example</p>
  
  <pre><code>void callback(DWORD u1, DWORD u2, LPWSTR s)
  {
      printf("%d %d %s", u1, u2, s);
  }
  
  typedef LPWSTR(WINAPI *CryptCATCDFEnumMembersByCDFTagEx)(
      CRYPTCATCDF                  *pCDF,
      LPWSTR                       pwszPrevCDFTag,
      PFN_CDF_PARSE_ERROR_CALLBACK pfnParseError,
      CRYPTCATMEMBER               **ppMember,
      BOOL                         fContinueOnError,
      LPVOID                       pvReserved);
  
  int _tmain(int argc, _TCHAR* argv[])
  {
      CRYPTCATCDF     *cdf;
      CRYPTCATMEMBER  *pMember = NULL;
      LPWSTR          pwszMemberTag = NULL;
      HINSTANCE       dllHandle = LoadLibrary(L"wintrust.dll");
  
      cdf = CryptCATCDFOpen(L"catalog.cdf", (PFN_CDF_PARSE_ERROR_CALLBACK)callback);
      CryptCATCDFEnumMembersByCDFTagEx fptr = (CryptCATCDFEnumMembersByCDFTagEx)GetProcAddress(dllHandle, "CryptCATCDFEnumMembersByCDFTagEx");
  
      while (pwszMemberTag = (*fptr)(cdf, pwszMemberTag, NULL, &amp;pMember, TRUE, NULL))
      {
          wprintf(L"%s", pwszMemberTag);
      }
  
      CryptCATCDFClose(cdf);
  }
  </code></pre>