https的连接问题。
下了一个连接https服务器的例子。是个SDK的工程,可以正常使用。
现在想做成多线程的,自己开了个MFC的工程,建立线程等等,都可以正常LINK。
但把例子里的main函数中的代码复制到进程函数中,就报这个错。
nresolved external symbol __imp__InternetConnectA@32
SSLCon.obj : error LNK2001: unresolved external symbol __imp__InternetOpenA@20
SSLCon.obj : error LNK2001: unresolved external symbol __imp__HttpSendRequestA@20
SSLCon.obj : error LNK2001: unresolved external symbol __imp__HttpOpenRequestA@32
SSLCon.obj : error LNK2001: unresolved external symbol __imp__CertCloseStore@8
SSLCon.obj : error LNK2001: unresolved external symbol __imp__CertFreeCertificateContext@4
SSLCon.obj : error LNK2001: unresolved external symbol __imp__InternetCloseHandle@4
SSLCon.obj : error LNK2001: unresolved external symbol __imp__InternetSetOptionA@16
SSLCon.obj : error LNK2001: unresolved external symbol __imp__CertOpenSystemStoreA@8
SSLCon.obj : error LNK2001: unresolved external symbol __imp__CertFindCertificateInStore@24
SSLCon.obj : error LNK2001: unresolved external symbol __imp__InternetReadFile@16
Release/httpsconnect.exe : fatal error LNK1120: 11 unresolved externals
求问题的原因和解决的办法。附录SSLCon这个类的代码:
// SSLCon.cpp: implementation of the CSslConnection class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "SSLCon.h"
#include "WinInet.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CSslConnection::CSslConnection()
{
m_hInternet = NULL;
m_hRequest = NULL;
m_certStoreType = certStoreMY;
m_hStore = NULL;
m_hSession = NULL;
m_pContext = NULL;
m_wPort = 443;
m_strAgentName = "";
m_secureFlags = INTERNET_FLAG_RELOAD|INTERNET_FLAG_KEEP_CONNECTION|INTERNET_FLAG_NO_CACHE_WRITE|
INTERNET_FLAG_SECURE|INTERNET_FLAG_IGNORE_CERT_CN_INVALID;
}
CSslConnection::~CSslConnection()
{
ClearHandles();
}
bool CSslConnection::ConnectToHttpsServer(string &strVerb)
{
try {
m_hInternet = InternetOpen(m_strAgentName.c_str(), INTERNET_OPEN_TYPE_PRECONFIG ,
NULL, NULL, 0);
if (!m_hInternet) {
m_strLastError = "Cannot open internet";
m_lastErrorCode = GetLastError();
return false;
}
m_hSession = InternetConnect(m_hInternet,
m_strServerName.c_str(),
m_wPort,
m_strUserName.c_str(),
m_strPassword.c_str(),
INTERNET_SERVICE_HTTP,
0,
0);
if (!m_hSession) {
m_strLastError = "Cannot connect to internet";
m_lastErrorCode = GetLastError();
ClearHandles();
return false;
}
}
catch(...) {
m_strLastError = "Memory Exception occured";
m_lastErrorCode = GetLastError();
return false;
}
return true;
}
bool CSslConnection::SendHttpsRequest()
{
try {
m_hRequest = HttpOpenRequest(m_hSession,
"POST",
m_strObjectName.c_str(),
NULL,
"",
NULL,
m_secureFlags,
m_ReqID);
if (!m_hRequest) {
m_strLastError = "Cannot perform http request";
m_lastErrorCode = GetLastError();
ClearHandles();
return false;
}
m_ReqID++;
for (int tries = 0; tries < 20; ++tries) {
int result = HttpSendRequest(m_hRequest, NULL, 0, NULL, 0);
if (result)
return true;
int lastErr = GetLastError();
if (lastErr == ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED) {
if (!SetClientCert()) {
m_strLastError = "Cannot perform http request, client authentication needed but couldnt detect required client certificate";
m_lastErrorCode = GetLastError();
return false;
}
}
else if (lastErr == ERROR_INTERNET_INVALID_CA) {
m_strLastError = "Cannot perform http request, client authentication needed, invalid client certificate is used";
m_lastErrorCode = GetLastError();
return false;
}
else {
m_strLastError = "Cannot perform http request";
m_lastErrorCode = GetLastError();
return false;
}
}
}
catch(...) {
m_strLastError = "Memory Exception occured";
m_lastErrorCode = GetLastError();
return false;
}
return false;
}
void CSslConnection::ClearHandles()
{
if (m_hInternet) {
InternetCloseHandle(m_hInternet);
m_hInternet = NULL;
}
if (m_hSession) {
InternetCloseHandle(m_hSession);
m_hSession = NULL;
}
if (m_pContext) {
CertFreeCertificateContext(m_pContext);
m_pContext = NULL;
}
if (m_hStore) {
CertCloseStore(m_hStore, CERT_CLOSE_STORE_FORCE_FLAG);
m_hStore = NULL;
}
}
bool CSslConnection::SetClientCert()
{
char *lpszStoreName;
switch (m_certStoreType) {
case certStoreMY:
lpszStoreName = "MY";
break;
case certStoreCA:
lpszStoreName = "CA";
break;
case certStoreROOT:
lpszStoreName = "ROOT";
break;
case certStoreSPC:
lpszStoreName = "SPC";
break;
}
m_hStore = CertOpenSystemStore(NULL, lpszStoreName);
if (!m_hStore) {
m_strLastError = "Cannot open system store ";
m_strLastError += lpszStoreName;
m_lastErrorCode = GetLastError();
ClearHandles();
return false;
}
m_pContext = FindCertWithOUNITName();
if (!m_pContext) {
m_strLastError = "Cannot find the required certificate";
m_lastErrorCode = GetLastError();
ClearHandles();
return false;
}
// INTERNET_OPTION_CLIENT_CERT_CONTEXT is 84
int res = InternetSetOption(m_hRequest,
INTERNET_OPTION_CLIENT_CERT_CONTEXT,
(void *) m_pContext, sizeof(CERT_CONTEXT));
if (!res) {
m_strLastError = "Cannot set certificate context";
m_lastErrorCode = GetLastError();
ClearHandles();
return false;
}
return true;
}
PCCERT_CONTEXT CSslConnection::FindCertWithOUNITName()
{
//This function performs a certificate contex search
//by the organizational unit name of the issuer
//Take this function as a sample for your possible different search functions
PCCERT_CONTEXT pCertContext = NULL;
CERT_RDN certRDN;
certRDN.cRDNAttr = 1;
certRDN.rgRDNAttr = new CERT_RDN_ATTR;
certRDN.rgRDNAttr->pszObjId = szOID_ORGANIZATIONAL_UNIT_NAME;
certRDN.rgRDNAttr->dwValueType = CERT_RDN_ANY_TYPE;
certRDN.rgRDNAttr->Value.pbData = (BYTE *) m_strOName.c_str();
certRDN.rgRDNAttr->Value.cbData = strlen(m_strOName.c_str());
pCertContext = CertFindCertificateInStore(m_hStore,
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
0, CERT_FIND_SUBJECT_STR, L"hsic", NULL);
delete certRDN.rgRDNAttr;
return pCertContext;
}
string CSslConnection::GetRequestResult()
{
DWORD dwNumberOfBytesRead;
char sz[1024];
string strResult;
int result;
do {
result = InternetReadFile(m_hRequest, sz, 1023, &dwNumberOfBytesRead);
sz[dwNumberOfBytesRead] = '\0';
int x = strlen(sz);
strResult += sz;
memset(sz, 0, 1024);
} while(result && dwNumberOfBytesRead != 0);
return strResult;
}