サーバレス練習帳

着眼大局着手小局

【Windowsアプリ】IE内のHTMLに書かれた文字列を元に自動でtextareaにフォーマットを記入する。

登録画面をIEで開き、タイトルに「〇〇申請」と入力します。
その後、cppのプログラムを動かすと、タイトルに「申請」が含まれているか否かを判断します。
含まれている場合は、申請用のフォーマットをtextareaにIEが書き込んでくれます。

◆登録画面
freeform.html

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="utf-8"/>
		<title>テスト用!</title>
	</head>
	<body>
		<h1>登録画面</h1>
		<form action="./confirmation.html" method="get">
			<p>
				タイトル:<br>
				<input type="text" name="title" size="40" id ="title">
			</p>
			<p>
				コンテンツ:<br>
				<textarea name="contents" rows="10" cols="40" id = "contents">ここに申請内容が書かれます!</textarea>
			</p>
			<p>
				<input id = "sample" type="submit" value="申請"><input type="reset" value="リセット">
			</p>
		</form>
	</body>
</html>


◆変換プログラム

「全般」から「空のプロジェクト」を作成 → 新しい項目の追加(CPPファイル)

という方式で作成した1回だけ起動するアプリです。
常駐っぽく動かしたいですが、それはこれからトライします。

#include <windows.h>
#include <exdisp.h>
#include <mshtml.h>
#include <oleacc.h>
#include <string.h>

#pragma comment (lib, "oleacc.lib")

BOOL CheckElementData(IHTMLDocument3 *pDocument3);
BOOL GetDocumentFromIE(IHTMLDocument3 **pp);
BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpszCmdLine, int nCmdShow)
{
	IHTMLDocument3 *pDocument3;

	CoInitialize(NULL);


	if (!GetDocumentFromIE(&pDocument3)) {
			CoUninitialize();
			return 0;
	}

	CheckElementData(pDocument3);
	CoUninitialize();
	Sleep(1000);
	
	return 0;
}

BOOL CheckElementData(IHTMLDocument3 *pDocument3)
{
	BSTR               bstrIdTitle,bstrIdContents,bstrHref, bstrText,bstrContents,bstrTarget;
	IHTMLElement       *pElementTitle, *pElementContents;
	IHTMLAnchorElement *pAnchorElement;
	IHTMLInputElement  *pInputElement;

	bstrIdContents = SysAllocString(L"contents");
	pDocument3->getElementById(bstrIdContents, &pElementContents);
	
	bstrIdTitle = SysAllocString(L"title");
	pDocument3->getElementById(bstrIdTitle, &pElementTitle);

	pElementTitle->QueryInterface(IID_PPV_ARGS(&pInputElement));
	pInputElement->get_value(&bstrText);

	char szTitle[255] = "";
	char szTarget[255] = "申請";
	char *adr1;
	char *adr2;

	WideCharToMultiByte(
		CP_ACP, // ANSI コードページ
		0,			// 処理速度とマッピング方法を決定するフラグ
		(OLECHAR*)bstrText,		// ワイド文字列のアドレス
		-1,			// ワイド文字列の文字数
		szTitle,			// 新しい文字列を受け取るバッファのアドレス
		sizeof(szTitle) - 1,		// 新しい文字列を受け取るバッファのサイズ
		NULL,			// マップできない文字の既定値のアドレス
		NULL			// 既定の文字を使ったときにセットするフラグのアドレス
	);

	MessageBox(NULL, TEXT(szTitle), TEXT("OK"), MB_OK);

	adr1 = strstr(szTitle, szTarget);
	if (adr1 != NULL) {
		bstrContents = SysAllocString(L"1. 会社名\n\n2.金額\n\n3.実施日");
		pElementContents->put_innerText(bstrContents);
		MessageBox(NULL, TEXT("このフォーマットで申請してください!"), TEXT("OK"), MB_OK);
	}

	SysFreeString(bstrText);
	//SysFreeString(bstrHref);
	SysFreeString(bstrIdTitle);
	SysFreeString(bstrIdContents);
	//pAnchorElement->Release();
	pElementTitle->Release();
	pElementContents->Release();

	return TRUE;
}


BOOL GetDocumentFromIE(IHTMLDocument3 **pp)
{
	HWND    hwnd;
	UINT    uMsg;
	LRESULT lResult;
	HRESULT hr;

	EnumChildWindows(FindWindow(TEXT("IEFrame"), NULL), EnumChildProc, (LPARAM)&hwnd);
	if (hwnd == NULL)
		return FALSE;

	uMsg = RegisterWindowMessage(TEXT("WM_HTML_GETOBJECT"));
	if (!SendMessageTimeout(hwnd, uMsg, 0, 0, SMTO_ABORTIFHUNG, 1000, (LPDWORD)&lResult))
		return FALSE;

	hr = ObjectFromLresult(lResult, IID_IHTMLDocument3, 0, (void **)pp);
	if (FAILED(hr))
		return FALSE;

	return TRUE;
}

BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM lParam)
{
	TCHAR szClassName[256];

	GetClassName(hwnd, szClassName, sizeof(szClassName) / sizeof(TCHAR));
	if (lstrcmp(szClassName, TEXT("Internet Explorer_Server")) == 0) {
		*((HWND *)lParam) = hwnd;
		return FALSE;
	}
	else
		return TRUE;
}

ちなみに、textareaタグの中身はinnertextでとることができるのですが、inputタグはそれでは中身は見れません。
次のようにinput型のエレメントであることを指定してから、get_valueで取得する必要があります。面倒ですね

	bstrIdTitle = SysAllocString(L"title");
	pDocument3->getElementById(bstrIdTitle, &pElementTitle);

	pElementTitle->QueryInterface(IID_PPV_ARGS(&pInputElement));
	pInputElement->get_value(&bstrText);

◆参考
http://eternalwindows.jp/browser/mshtml/mshtml05.html