#include "stdafx.h"
 #include "ZdActivex.h"
 #include "ZdActivexCtrl.h"
 #include "ZdActivexPropPage.h"
 #include "afxdialogex.h"
 #include <stdio.h>
 #include <windows.h>
 #include <wininet.h>

 #define MAXSIZE 4096
 #pragma comment(lib, "Wininet.lib")

 #ifdef _DEBUG
 #define new DEBUG_NEW
 #endif

 //CSP
 #include <wincrypt.h>
 #pragma comment(lib,"crypt32.lib")

 #define MALLOC(l) (BYTE*)malloc(l)

 IMPLEMENT_DYNCREATE(CZdActivexCtrl, COleControl)

 // 消息映射

 BEGIN_MESSAGE_MAP(CZdActivexCtrl, COleControl)
     ON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties)
 END_MESSAGE_MAP()

 // 调度映射

 BEGIN_DISPATCH_MAP(CZdActivexCtrl, COleControl)
     DISP_FUNCTION_ID(CZdActivexCtrl, "AboutBox", DISPID_ABOUTBOX, AboutBox, VT_EMPTY, VTS_NONE)
     DISP_FUNCTION_ID(CZdActivexCtrl, "ImportPFX", dispidImportPFX, ImportPFX, VT_EMPTY, VTS_BSTR VTS_BSTR VTS_BSTR VTS_BSTR)
     DISP_FUNCTION_ID(CZdActivexCtrl, "DownLoadToLocal", dispidDownLoadToLocal, DownLoadToLocal, VT_I4, VTS_BSTR VTS_BSTR)
     DISP_FUNCTION_ID(CZdActivexCtrl, "ImportExchangePFX", dispidImportExchangePFX, ImportExchangePFX, VT_EMPTY, VTS_BSTR VTS_BSTR VTS_BSTR VTS_BSTR)
     DISP_FUNCTION_ID(CZdActivexCtrl, "EnumCspProvider", dispidEnumCspProvider, EnumCspProvider, VT_BSTR, VTS_NONE)
 END_DISPATCH_MAP()

 // 事件映射

 BEGIN_EVENT_MAP(CZdActivexCtrl, COleControl)
 END_EVENT_MAP()

 // 属性页
 // TODO: 按需要添加更多属性页。请记住增加计数!
 BEGIN_PROPPAGEIDS(CZdActivexCtrl, 1)
     PROPPAGEID(CZdActivexPropPage::guid)
 END_PROPPAGEIDS(CZdActivexCtrl)

 // 初始化类工厂和 guid
 IMPLEMENT_OLECREATE_EX(CZdActivexCtrl, "ZDACTIVEX.ZdActivexCtrl.1",
     0x5f0ece95, 0x9bbb, 0x4f87, 0xb2, 0xc6, 0x2d, 0x7e, 0xb0, 0xf0, 0xf4, 0x54)

 // 键入库 ID 和版本
 IMPLEMENT_OLETYPELIB(CZdActivexCtrl, _tlid, _wVerMajor, _wVerMinor) // 接口 ID
 const IID IID_DZdActivex = { 0xA8294AA6, 0x8C40, 0x4029, { 0xB9, 0x5E, 0xAB, 0x71, 0xFC, 0xC, 0xB7, 0xEF } };
 const IID IID_DZdActivexEvents = { 0x47A58B2B, 0xCDD8, 0x4BF9, { 0xBB, 0xE3, 0x13, 0xDB, 0x32, 0xB8, 0x5E, 0x6A } };

 // 控件类型信息
 static const DWORD _dwZdActivexOleMisc =
     OLEMISC_ACTIVATEWHENVISIBLE |
     OLEMISC_SETCLIENTSITEFIRST |
     OLEMISC_INSIDEOUT |
     OLEMISC_CANTLINKINSIDE |
     OLEMISC_RECOMPOSEONRESIZE;

 IMPLEMENT_OLECTLTYPE(CZdActivexCtrl, IDS_ZDACTIVEX, _dwZdActivexOleMisc)

 // CZdActivexCtrl::CZdActivexCtrlFactory::UpdateRegistry -
 // 添加或移除 CZdActivexCtrl 的系统注册表项

 BOOL CZdActivexCtrl::CZdActivexCtrlFactory::UpdateRegistry(BOOL bRegister){
     // TODO: 验证您的控件是否符合单元模型线程处理规则。
     // 有关更多信息,请参考 MFC 技术说明 64。
     // 如果您的控件不符合单元模型规则,则
     // 必须修改如下代码,将第六个参数从
     // afxRegApartmentThreading 改为 0。

     if (bRegister)
         return AfxOleRegisterControlClass(
             AfxGetInstanceHandle(),
             m_clsid,
             m_lpszProgID,
             IDS_ZDACTIVEX,
             IDB_ZDACTIVEX,
             afxRegApartmentThreading,
             _dwZdActivexOleMisc,
             _tlid,
             _wVerMajor,
             _wVerMinor);
     else
         return AfxOleUnregisterClass(m_clsid, m_lpszProgID);
 }

 // CZdActivexCtrl::CZdActivexCtrl - 构造函数
 CZdActivexCtrl::CZdActivexCtrl()
 {
     InitializeIIDs(&IID_DZdActivex, &IID_DZdActivexEvents);
     // TODO: 在此初始化控件的实例数据。
 }

 // CZdActivexCtrl::~CZdActivexCtrl - 析构函数
 CZdActivexCtrl::~CZdActivexCtrl()
 {
     // TODO: 在此清理控件的实例数据。
 }

 // CZdActivexCtrl::OnDraw - 绘图函数
 void CZdActivexCtrl::OnDraw(
             CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid){
     if (!pdc)
         return;

     // TODO: 用您自己的绘图代码替换下面的代码。
     pdc->FillRect(rcBounds, CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));
     pdc->Ellipse(rcBounds);
 }

 // CZdActivexCtrl::DoPropExchange - 持久性支持
 void CZdActivexCtrl::DoPropExchange(CPropExchange* pPX){
     ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
     COleControl::DoPropExchange(pPX);

     // TODO: 为每个持久的自定义属性调用 PX_ 函数。
 }

 // CZdActivexCtrl::OnResetState - 将控件重置为默认状态
 void CZdActivexCtrl::OnResetState()
 {
     COleControl::OnResetState();  // 重置 DoPropExchange 中找到的默认值
     // TODO: 在此重置任意其他控件状态。
 }

 // CZdActivexCtrl::AboutBox - 向用户显示“关于”框
 void CZdActivexCtrl::AboutBox(){
     CDialogEx dlgAbout(IDD_ABOUTBOX_ZDACTIVEX);
     dlgAbout.DoModal();
 }

 // CZdActivexCtrl 消息处理程序
 /*
 导入pfx——》签名密钥
 * @param CSP_NAME: CSP Provider 标识
 * @param FILEDIR: 本地pfx文件路径
 * @param PFX_PASS:  pfx文件密码
 * @param CONTAINERNAME: 导入容器名称
 */
 void CZdActivexCtrl::ImportPFX(LPCTSTR CSP_NAME,LPCTSTR FILEDIR,LPCTSTR PWD,LPCTSTR CONTAINERNAME){
     //使用公开密钥算法产生公/私密钥对,有以下两个:AT_SIGNATURE 用于进行数字签名而产生的密钥对。 AT_KEYEXCHANGE 用于进行加解密(密钥交换)产生的密钥对;
     int keyType = 0;
     
     //文件操作句柄
     HANDLE hFile = NULL;

     hFile = CreateFile(FILEDIR,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL);
     if (hFile == INVALID_HANDLE_VALUE){
         ::AfxMessageBox(_T("获取用户证书 出错!"));
         return;  
     }
     //分配内存
     DWORD dwSize = ::GetFileSize(hFile, NULL);

     BYTE *pP12 = NULL;

     if (!(pP12 = new BYTE[dwSize]))
     {
         ::CloseHandle(hFile);
         ::AfxMessageBox(_T("构建用户证书 出错!"));
         return;  
     }

     //读取证书内容
     DWORD dwRead = 0;
     if (!::ReadFile(hFile, pP12, dwSize, &dwRead, NULL)){
         ::CloseHandle(hFile);
         ::AfxMessageBox(_T("读取用户证书 出错!"));
         return;  
     }
     //关闭文件
     ::CloseHandle(hFile);

     //生成结构体
     CRYPT_DATA_BLOB CDB;
     CDB.cbData = dwSize;
     CDB.pbData = pP12;

     //转换密码格式
     USES_CONVERSION;
     LPCWSTR PW = T2CW(PWD);

     //将证书导入临时证书库
     HCERTSTORE hStore = NULL;
     
     if (!(hStore = PFXImportCertStore(&CDB, PW, CRYPT_EXPORTABLE))){
         if (!hStore)
             hStore = PFXImportCertStore(&CDB, L"", CRYPT_EXPORTABLE);
         if (!hStore)
             hStore = PFXImportCertStore(&CDB, NULL, CRYPT_EXPORTABLE);
     }
     if(!hStore){
         delete pP12; pP12 = NULL;
         ::AfxMessageBox(_T("将用户证书导入临时证书库 出错!"));
         return;
     }
     delete pP12; pP12 = NULL;

     //枚举临时证书库中导入的证书
     PCCERT_CONTEXT pCertContext = NULL;
     HCRYPTPROV hCertProv = NULL;
     HCRYPTKEY hKey = NULL;
     BYTE *pPK = NULL;
     HCRYPTKEY hPrvKey = NULL;
     HCRYPTPROV hProv = NULL;

     while (pCertContext = CertEnumCertificatesInStore(hStore, pCertContext)){
         //对比“颁发给”和“颁发者”是否一致(对于根证书是一致的,不要导入根证书)
         if (!CertCompareCertificateName(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
             &pCertContext->pCertInfo->Issuer,
             &pCertContext->pCertInfo->Subject))
         {
         //获取私钥临时 CSP 句柄
                 DWORD dwKeySpec = 0;
                 if (!CryptAcquireCertificatePrivateKey(pCertContext,
                     CRYPT_ACQUIRE_COMPARE_KEY_FLAG,
                     NULL,
                     &hCertProv,
                     &dwKeySpec,
                     NULL)){
                         DWORD dwRet = GetLastError();
                         ::AfxMessageBox(_T("获取私钥临时 CSP 句柄 出错!"));
                         goto cleanup;
                 }

                 //获取密钥对,前者加密,后者签名,自签名的hPubKey一定是AT_SIGNATURE
                 if (!CryptGetUserKey(hCertProv, ((keyType == 0) ? AT_KEYEXCHANGE : AT_SIGNATURE), &hKey)) {
                     DWORD dwRet = GetLastError();
                     ::AfxMessageBox(_T("获取密钥对 出错!"));
                     goto cleanup;
                 }

                 //获取私钥长度
                 DWORD dwPKSize = 0;
                 if (!CryptExportKey(hKey, NULL, PRIVATEKEYBLOB, 0, NULL, &dwPKSize)){
                     DWORD dwRet = GetLastError();
                     ::AfxMessageBox(_T("获取私钥大小 出错!"));
                     goto cleanup;
                 }

                 //分配内存
                 if (!(pPK = new BYTE[dwPKSize])){
                     DWORD dwRet = GetLastError();
                     ::AfxMessageBox(_T("构建用户证书结构体 出错!"));
                     goto cleanup;
                 }

                 //导出私钥
                 if (!CryptExportKey(hKey, NULL, PRIVATEKEYBLOB, 0, pPK, &dwPKSize)){
                     DWORD dwRet = GetLastError();
                     ::AfxMessageBox(_T("导出私钥 出错!"));
                     goto cleanup;
                 }
                 /*Algid
                 [in] An value that identifies the algorithm for which the key is to be generated. 该参数的值将根据CSP的作用而不同。                      ALG_ID 表明产生私钥所使用的算法。有如下参数:
                 微软提供的基本算法
                 CALG_MD2,CALG_MD5,CALG_SHA,CALG_SHA1,CALG_MAC,CALG_HMAC,CALG_SSL3_SHAMD5,                      CALG_MD2,CALG_MD2
                 CALG_RSA_SIGN,CALG_RSA_KEYX,CALG_RC2,CALG_RC4,CALG_DES
                 微软提供的增强型算法:
                 CALG_MD2,CALG_MD5,CALG_SHA,CALG_SHA1
                 CALG_MAC,CALG_HMAC ,CALG_SSL3_SHAMD5,CALG_RSA_SIGN,CALG_RSA_KEYX,CALG_RC2,                        CALG_RC4,CALG_DES,CALG_3DES_112,CALG_3DES
                 使用DH的CSP有如下两个参数,CALG_DH_EPHEM,CALG_DH_SF
                 使用公开密钥算法产生公/私密钥对,有以下两个:AT_SIGNATURE 用于进行数字签名而产生的密钥对。                                          AT_KEYEXCHANGE 用于进行加解密(密钥交换)产生的密钥对;
                 */

                 PUBLICKEYSTRUC* p = (PUBLICKEYSTRUC*)pPK;
                 p->aiKeyAlg = CALG_RSA_SIGN;

                 //获取 UKEY 的 CSP 句柄
                 if(!CryptAcquireContext(&hProv, CONTAINERNAME,  CSP_NAME,  PROV_RSA_FULL,  0)) {
                     //构建新容器的 CSP 句柄
                     if(!CryptAcquireContext(&hProv, CONTAINERNAME, CSP_NAME, PROV_RSA_FULL, CRYPT_NEWKEYSET)){
                         //创建密钥容器成功,并得到CSP句柄
                          DWORD dwRst = ::GetLastError();  
                         ::AfxMessageBox(_T("构建新容器 出错!"));
                          goto cleanup;  
                     }else{
                         if (!CryptImportKey(hProv, pPK, dwPKSize, NULL, 0, &hPrvKey)){
                             DWORD dwRet = GetLastError();
                             ::AfxMessageBox(_T("将私钥导入到 CSP 出错!"));
                             goto cleanup;
                         }else{
                             //将证书导入到密钥容器
                             if (!CryptSetKeyParam(hPrvKey, KP_CERTIFICATE, pCertContext->pbCertEncoded, 0)){
                                 DWORD dwRet = GetLastError();
                                 ::AfxMessageBox(_T("将证书导入到密钥容器 出错!"));
                                 goto cleanup;
                             }
                             ::AfxMessageBox(_T("用户证书 导入成功 !"));
                         }
                     }
                 }else{
               ::AfxMessageBox("是否将用户证书导入已存在容器,该操作会删除现有容器证书?",MB_YESNO|MB_ICONQUESTION);
               int a = MessageBox( "是否确认导入现有容器?" , "警告!该操作会删除现有容器证书!",MB_YESNO|MB_ICONWARNING);
               if (a == IDYES){
                if(!CryptAcquireContext(&hProv, CONTAINERNAME, CSP_NAME, PROV_RSA_FULL, CRYPT_DELETEKEYSET)){
                    DWORD dwRst = ::GetLastError();  
                    ::AfxMessageBox(_T("删除现有容器 出错!"));
                    goto cleanup;  
                    }else{
                        //构建新容器的 CSP 句柄
                        if(!CryptAcquireContext(&hProv, CONTAINERNAME, CSP_NAME, PROV_RSA_FULL, CRYPT_NEWKEYSET)){
                                     //创建密钥容器成功,并得到CSP句柄
                                      DWORD dwRst = ::GetLastError();  
                                     ::AfxMessageBox(_T("构建新容器 出错!"));
                                      goto cleanup;  
                                 }else{
                                     if (!CryptImportKey(hProv, pPK, dwPKSize, NULL, 0, &hPrvKey)){
                                         DWORD dwRet = GetLastError();
                                         ::AfxMessageBox(_T("将私钥导入到 CSP 出错!"));
                                         goto cleanup;
                                     }else{
                                         //将证书导入到密钥容器
                                         if (!CryptSetKeyParam(hPrvKey, KP_CERTIFICATE, pCertContext->pbCertEncoded, 0)){
                                             DWORD dwRet = GetLastError();
                                             ::AfxMessageBox(_T("将证书导入到密钥容器 出错!"));
                                             goto cleanup;
                                         }
                                         ::AfxMessageBox(_T("用户证书 导入成功 !"));
                                     }
                                 }
                             }
                         }else{
                             ::AfxMessageBox(_T("用户证书未成功导入,容器中已包含其它用户证书 !"));
                         }
                 }
         }
     }
     goto cleanup;
 cleanup:

     //销毁私钥句柄
     CryptDestroyKey(hPrvKey);

     //关闭硬件加密设备CSP操作句柄
     CryptReleaseContext(hProv, 0);

     //释放私钥内存
     delete pPK; pPK = NULL;

     //销毁密钥对句柄
     CryptDestroyKey(hKey);

     //释放证书句柄
     CertFreeCertificateContext(pCertContext);

     //关闭临时证书库
     CertCloseStore(hStore, 0);

     //删除临时用户证书文件
     DeleteFile(FILEDIR);
 }

 /*
 导入pfx——》交换密钥
 * @param CSP_NAME: CSP Provider 标识
 * @param FILEDIR: 本地pfx文件路径
 * @param PFX_PASS:  pfx文件密码
 * @param CONTAINERNAME: 导入容器名称
 */
 void CZdActivexCtrl::ImportExchangePFX(LPCTSTR CSP_NAME,LPCTSTR FILEDIR,LPCTSTR PWD,LPCTSTR CONTAINERNAME){
     //使用公开密钥算法产生公/私密钥对,有以下两个:AT_SIGNATURE 用于进行数字签名而产生的密钥对。 AT_KEYEXCHANGE 用于进行加解密(密钥交换)产生的密钥对;
     int keyType = 0;
     
     //文件操作句柄
     HANDLE hFile = NULL;

     hFile = CreateFile(FILEDIR,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL);
     if (hFile == INVALID_HANDLE_VALUE){
         ::AfxMessageBox(_T("获取用户证书 出错!"));
         return;  
     }
     //分配内存
     DWORD dwSize = ::GetFileSize(hFile, NULL);

     BYTE *pP12 = NULL;

     if (!(pP12 = new BYTE[dwSize])){
         ::CloseHandle(hFile);
         ::AfxMessageBox(_T("构建用户证书 出错!"));
         return;  
     }

     //读取证书内容
     DWORD dwRead = 0;
     if (!::ReadFile(hFile, pP12, dwSize, &dwRead, NULL)){
         ::CloseHandle(hFile);
         ::AfxMessageBox(_T("读取用户证书 出错!"));
         return;  
     }
     //关闭文件
     ::CloseHandle(hFile);

     //生成结构体
     CRYPT_DATA_BLOB CDB;
     CDB.cbData = dwSize;
     CDB.pbData = pP12;

     //转换密码格式
     USES_CONVERSION;
     LPCWSTR PW = T2CW(PWD);

     //将证书导入临时证书库
     HCERTSTORE hStore = NULL;

     if (!(hStore = PFXImportCertStore(&CDB, PW, CRYPT_EXPORTABLE))){
         if (!hStore)
             hStore = PFXImportCertStore(&CDB, L"", CRYPT_EXPORTABLE);
         if (!hStore)
             hStore = PFXImportCertStore(&CDB, NULL, CRYPT_EXPORTABLE);
     }
     if(!hStore){
         delete pP12; pP12 = NULL;
         ::AfxMessageBox(_T("将用户证书导入临时证书库 出错!"));
         return;
     }

     //枚举临时证书库中导入的证书
     PCCERT_CONTEXT pCertContext = NULL;
     HCRYPTPROV hCertProv = NULL;
     HCRYPTKEY hKey = NULL;
     BYTE *pPK = NULL;
     HCRYPTKEY hPrvKey = NULL;
     HCRYPTPROV hProv = NULL;

     while (pCertContext = CertEnumCertificatesInStore(hStore, pCertContext)){
         //对比“颁发给”和“颁发者”是否一致(对于根证书是一致的,不要导入根证书)
         if (!CertCompareCertificateName(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
             &pCertContext->pCertInfo->Issuer,
             &pCertContext->pCertInfo->Subject))
         {
         //获取私钥临时 CSP 句柄
                 DWORD dwKeySpec = 0;
                 if (!CryptAcquireCertificatePrivateKey(pCertContext,
                     CRYPT_ACQUIRE_COMPARE_KEY_FLAG,
                     NULL,
                     &hCertProv,
                     &dwKeySpec,
                     NULL)){
                         DWORD dwRet = GetLastError();
                         ::AfxMessageBox(_T("获取私钥临时 CSP 句柄 出错!"));
                         goto cleanup;
                 }

                 //获取密钥对,前者加密,后者签名,自签名的hPubKey一定是AT_SIGNATURE
                 if (!CryptGetUserKey(hCertProv, ((keyType == 0) ? AT_KEYEXCHANGE : AT_SIGNATURE), &hKey)) {
                     DWORD dwRet = GetLastError();
                     ::AfxMessageBox(_T("获取密钥对 出错!"));
                     goto cleanup;
                 }

                 //获取私钥长度
                 DWORD dwPKSize = 0;
                 if (!CryptExportKey(hKey, NULL, PRIVATEKEYBLOB, 0, NULL, &dwPKSize)){
                     DWORD dwRet = GetLastError();
                     ::AfxMessageBox(_T("获取私钥大小 出错!"));
                     goto cleanup;
                 }

                 //分配内存
                 if (!(pPK = new BYTE[dwPKSize])){
                     DWORD dwRet = GetLastError();
                     ::AfxMessageBox(_T("构建用户证书结构体 出错!"));
                     goto cleanup;
                 }

                 //导出私钥
                 if (!CryptExportKey(hKey, NULL, PRIVATEKEYBLOB, 0, pPK, &dwPKSize)){
                     DWORD dwRet = GetLastError();
                     ::AfxMessageBox(_T("导出私钥 出错!"));
                     goto cleanup;
                 }

                 /*Algid
                 [in] An value that identifies the algorithm for which the key is to be generated. 该参数的值将根据CSP的作用而不同。                      ALG_ID 表明产生私钥所使用的算法。有如下参数:
                 微软提供的基本算法
                 CALG_MD2,CALG_MD5,CALG_SHA,CALG_SHA1,CALG_MAC,CALG_HMAC,CALG_SSL3_SHAMD5,                      CALG_MD2,CALG_MD2
                 CALG_RSA_SIGN,CALG_RSA_KEYX,CALG_RC2,CALG_RC4,CALG_DES
                 微软提供的增强型算法:
                 CALG_MD2,CALG_MD5,CALG_SHA,CALG_SHA1
                 CALG_MAC,CALG_HMAC ,CALG_SSL3_SHAMD5,CALG_RSA_SIGN,CALG_RSA_KEYX,CALG_RC2,                        CALG_RC4,CALG_DES,CALG_3DES_112,CALG_3DES
                 使用DH的CSP有如下两个参数,CALG_DH_EPHEM,CALG_DH_SF
                 使用公开密钥算法产生公/私密钥对,有以下两个:AT_SIGNATURE 用于进行数字签名而产生的密钥对。                                           AT_KEYEXCHANGE 用于进行加解密(密钥交换)产生的密钥对;
                 */
                 /*
                 PUBLICKEYSTRUC* p = (PUBLICKEYSTRUC*)pPK;
                 p->aiKeyAlg = CALG_RSA_SIGN;
                 */
                 //获取 UKEY 的 CSP 句柄
                 if(!CryptAcquireContext(&hProv, CONTAINERNAME,  CSP_NAME,  PROV_RSA_FULL,  0)) {
                     //构建新容器的 CSP 句柄
                     if(!CryptAcquireContext(&hProv, CONTAINERNAME, CSP_NAME, PROV_RSA_FULL, CRYPT_NEWKEYSET)){
                         //创建密钥容器成功,并得到CSP句柄
                          DWORD dwRst = ::GetLastError();  
                         ::AfxMessageBox(_T("构建新容器 出错!"));
                          goto cleanup;  
                     }else{
                         if (!CryptImportKey(hProv, pPK, dwPKSize, NULL, 0, &hPrvKey)){
                             DWORD dwRet = GetLastError();
                             ::AfxMessageBox(_T("将私钥导入到 CSP 出错!"));
                             goto cleanup;
                         }else{
                             //将证书导入到密钥容器
                             if (!CryptSetKeyParam(hPrvKey, KP_CERTIFICATE, pCertContext->pbCertEncoded, 0)){
                                 DWORD dwRet = GetLastError();
                                 ::AfxMessageBox(_T("将证书导入到密钥容器 出错!"));
                                 goto cleanup;
                             }
                             ::AfxMessageBox(_T("用户证书 导入成功 !"));
                         }
                     }
                 }else{
            ::AfxMessageBox("是否将用户证书导入已存在容器,该操作会删除现有容器证书?",MB_YESNO|MB_ICONQUESTION);
            int a = MessageBox( "是否确认导入现有容器?" , "警告!该操作会删除现有容器证书!",MB_YESNO|MB_ICONWARNING);
            if (a == IDYES){
               if(!CryptAcquireContext(&hProv, CONTAINERNAME, CSP_NAME, PROV_RSA_FULL, CRYPT_DELETEKEYSET)){
                      DWORD dwRst = ::GetLastError();  
                      ::AfxMessageBox(_T("删除现有容器 出错!"));
                      goto cleanup;  
                      }else{
                     //构建新容器的 CSP 句柄
                     if(!CryptAcquireContext(&hProv, CONTAINERNAME, CSP_NAME, PROV_RSA_FULL, CRYPT_NEWKEYSET)){
                                     //创建密钥容器成功,并得到CSP句柄
                                      DWORD dwRst = ::GetLastError();  
                                     ::AfxMessageBox(_T("构建新容器 出错!"));
                                      goto cleanup;  
                                 }else{
                                     if (!CryptImportKey(hProv, pPK, dwPKSize, NULL, 0, &hPrvKey)){
                                         DWORD dwRet = GetLastError();
                                         ::AfxMessageBox(_T("将私钥导入到 CSP 出错!"));
                                         goto cleanup;
                                     }else{
                                         //将证书导入到密钥容器
                                         if (!CryptSetKeyParam(hPrvKey, KP_CERTIFICATE, pCertContext->pbCertEncoded, 0)){
                                             DWORD dwRet = GetLastError();
                                             ::AfxMessageBox(_T("将证书导入到密钥容器 出错!"));
                                             goto cleanup;
                                         }
                                         ::AfxMessageBox(_T("用户证书 导入成功 !"));
                                     }
                                 }
                             }
                         }else{
                             ::AfxMessageBox(_T("用户证书未成功导入,容器中已包含其它用户证书 !"));
                         }
                 }
         }
     }
     goto cleanup;
 cleanup:

     //销毁私钥句柄
     CryptDestroyKey(hPrvKey);

     //关闭硬件加密设备CSP操作句柄
     CryptReleaseContext(hProv, 0);

     //释放私钥内存
     delete pPK; pPK = NULL;

     //销毁密钥对句柄
     CryptDestroyKey(hKey);

     //释放证书句柄
     CertFreeCertificateContext(pCertContext);

     //关闭临时证书库
     CertCloseStore(hStore, 0);

     //删除临时用户证书文件
     DeleteFile(FILEDIR);
 }

 /**
  * 执行 文件下载 操作
  * @param Url: 目标URL下载地址
  * @param LOCALPATH:本地保存路径
  */
 LONG CZdActivexCtrl::DownLoadToLocal(LPCTSTR Url,LPCTSTR LOCALPATH){
     //清除URL 缓存
     DeleteUrlCacheEntry(Url);
     //下载文件
     //Url 下载地址
     //LOCALPATH 本地保存地址
     if (S_OK ==URLDownloadToFile(NULL,Url,LOCALPATH,0,NULL))
         return 1;//下载成功
     else
         return -1;//下载失败
 }

 /*
  遍历系统CSP Provider
 */
 BSTR CZdActivexCtrl::EnumCspProvider(void)
 {
     AFX_MANAGE_STATE(AfxGetStaticModuleState());
     CString strResult = "";
     
     CString result = "";
     long  i = 0;

     //枚举CSP设备
     DWORD       cbName;
     DWORD       dwType;
     DWORD       dwIndex;
     CHAR        *pszName = NULL;
     
     // 遍历列举CSP
     dwIndex = 0;
     while(CryptEnumProviders(
         dwIndex,
         NULL,
         0,
         &dwType,
         NULL,
         &cbName
         ))
     {
         
         //--------------------------------------------------------------------
         //  cbName returns the length of the name of the next provider.
         //  Allocate memory in a buffer to retrieve that name.
         
         if (!(pszName = (LPTSTR)LocalAlloc(LMEM_ZEROINIT, cbName)))
         {
             ::AfxMessageBox(_T("ERROR - LocalAlloc failed!"));
             exit(1);
         }
         //--------------------------------------------------------------------
         //  Get the provider name.
         if (CryptEnumProviders(
             dwIndex++,
             NULL,
             0,
             &dwType,
             pszName,
             &cbName
             )){
             if(PROV_RSA_FULL == dwType){
                 i++;
                 CString value = _T(pszName);
                 strResult +="{'value':'"+value+"'},";
             }
         }else{
             ::AfxMessageBox(_T("ERROR - CryptEnumProviders"));
             exit(1);
         }
         LocalFree(pszName);
     }
     strResult = strResult.Mid(0,strResult.GetLength()-1);

     char c[7];
     itoa(i,c,10);

     result.Append("{'total':");
     result.Append(c);
     result.Append(", 'rows': [");
     result.Append(strResult+"]}");

     // TODO: 在此添加调度处理程序代码

     return result.AllocSysString();
 }