private Byte[] GetBinaryRequestProperty(ref CCertServerExit server, string name)
        {
            // https://blogs.msdn.microsoft.com/alejacma/2008/08/04/how-to-modify-an-interop-assembly-to-change-the-return-type-of-a-method-vb-net/
            IntPtr variantObjectPtr = Marshal.AllocHGlobal(2048);

            try
            {
                IntPtr bstrPtr;
                int    bstrLen;

                // Get VARIANT containing certificate bytes
                // Read ANSI BSTR information from the VARIANT as we know RawCertificate property is ANSI BSTR.
                server.GetRequestProperty(name, (int)PropertyType.PROPTYPE_BINARY, variantObjectPtr);
                bstrPtr = Marshal.ReadIntPtr(variantObjectPtr, 8);
                bstrLen = Marshal.ReadInt32(bstrPtr, -4);
                byte[] result = new byte[bstrLen];
                Marshal.Copy(bstrPtr, result, 0, bstrLen);
                return(result);
            }
            catch
            {
                return(null);
            }
            finally
            {
                VariantClear(variantObjectPtr);
                Marshal.FreeHGlobal(variantObjectPtr);
            }
        }
        private int GetLongRequestProperty(ref CCertServerExit server, string name)
        {
            IntPtr variantObjectPtr = Marshal.AllocHGlobal(2048);

            try
            {
                server.GetRequestProperty(name, (int)PropertyType.PROPTYPE_LONG, variantObjectPtr);
                var result = (int)(Marshal.GetObjectForNativeVariant(variantObjectPtr));
                return(result);
            }
            catch
            {
                return(0);
            }
            finally
            {
                VariantClear(variantObjectPtr);
                Marshal.FreeHGlobal(variantObjectPtr);
            }
        }
        private DateTime GetDateCertificateProperty(ref CCertServerExit server, string name)
        {
            IntPtr variantObjectPtr = Marshal.AllocHGlobal(2048);

            try
            {
                server.GetCertificateProperty(name, (int)PropertyType.PROPTYPE_DATE, variantObjectPtr);
                var result = (DateTime)(Marshal.GetObjectForNativeVariant(variantObjectPtr));
                return(result);
            }
            catch
            {
                return(new DateTime());
            }
            finally
            {
                VariantClear(variantObjectPtr);
                Marshal.FreeHGlobal(variantObjectPtr);
            }
        }
        private string GetStringCertificateProperty(ref CCertServerExit server, string name)
        {
            IntPtr variantObjectPtr = Marshal.AllocHGlobal(2048);

            try
            {
                server.GetCertificateProperty(name, (int)PropertyType.PROPTYPE_STRING, variantObjectPtr);
                var result = (string)(Marshal.GetObjectForNativeVariant(variantObjectPtr));
                return(result);
            }
            catch
            {
                return(null);
            }
            finally
            {
                VariantClear(variantObjectPtr);
                Marshal.FreeHGlobal(variantObjectPtr);
            }
        }
        public void Notify(int ExitEvent, int Context)
        {
            switch (ExitEvent)
            {
            case (int)ExitEvents.CertIssued:

                var CertServer      = new CCertServerExit();
                var CertificateInfo = new IssuedCertificate();

                // Retrieving CA Properties

                // The context must be zero to read any of these properties. The context is set to zero when the ICertServerExit object is initially created.
                // It can also be set to zero by invoking the SetContext method.
                CertServer.SetContext(0);

                CertificateInfo.Issuer = GetStringCertificateProperty(ref CertServer, "SanitizedCAName");

                // Must be called before querying Certificate properties
                // https://docs.microsoft.com/en-us/windows/win32/api/certif/nf-certif-icertserverexit-setcontext
                CertServer.SetContext(Context);

                // Retrieving Certificate Properties
                // https://docs.microsoft.com/en-us/windows/win32/api/certif/nf-certif-icertserverexit-getcertificateproperty

                CertificateInfo.RawCertificate = Convert.ToBase64String(
                    GetBinaryCertificateProperty(ref CertServer, "RawCertificate"),
                    Base64FormattingOptions.None
                    );

                CertificateInfo.RequestId    = GetLongCertificateProperty(ref CertServer, "RequestId");
                CertificateInfo.SerialNumber = GetStringCertificateProperty(ref CertServer, "SerialNumber");
                CertificateInfo.Subject      = GetStringCertificateProperty(ref CertServer, "DistinguishedName");
                CertificateInfo.NotBefore    = GetDateCertificateProperty(ref CertServer, "NotBefore");
                CertificateInfo.NotAfter     = GetDateCertificateProperty(ref CertServer, "NotAfter");


                // Retrieving Request Properties
                // https://docs.microsoft.com/de-de/windows/win32/api/certif/nf-certif-icertserverexit-getrequestproperty

                CertificateInfo.RawRequest = Convert.ToBase64String(
                    GetBinaryRequestProperty(ref CertServer, "RawRequest"),
                    Base64FormattingOptions.None
                    );

                CertificateInfo.RequesterName = GetStringRequestProperty(ref CertServer, "RequesterName");
                CertificateInfo.RequestType   = GetLongRequestProperty(ref CertServer, "RequestType");

                // TODO: Can we access the "Name Properties" here, and should we, in Terms of accessing the CA Database...?
                // https://docs.microsoft.com/en-us/windows/win32/seccrypto/name-properties

                // Serialize to XML
                var OutputXmlSerializer = new XmlSerializer(typeof(IssuedCertificate));

                var OutputFileName = CertificateInfo.RequestId.ToString() + ".xml";

                /*
                 * OutputFileName.Replace("%1", CertificateInfo.RequestId.ToString());
                 * OutputFileName.Replace("%2", CertificateInfo.Issuer);
                 * OutputFileName.Replace("%3", CertificateInfo.SerialNumber);
                 */

                using (var OutputStringWriter = new StringWriter())
                {
                    using (XmlWriter OutputXmlWriter = XmlWriter.Create(OutputStringWriter))
                    {
                        OutputXmlSerializer.Serialize(OutputXmlWriter, CertificateInfo);

                        if (OutputDirectory != null)
                        {
                            System.IO.File.WriteAllText(
                                OutputDirectory + @"\" + OutputFileName,
                                PrettyXml(OutputStringWriter.ToString())
                                );
                        }
                    }
                }

                break;
            }
        }