/*
 * Copyright
 *   2008 axYus - www.axyus.com
 *   2008 L.Meckert - laurent.meckert.com
 *
 * This file is part of XEMELIOS.
 *
 * XEMELIOS is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * XEMELIOS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with XEMELIOS; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
package fr.gouv.finances.cp.xemelios.plugin.signerfichier;

/**
 *
 * @author laurent.meckert
 */
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.WString;
import com.sun.jna.win32.*;

import java.io.File;
import java.util.Vector;

public class W32CryptExporter {

   private java.awt.Window parentWindow;
   private Vector<File> generatedFiles;

   public Vector<File> getGeneratedFiles() {
      return generatedFiles;
   }

   public void setGeneratedFiles(Vector<File> generatedFiles) {
      this.generatedFiles = generatedFiles;
   }

   public W32CryptExporter(java.awt.Window parentWindow) {
      this.parentWindow = parentWindow;
      generatedFiles = new Vector<File>();
   }
   /*typedef struct _CRYPTUI_WIZ_EXPORT_INFO {
   DWORD dwSize;
   DWORD dwExportFormat;
   BOOL fExportChain;
   BOOL fExportPrivateKeys;
   LPCWSTR pwszPassword;
   BOOL fStrongEncryption;
   }  CRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO */

   static public class CryptuiWizExportCertContextInfo extends Structure {

      public int dwSize = size();
      public int dwExportFormat;
      public boolean fExportChain;
      public boolean fExportPrivateKeys;
      public WString pwszPassword;
      public boolean fStrongEncryption;
   };


   // typedef struct _CRYPTUI_WIZ_EXPORT_INFO {
   //    DWORD dwSize;
   //    LPCWSTR pwszExportFileName;
   //    DWORD dwSubjectChoice;
   //    union {
   //    PCCERT_CONTEXT pCertContext;
   //    PCCTL_CONTEXT pCTLContext;
   //    PCCRL_CONTEXT 	pCRLContext;
   //    HCERTSTORE hCertStore;
   //    } ;
   //    DWORD cStores;
   //    HCERTSTORE *rghStores;
   //    } CRYPTUI_WIZ_EXPORT_INFO,
   //    *PCRYPTUI_WIZ_EXPORT_INFO;
   static public class CryptuiWizExportInfo extends Structure {

      public int dwSize = size();
      public WString pwszExportFileName;
      public int dwSubjectChoice;
      public Pointer pCertContext;
      public int cStores;  // on sen fou
      public Pointer rghStores;   // oci
   };

   public interface User32 extends StdCallLibrary {

      User32 INSTANCE = (User32) Native.loadLibrary("User32",
              User32.class);
      /*
       * MessageBox() Flags
       */
      static public final long MB_OK = 0x00000000L;
      static public final long MB_OKCANCEL = 0x00000001L;
      static public final long MB_ABORTRETRYIGNORE = 0x00000002L;
      static public final long MB_YESNOCANCEL = 0x00000003L;
      static public final long MB_YESNO = 0x00000004L;
      static public final long MB_RETRYCANCEL = 0x00000005L;
      static public final long MB_CANCELTRYCONTINUE = 0x00000006L;
      static public final long MB_ICONHAND = 0x00000010L;
      static public final long MB_ICONQUESTION = 0x00000020L;
      static public final long MB_ICONEXCLAMATION = 0x00000030L;
      static public final long MB_ICONASTERISK = 0x00000040L;
      static public final long MB_USERICON = 0x00000080L;
      static public final long MB_ICONWARNING = MB_ICONEXCLAMATION;
      static public final long MB_ICONERROR = MB_ICONHAND;
      static public final long MB_ICONINFORMATION = MB_ICONASTERISK;
      static public final long MB_ICONSTOP = MB_ICONHAND;
      static public final long MB_DEFBUTTON1 = 0x00000000L;
      static public final long MB_DEFBUTTON2 = 0x00000100L;
      static public final long MB_DEFBUTTON3 = 0x00000200L;
      static public final long MB_DEFBUTTON4 = 0x00000300L;
      static public final long MB_APPLMODAL = 0x00000000L;
      static public final long MB_SYSTEMMODAL = 0x00001000L;
      static public final long MB_TASKMODAL = 0x00002000L;
      static public final long MB_HELP = 0x00004000L; // Help Button
      static public final long MB_NOFOCUS = 0x00008000L;
      static public final long MB_SETFOREGROUND = 0x00010000L;
      static public final long MB_DEFAULT_DESKTOP_ONLY = 0x00020000L;
      static public final long MB_TOPMOST = 0x00040000L;
      static public final long MB_RIGHT = 0x00080000L;
      static public final long MB_RTLREADING = 0x00100000L;
      static public final long MB_TYPEMASK = 0x0000000FL;
      static public final long MB_ICONMASK = 0x000000F0L;
      static public final long MB_DEFMASK = 0x00000F00L;
      static public final long MB_MODEMASK = 0x00003000L;
      static public final long MB_MISCMASK = 0x0000C000L;
      /*
       * Dialog Box Command IDs
       */
      static public final int IDOK = 1;
      static public final int IDCANCEL = 2;
      static public final int IDABORT = 3;
      static public final int IDRETRY = 4;
      static public final int IDIGNORE = 5;
      static public final int IDYES = 6;
      static public final int IDNO = 7;
      static public final int IDCLOSE = 8;
      static public final int IDHELP = 9;
      static public final int IDTRYAGAIN = 10;
      static public final int IDCONTINUE = 11;
      static public final int IDTIMEOUT = 32000;

      int MessageBoxA(int hwnd, String text, String caption, long flags);
   }

   public interface Crypt32 extends StdCallLibrary {

      Crypt32 INSTANCE = (Crypt32) Native.loadLibrary("Crypt32",
              Crypt32.class);

      Pointer CertOpenSystemStoreA(
              Pointer unused,
              String storeName);

      boolean CertCloseStore(
              Pointer hCertStore,
              int dwFlags);

      Pointer CertEnumCertificatesInStore(
              Pointer hStoreHandle,
              Pointer pCertContext);

      // DWORD WINAPI CertGetNameString(
      //   __in   PCCERT_CONTEXT pCertContext,
      //   __in   DWORD dwType,
      //   __in   DWORD dwFlags,
      //   __in   void *pvTypePara,
      //   __out  LPTSTR pszNameString,
      //   __in   DWORD cchNameString
      // );
      public int CertGetNameStringA(
              Pointer pCertContext,
              int dwType,
              int dwFlags,
              Pointer pvTypePara,
              byte[] pszNameString,
              int cchNameString);
      // BOOL WINAPI CryptFindCertificateKeyProvInfo(
      //   __in  PCCERT_CONTEXT pCert,
      //   __in  DWORD dwFlags,
      //   __in  void *pvReserved
      // );

      public boolean CryptFindCertificateKeyProvInfo(
              Pointer pCertContext,
              int dwFlags,
              Pointer pvReserved);


      // BOOL WINAPI CertFreeCertificateContext(
      //   __in  PCCERT_CONTEXT pCertContext
      // );
      public boolean CertFreeCertificateContext(
              Pointer pCertContext);
   }

   public interface Cryptui extends StdCallLibrary {

      /**
       *
       */
      public static final int CRYPTUI_WIZ_EXPORT_FORMAT_PFX = 2;
      /**
       *
       */
      public static final int CRYPTUI_WIZ_EXPORT_CERT_CONTEXT = 1;
      public static final int CRYPTUI_WIZ_NO_UI_EXCEPT_CSP = 0x0003;
      public static final int CRYPTUI_WIZ_EXPORT_PRIVATE_KEY = 0x0100;
      public static final int CRYPTUI_WIZ_EXPORT_NO_DELETE_PRIVATE_KEY = 0x0200;
      Cryptui INSTANCE = (Cryptui) Native.loadLibrary("Cryptui",
              Cryptui.class);

      // BOOL WINAPI CryptUIWizExport(
      //   __in  DWORD dwFlags,
      //   __in  HWND hwndParent,
      //   __in  LPCWSTR pwszWizardTitle,
      //   __in  PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo,
      //   __in  void *pvoid
      // );
      boolean CryptUIWizExport(int dwFlags,
              Pointer hwndParent,
              WString pwszWizardTitle,
              Pointer pExportInfo, //CryptuiWizExportInfo
              Pointer certContextInfo); //CryptuiWizExportCertContextInfo

      // PCCERT_CONTEXT WINAPI CryptUIDlgSelectCertificateFromStore(
      //   __in      HCERTSTORE hCertStore,
      //   __in      HWND hwnd,
      //   __in_opt  LPCWSTR pwszTitle,
      //   __in_opt  LPCWSTR pwszDisplayString,
      //   __in      DWORD dwDontUseColumn,
      //   __in      DWORD dwFlags,
      //   __in      void *pvReserved
      // );
      Pointer CryptUIDlgSelectCertificateFromStore(
              Pointer hCertStore,
              Pointer hwndParent,
              WString pwszTitle,
              WString pwszDisplayString,
              int dwDontUseColumn,
              int dwFlags,
              Pointer pvReserved);

      // BOOL WINAPI CryptUIDlgViewContext(
      //   __in  DWORD dwContextType,
      //   __in  const void *pvContext,
      //   __in  HWND hwnd,
      //   __in  LPCWSTR pwszTitle,
      //   __in  DWORD dwFlags,
      //   __in  void *pvReserved
      // );
      public boolean CryptUIDlgViewContext(
              int dwContextType,
              Pointer pvContext,
              Pointer hwnd,
              WString pwszTitle,
              int dwFlags,
              Pointer pvReserved);
   }

   public void exportSelected(String password) {
      generatedFiles.clear();
      Native.setProtected(true);
      Pointer storeHandle = Crypt32.INSTANCE.CertOpenSystemStoreA(null, "MY");
      if (storeHandle != null) {
         // System.out.println("CertOpenSystemStoreA returned not null");
         Pointer certContext = null;
         boolean again = true;
         CryptuiWizExportCertContextInfo certContextInfo = new CryptuiWizExportCertContextInfo();
         CryptuiWizExportInfo exportInfo = new CryptuiWizExportInfo();



         //  certContextInfo.dwSize = sizeof(certContextInfo);
         //    certContextInfo.dwExportFormat = CRYPTUI_WIZ_EXPORT_FORMAT_PFX;
         //    certContextInfo.fExportChain = true;
         //    certContextInfo.fExportPrivateKeys = true;
         //    certContextInfo.pwszPassword = wPassword;
         //    certContextInfo.fStrongEncryption = false;


         certContextInfo.dwExportFormat = Cryptui.CRYPTUI_WIZ_EXPORT_FORMAT_PFX; //2

         certContextInfo.fExportChain = true;
         certContextInfo.fExportPrivateKeys = true;
         certContextInfo.pwszPassword = new WString(password);



         certContextInfo.fStrongEncryption = true;//false;

         certContextInfo.write(); // IMPORTANT "flushe" dans la memoire "native"
         System.out.println(certContextInfo);

         exportInfo.pwszExportFileName = new WString("C:\\lolo.pfx"); //  en fait on le remplit dans la boucle

         exportInfo.dwSubjectChoice = Cryptui.CRYPTUI_WIZ_EXPORT_CERT_CONTEXT; //non CRYPTUI_WIZ_EXPORT_CERT_STORE;

         exportInfo.pCertContext = certContext;
         exportInfo.rghStores = null;
         exportInfo.cStores = 0;

         while (again) {
            certContext = Cryptui.INSTANCE.CryptUIDlgSelectCertificateFromStore(
                    storeHandle,
                    Native.getWindowPointer(parentWindow), // null,//HWND hwnd, fenetre parent
                    new WString("Selection d'un certificat"),
                    new WString("OK pour exporter le certificat sélectionné, Annuler pour terminer"),
                    0, // int dwDontUseColumn,
                    0,
                    null);

            if (certContext != null) {

//                    Cryptui.INSTANCE.CryptUIDlgViewContext(
//                            1, //int  dwContextType,:#define CERT_STORE_CERTIFICATE_CONTEXT  1
//                            certContext,
//                            null,
//                            new WString("Montrage d'un certificat"),
//                            0,
//                            null);


               byte[] byteArray = new byte[256];

//CERT_NAME_EMAIL_TYPE
//1
//If the certificate has a Subject Alternative Name extension or Issuer Alternative Name, uses the first rfc822Name choice. If no rfc822Name choice is found in the extension, uses the Subject Name field for the Email OID. If either rfc822Name or the Email OID is found, uses the string. Otherwise, returns an empty string (returned character count is 1). pvTypePara is not used and is set to NULL.
//
//CERT_NAME_RDN_TYPE
//2
//Converts the Subject Name BLOB by calling CertNameToStr. pvTypePara points to a DWORD containing the dwStrType passed to CertNameToStr. If the Subject Name field is empty and the certificate has a Subject Alternative Name extension, uses the first directory Name choice from CertNameToStr.
//
//CERT_NAME_ATTR_TYPE
//3
//pvTypePara points to an object identifier (OID) specifying the name attribute to be returned. For example, if pvTypePara is szOID_COMMON_NAME, uses the Subject Name member. If the Subject Name member is empty and the certificate has a Subject Alternative Name extension, uses the first directoryName choice.
//
//CERT_NAME_SIMPLE_DISPLAY_TYPE
//4
//Iterates through the following list of name attributes and uses the Subject Name or the Subject Alternative Name extension for the first occurrence of: szOID_COMMON_NAME, szOID_ORGANIZATIONAL_UNIT_NAME, szOID_ORGANIZATION_NAME, or szOID_RSA_emailAddr.
//If one of these attributes is not found, uses the Subject Alternative Name extension for a rfc822Name choice. If there is still no match, uses the first attribute.
//pvTypePara is not used and is set to NULL.
//
//CERT_NAME_FRIENDLY_DISPLAY_TYPE
//5
//Checks the certificate for a CERT_FRIENDLY_NAME_PROP_ID property. If the certificate has this property, it is returned. If the certificate does not have the property, the CERT_NAME_SIMPLE_DISPLAY_TYPE is returned.
//
//CERT_NAME_DNS_TYPE
//6
//If the certificate has a Subject Alternative Name extension for issuer, Issuer Alternative Name, search for first DNSName choice.
//
//If the DNSName choice is not found in the extension, search the Subject Name field for the CN OID, "2.5.4.3".
//
//If the DNSName or CN OID is found, return the string. Otherwise, return an empty string.
//
//CERT_NAME_URL_TYPE
//7
//If the certificate has a Subject Alternative Name extension for issuer, Issuer Alternative Name, search for first URL choice. If the URL choice is found, return the string. Otherwise, return an empty string.
//
//CERT_NAME_UPN_TYPE
//8
//If the certificate has a Subject Alternative Name extension, search the OtherName choices looking for a pszObjId == szOID_NT_PRINCIPAL_NAME, ("1.3.6.1.4.1.311.20.2.3").
//
//If the UPN OID is found, decode the BLOB as a X509_UNICODE_ANY_STRING and return the decoded string. Otherwise, return an empty string.
               Crypt32.INSTANCE.CertGetNameStringA(
                       certContext,
                       //   4 = CERT_NAME_SIMPLE_DISPLAY_TYPE,
                       5, //		5=	   CERT_NAME_FRIENDLY_DISPLAY_TYPE,
                       0,
                       null,
                       byteArray, // pszNameString,
                       128);
               String nameString = Native.toString(byteArray);
               System.out.println("found " + nameString);

               //





               if (Crypt32.INSTANCE.CryptFindCertificateKeyProvInfo(certContext, 0, null)) {

                  System.out.println("found private key for " + nameString);
                  String filename = new String("C:\\" + nameString + ".pfx");
                  exportInfo.pwszExportFileName = new WString(filename);
                  System.out.println("Certificate for " + nameString + " a mettre dans " + filename);
                  generatedFiles.add(new File(filename));
                  //   exportInfo.pCertContext  = pCertContext;

                  //                result = CryptUIWizExport(
                  //                                          //         CRYPTUI_WIZ_NO_UI
                  //                                          CRYPTUI_WIZ_NO_UI_EXCEPT_CSP |CRYPTUI_WIZ_EXPORT_PRIVATE_KEY | CRYPTUI_WIZ_EXPORT_NO_DELETE_PRIVATE_KEY, /*   __in  DWORD dwFlags, */
                  //                                          NULL, /*   __in  HWND hwndParent, */
                  //                                          L"Hello",/*   __in  LPCWSTR pwszWizardTitle, */
                  //                                          &exportInfo, /*   __in  PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo, */
                  //                                          &certContextInfo/*   __in  void *pvoid */
                  //                                          );

                  exportInfo.pCertContext = certContext;
                  exportInfo.write();
                  System.out.println(exportInfo);

                  boolean result = Cryptui.INSTANCE.CryptUIWizExport(
                          0x0003 | 0x0100 | 0x0200,
                          null,
                          new WString("Hello"),
                          exportInfo.getPointer(),
                          certContextInfo.getPointer());
                  if (result) {
                     again = false;
                  }
               } else {
                  System.out.println("did not found private key for " + nameString);
                  int iresult = User32.INSTANCE.MessageBoxA(0, "Ce certificat n'est pas associé à une clé privée", "Certificat non exporté",
                          User32.MB_OK |
                          User32.MB_TASKMODAL |
                          User32.MB_TOPMOST | User32.MB_SETFOREGROUND);
               }


               Crypt32.INSTANCE.CertFreeCertificateContext(certContext);
               certContext = null;
            } else {
               again = false;
            }
         }
      }
   }

   /**
    *
    * @param password
    */
   public void exportAll(String password) {
      generatedFiles.clear();
      Native.setProtected(true);
      Pointer storeHandle = Crypt32.INSTANCE.CertOpenSystemStoreA(null, "MY");
      if (storeHandle != null) {
         System.out.println("CertOpenSystemStoreA returned not null");
         Pointer certContext = null;



         CryptuiWizExportCertContextInfo certContextInfo = new CryptuiWizExportCertContextInfo();
         CryptuiWizExportInfo exportInfo = new CryptuiWizExportInfo();



         //  certContextInfo.dwSize = sizeof(certContextInfo);
         //    certContextInfo.dwExportFormat = CRYPTUI_WIZ_EXPORT_FORMAT_PFX;
         //    certContextInfo.fExportChain = true;
         //    certContextInfo.fExportPrivateKeys = true;
         //    certContextInfo.pwszPassword = wPassword;
         //    certContextInfo.fStrongEncryption = false;


         certContextInfo.dwExportFormat = 2;//CRYPTUI_WIZ_EXPORT_FORMAT_PFX

         certContextInfo.fExportChain = true;
         certContextInfo.fExportPrivateKeys = true;
         certContextInfo.pwszPassword = new WString(password);



         certContextInfo.fStrongEncryption = false;

         certContextInfo.write();
         System.out.println(certContextInfo);




         // exportInfo.dwSize = sizeof(exportInfo);
         //    exportInfo.pwszExportFileName = L"C:\\lolo.pfx"; // en fait on le remplit dans la boucle
         //    exportInfo.dwSubjectChoice =   CRYPTUI_WIZ_EXPORT_CERT_CONTEXT; //non CRYPTUI_WIZ_EXPORT_CERT_STORE;
         //    exportInfo.pCertContext  = pCertContext;
         //    exportInfo.rghStores = NULL;
         //    exportInfo.cStores = 0;



         exportInfo.pwszExportFileName = new WString("C:\\lolo.pfx"); //  en fait on le remplit dans la boucle

         exportInfo.dwSubjectChoice = 1;// CRYPTUI_WIZ_EXPORT_CERT_CONTEXT; //non CRYPTUI_WIZ_EXPORT_CERT_STORE;

         exportInfo.pCertContext = certContext;
         exportInfo.rghStores = null;
         exportInfo.cStores = 0;





         while ((certContext = Crypt32.INSTANCE.CertEnumCertificatesInStore(
                 storeHandle,
                 certContext)) != null) {
            System.out.println("Looping ..");
            byte[] byteArray = new byte[256];


            Crypt32.INSTANCE.CertGetNameStringA(
                    certContext,
                    //   CERT_NAME_SIMPLE_DISPLAY_TYPE,
                    5, //			   CERT_NAME_FRIENDLY_DISPLAY_TYPE,
                    0,
                    null,
                    byteArray, // pszNameString,
                    128);
            String nameString = Native.toString(byteArray);
            System.out.println("found " + nameString);
            if (Crypt32.INSTANCE.CryptFindCertificateKeyProvInfo(certContext, 0, null)) {
               System.out.println("found private key for " + nameString);


               String filename = new String("C:\\" + nameString + ".pfx");


               exportInfo.pwszExportFileName = new WString(filename);
               System.out.println("Certificate for " + nameString + " a mettre dans " + filename);
               generatedFiles.add(new File(filename));



               //   exportInfo.pCertContext  = pCertContext;

               //                result = CryptUIWizExport(
               //                                          //         CRYPTUI_WIZ_NO_UI
               //                                          CRYPTUI_WIZ_NO_UI_EXCEPT_CSP |CRYPTUI_WIZ_EXPORT_PRIVATE_KEY | CRYPTUI_WIZ_EXPORT_NO_DELETE_PRIVATE_KEY, /*   __in  DWORD dwFlags, */
               //                                          NULL, /*   __in  HWND hwndParent, */
               //                                          L"Hello",/*   __in  LPCWSTR pwszWizardTitle, */
               //                                          &exportInfo, /*   __in  PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo, */
               //                                          &certContextInfo/*   __in  void *pvoid */
               //                                          );



               exportInfo.pCertContext = certContext;
               exportInfo.write();
               System.out.println(exportInfo);

               boolean result = Cryptui.INSTANCE.CryptUIWizExport(
                       Cryptui.CRYPTUI_WIZ_NO_UI_EXCEPT_CSP |
                       Cryptui.CRYPTUI_WIZ_EXPORT_PRIVATE_KEY |
                       Cryptui.CRYPTUI_WIZ_EXPORT_NO_DELETE_PRIVATE_KEY,
                       //   0x0003 | 0x0100 | 0x0200,
                       null,
                       new WString("Hello"),
                       exportInfo.getPointer(),
                       certContextInfo.getPointer());
            } else {
               System.out.println("did not found private key for " + nameString);
            }

         }

         //-------------------------------------------------------------------
         // When all processing is completed, clean up.
         if (certContext != null) {
            Crypt32.INSTANCE.CertFreeCertificateContext(certContext);
            certContext = null;
         }

         Crypt32.INSTANCE.CertCloseStore(storeHandle, 0);

      } else {
         System.out.println("CertOpenSystemStoreA returned null");
      }

   }

   public static void main(String[] args) { //test
      Native.setProtected(true);
      Pointer storeHandle = Crypt32.INSTANCE.CertOpenSystemStoreA(null, "MY");
      if (storeHandle != null) {
         System.out.println("CertOpenSystemStoreA returned not null");
         Pointer certContext = null;

         certContext =
                 Cryptui.INSTANCE.CryptUIDlgSelectCertificateFromStore(
                 storeHandle,
                 null,//HWND hwnd, fenetre parent
                 new WString("Selection d'un certificat"),
                 new WString("hello je suis pwszDisplayString"),
                 0, // int dwDontUseColumn,
                 0,
                 null);

         // attention faut liberer


         if (certContext != null) {
            Cryptui.INSTANCE.CryptUIDlgViewContext(
                    1, //int  dwContextType,:#define CERT_STORE_CERTIFICATE_CONTEXT  1
                    certContext,
                    null,
                    new WString("Montrage d'un certificat"),
                    0,
                    null);
            Crypt32.INSTANCE.CertFreeCertificateContext(certContext);
            certContext =
                    null;
         }

         CryptuiWizExportCertContextInfo certContextInfo = new CryptuiWizExportCertContextInfo();
         CryptuiWizExportInfo exportInfo = new CryptuiWizExportInfo();



         //  certContextInfo.dwSize = sizeof(certContextInfo);
         //    certContextInfo.dwExportFormat = CRYPTUI_WIZ_EXPORT_FORMAT_PFX;
         //    certContextInfo.fExportChain = true;
         //    certContextInfo.fExportPrivateKeys = true;
         //    certContextInfo.pwszPassword = wPassword;
         //    certContextInfo.fStrongEncryption = false;


         certContextInfo.dwExportFormat = 2;//CRYPTUI_WIZ_EXPORT_FORMAT_PFX

         certContextInfo.fExportChain = true;
         certContextInfo.fExportPrivateKeys = true;
         certContextInfo.pwszPassword = new WString("jna");



         certContextInfo.fStrongEncryption = false;

         certContextInfo.write();
         System.out.println(certContextInfo);




         // exportInfo.dwSize = sizeof(exportInfo);
         //    exportInfo.pwszExportFileName = L"C:\\lolo.pfx"; // en fait on le remplit dans la boucle
         //    exportInfo.dwSubjectChoice =   CRYPTUI_WIZ_EXPORT_CERT_CONTEXT; //non CRYPTUI_WIZ_EXPORT_CERT_STORE;
         //    exportInfo.pCertContext  = pCertContext;
         //    exportInfo.rghStores = NULL;
         //    exportInfo.cStores = 0;



         exportInfo.pwszExportFileName = new WString("C:\\lolo.pfx"); //  en fait on le remplit dans la boucle

         exportInfo.dwSubjectChoice = 1;// CRYPTUI_WIZ_EXPORT_CERT_CONTEXT; //non CRYPTUI_WIZ_EXPORT_CERT_STORE;

         exportInfo.pCertContext = certContext;
         exportInfo.rghStores = null;
         exportInfo.cStores = 0;





         while ((certContext = Crypt32.INSTANCE.CertEnumCertificatesInStore(
                 storeHandle,
                 certContext)) != null) {
            System.out.println("Looping ..");
            byte[] byteArray = new byte[256];


            Crypt32.INSTANCE.CertGetNameStringA(
                    certContext,
                    //   CERT_NAME_SIMPLE_DISPLAY_TYPE,
                    5, //			   CERT_NAME_FRIENDLY_DISPLAY_TYPE,
                    0,
                    null,
                    byteArray, // pszNameString,
                    128);
            String nameString = Native.toString(byteArray);
            System.out.println("found " + nameString);
            if (Crypt32.INSTANCE.CryptFindCertificateKeyProvInfo(certContext, 0, null)) {
               System.out.println("found private key for " + nameString);


               String filename = new String("C:\\" + nameString + ".pfx");


               exportInfo.pwszExportFileName = new WString(filename);
               System.out.println("Certificate for " + nameString + " a mettre dans " + filename);




               //   exportInfo.pCertContext  = pCertContext;

               //                result = CryptUIWizExport(
               //                                          //         CRYPTUI_WIZ_NO_UI
               //                                          CRYPTUI_WIZ_NO_UI_EXCEPT_CSP |CRYPTUI_WIZ_EXPORT_PRIVATE_KEY | CRYPTUI_WIZ_EXPORT_NO_DELETE_PRIVATE_KEY, /*   __in  DWORD dwFlags, */
               //                                          NULL, /*   __in  HWND hwndParent, */
               //                                          L"Hello",/*   __in  LPCWSTR pwszWizardTitle, */
               //                                          &exportInfo, /*   __in  PCCRYPTUI_WIZ_EXPORT_INFO pExportInfo, */
               //                                          &certContextInfo/*   __in  void *pvoid */
               //                                          );



               exportInfo.pCertContext = certContext;
               exportInfo.write();
               System.out.println(exportInfo);

               boolean result = Cryptui.INSTANCE.CryptUIWizExport(
                       0x0003 | 0x0100 | 0x0200,
                       null,
                       new WString("Hello"),
                       exportInfo.getPointer(),
                       certContextInfo.getPointer());

            } else {
               System.out.println(User32.INSTANCE.MessageBoxA(0, "Ce certificat n'est pas associé à une clé privée", "Certificat non exporté", 0x24));
               System.out.println("did not found private key for " + nameString);
            }

         }

         //-------------------------------------------------------------------
         // When all processing is completed, clean up.
         if (certContext != null) {
            Crypt32.INSTANCE.CertFreeCertificateContext(certContext);
            certContext =
                    null;
         }

         Crypt32.INSTANCE.CertCloseStore(storeHandle, 0);

      } else {
         System.out.println("CertOpenSystemStoreA returned null");
      }
   }
}

