HTTP/HTTPSでPOST(wininet.dll)

解説


 Wininet.dllを利用して掲示板に投稿する方法。URLを変えることでHTTPとHTTPS(SSL)に対応する。ここではポストした結果はファイルとして保存している。



使用例


	DownloadWithPostTest(_T("https://www.dinop.com/testssl.html"),_T("aaa=bbb&ccc=ddd"),"c:\\aaa.txt");



ソースコード




#include "atlfile.h"
#include "wininet.h" 
#pragma comment(lib,"wininet.lib")


bool	DownloadWithPostTest(LPCTSTR pszURL,LPCTSTR pszPostData,LPCTSTR pszLocalFile,DWORD dwBuffSize=1024)
{
	TCHAR		pszAccept[] = _T("Accept: */*");
	TCHAR		pszContentType[] = _T("Content-Type: application/x-www-form-urlencoded");
	BOOL		ret;
	DWORD		dwReadSize;
	DWORD		dwWrittenSize;
	BYTE*		pcbBuff;
	HRESULT		hr;
	HINTERNET	hInternet;
	HINTERNET	hConnect;
	HINTERNET	hRequest;
	TCHAR		lpszHostName[256];
	TCHAR		lpszScheme[256];
	TCHAR		lpszUserName[256];
	TCHAR		lpszPassword[256];
	TCHAR		lpszUrlPath[1024];
	TCHAR		lpszExtraInfo[1024];
	int			nFind;
	CAtlFile	cFile;
	CAtlString	strPath;
	URL_COMPONENTS	sComponents;


	//////////////////////////////
	//	URLからサーバー名やポート番号などを取得
	//
	ZeroMemory(&sComponents,sizeof(URL_COMPONENTS));
	sComponents.dwStructSize		= sizeof(URL_COMPONENTS);
	sComponents.lpszHostName		= lpszHostName;
	sComponents.dwHostNameLength	= sizeof(lpszHostName) / sizeof(TCHAR);
	sComponents.lpszScheme			= lpszScheme;
	sComponents.dwSchemeLength		= sizeof(lpszScheme) / sizeof(TCHAR);
	sComponents.lpszUserName		= lpszUserName;
	sComponents.dwUserNameLength	= sizeof(lpszUserName) / sizeof(TCHAR);
	sComponents.lpszPassword		= lpszPassword;
	sComponents.dwPasswordLength	= sizeof(lpszPassword) / sizeof(TCHAR);
	sComponents.lpszUrlPath			= lpszUrlPath;
	sComponents.dwUrlPathLength		= sizeof(lpszUrlPath) / sizeof(TCHAR);
	sComponents.lpszExtraInfo		= lpszExtraInfo;
	sComponents.dwExtraInfoLength	= sizeof(lpszExtraInfo) / sizeof(TCHAR);

	ret = ::InternetCrackUrl(pszURL,lstrlen(pszURL),ICU_ESCAPE,&sComponents);
	if(ret == FALSE)
		return	false;


	//////////////////////////////
	//	InternetCrackUrlはURLなどに含まれる"%20"などをデコード
	//	してしまうので、関数呼出時のURLのパスを使って接続する
	//	変則的なサーバーは「/index.html?aaa=bbb」というURLに対
	//	してPOSTを要求することもあるので、それにも対応。
	//

	strPath = pszURL;
	nFind = strPath.Find(lpszHostName);
	if(nFind >= 0)
	{
		nFind = strPath.Find(_T("/"),nFind);
		if(nFind >= 0)
			strPath = strPath.Right(strPath.GetLength() - nFind);
	}
	if(nFind < 0)
	{
		strPath = lpszUrlPath;
		strPath += lpszExtraInfo;
	}


	//バッファ確保
	pcbBuff = new BYTE[dwBuffSize];
	if(pcbBuff == NULL)
		return	false;


	//////////////////////////////
	//	接続開始
	//

	hInternet = ::InternetOpen(NULL,INTERNET_OPEN_TYPE_PRECONFIG,NULL,NULL,0);

	hConnect = NULL;
	if(hInternet)
		hConnect = ::InternetConnect(hInternet,lpszHostName,sComponents.nPort,lpszUserName,lpszPassword,INTERNET_SERVICE_HTTP,0,0);

	hRequest = NULL;
	if(hConnect)
	{
		if(sComponents.nScheme == INTERNET_SCHEME_HTTPS)
			hRequest = ::HttpOpenRequest(hConnect,_T("POST"),strPath,NULL,NULL,(LPCTSTR*)&pszAccept,INTERNET_FLAG_RELOAD | INTERNET_FLAG_SECURE | INTERNET_FLAG_NO_UI | INTERNET_FLAG_KEEP_CONNECTION,0);
		else
			hRequest = ::HttpOpenRequest(hConnect,_T("POST"),strPath,NULL,NULL,(LPCTSTR*)&pszAccept,INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_UI | INTERNET_FLAG_KEEP_CONNECTION,0);
	}

	ret = FALSE;
	if(hRequest)
		ret = ::HttpSendRequest(hRequest,pszContentType,lstrlen(pszContentType),(LPVOID)pszPostData,lstrlen(pszPostData));

	//if(ret)
	//{
	//	DWORD	dwContentLength;

	//	dwContentLength = dwBuffSize;
	//	ret = ::HttpQueryInfo(hRequest,HTTP_QUERY_CONTENT_LENGTH,pcbBuff,&dwContentLength,NULL);
	//	if(ret)
	//	{
	//		ATLTRACE(_T("ダウンロードサイズは合計 %d Bytes\n"),dwContentLength);
	//	}
	//	else
	//	{
	//		ATLTRACE(_T("ダウンロードサイズは不明\n"),dwContentLength);
	//	}
	//	ret = TRUE;
	//}

	if(ret)
		ret = SUCCEEDED(cFile.Create(pszLocalFile,GENERIC_WRITE,0,CREATE_ALWAYS)) ? TRUE : FALSE;
	if(ret)
	{
		while(1)
		{
			::Sleep(0);
			dwReadSize = 0;
			ret = ::InternetReadFile(hRequest,pcbBuff,dwBuffSize,&dwReadSize);
			if(ret == FALSE)
				break;

			if(dwReadSize == 0)
				break;

			hr = cFile.Write(pcbBuff,dwReadSize,&dwWrittenSize);
			if(SUCCEEDED(hr))
				continue;

			ret = FALSE;
			break;
		}
	}

	hr = cFile.Flush();
	cFile.Close();
	if(hRequest)
		::InternetCloseHandle(hRequest);
	if(hConnect)
		::InternetCloseHandle(hConnect);
	if(hInternet)
		::InternetCloseHandle(hInternet);
	delete	pcbBuff;

	return	(SUCCEEDED(hr) && ret) ? true : false;
}


カテゴリー「VC++ TIPS」 のエントリー