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

以前に書いたプログラムは1起動で1回しか動かなかったので、今度はフォームを立ち上げているかぎりずっと動くプログラムです。

以前のプログラム

serverless.hateblo.jp

今回のプログラム

// WindowsProject1.cpp: アプリケーションのエントリ ポイントを定義します。
//

#include "stdafx.h"
#include "WindowsProject1.h"


//// MSHTML追加ここから
//#include <exdisp.h>
#include <mshtml.h>
#include <oleacc.h>

#pragma comment (lib, "oleacc.lib")
//// MSHTML追加ここまで

#define MAX_LOADSTRING 100

//// MSHTML追加ここから
class CEventHandler : public IDispatch
{
public:
	STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject);
	STDMETHODIMP_(ULONG) AddRef();
	STDMETHODIMP_(ULONG) Release();

	STDMETHODIMP GetTypeInfoCount(UINT *pctinfo);
	STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo);
	STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId);
	STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr);

	CEventHandler(IHTMLWindow2 *pWindow2, IHTMLDocument3 *pDocument3);
public:
	LONG         m_cRef;
	IHTMLWindow2 *m_pWindow2;
	IHTMLDocument3 *m_pDocument3;

};

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

//// MSHTML追加ここまで


// グローバル変数:
HINSTANCE hInst;                                // 現在のインターフェイス
WCHAR szTitle[MAX_LOADSTRING];                  // タイトル バーのテキスト
WCHAR szWindowClass[MAX_LOADSTRING];            // メイン ウィンドウ クラス名

// このコード モジュールに含まれる関数の宣言を転送します:
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // TODO: ここにコードを挿入してください。
	//// MSHTML追加ここから
	BOOL bIeOpen = false; //2回目以降はIEを読み込まないようにするためのフラグ
	IHTMLDocument3 *pDocument3;
	CoInitialize(NULL);
	BSTR           bstrIdTitle = SysAllocString(L"");
	BSTR           bstrIdButton = SysAllocString(L"");
	VARIANT        var;
	IHTMLElement   *pElementTitle = NULL;
	IHTMLElement   *pElementButton = NULL;
	IHTMLDocument2 *pDocument2 = NULL;
	IHTMLWindow2   *pWindow2 = NULL;
	IHTMLInputElement  *pInputElement = NULL;
	//// MSHTML追加ここまで


    // グローバル文字列を初期化しています。
    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadStringW(hInstance, IDC_WINDOWSPROJECT1, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    // アプリケーションの初期化を実行します:
    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }

    HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WINDOWSPROJECT1));

    MSG msg;

    // メイン メッセージ ループ:
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
		//// MSHTML追加ここから
		if (!bIeOpen) {
			if (GetDocumentFromIE(&pDocument3)){
				bIeOpen = true;
				bstrIdTitle = SysAllocString(L"title");
				pDocument3->getElementById(bstrIdTitle, &pElementTitle);
				if (pElementTitle == NULL) {
					SysFreeString(bstrIdTitle);
					return FALSE;
				}
				pElementTitle->QueryInterface(IID_PPV_ARGS(&pInputElement));

				bstrIdTitle = SysAllocString(L"button");
				pDocument3->getElementById(bstrIdTitle, &pElementButton);
				if (pElementButton == NULL) {
					SysFreeString(bstrIdButton);
					return FALSE;
				}

				pDocument3->QueryInterface(IID_PPV_ARGS(&pDocument2));
				pDocument2->get_parentWindow(&pWindow2);

				var.vt = VT_DISPATCH;
				var.pdispVal = new CEventHandler(pWindow2,pDocument3);
				pElementButton->put_onclick(var);
				pInputElement->put_onchange(var);

			}
		}
		//// MSHTML追加ここまで
    }

	//// MSHTML追加ここから
	SysFreeString(bstrIdButton);
	SysFreeString(bstrIdTitle);
	var.pdispVal->Release();
	pWindow2->Release();
	pDocument2->Release();
	pElementButton->Release();
	pElementTitle->Release();
	pInputElement->Release();
	CoUninitialize();
	//// MSHTML追加ここまで


    return (int) msg.wParam;
}

//// MSHTML追加ここから

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;
}

CEventHandler::CEventHandler(IHTMLWindow2 *pWindow2, IHTMLDocument3 *pDocument3)
{
	m_cRef = 1;
	m_pWindow2 = pWindow2;
	m_pDocument3 = pDocument3;
}

STDMETHODIMP CEventHandler::QueryInterface(REFIID riid, void **ppvObject)
{
	*ppvObject = NULL;

	if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IDispatch))
		*ppvObject = static_cast<IDispatch *>(this);
	else
		return E_NOINTERFACE;

	AddRef();

	return S_OK;
}

STDMETHODIMP_(ULONG) CEventHandler::AddRef()
{
	return InterlockedIncrement(&m_cRef);
}

STDMETHODIMP_(ULONG) CEventHandler::Release()
{
	if (InterlockedDecrement(&m_cRef) == 0) {
		delete this;
		return 0;
	}

	return m_cRef;
}

STDMETHODIMP CEventHandler::GetTypeInfoCount(UINT *pctinfo)
{
	*pctinfo = 0;

	return S_OK;
}

STDMETHODIMP CEventHandler::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
{
	return E_NOTIMPL;
}

STDMETHODIMP CEventHandler::GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
{
	return E_NOTIMPL;
}

STDMETHODIMP CEventHandler::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
{
	BSTR          bstr,bstrValue,bstrContents,bstrIdContents;
	IHTMLEventObj *pEventObj;
	IHTMLElement  *pElement;
	IHTMLInputElement  *pInputElement;
	IHTMLElement       *pElementContents;

	m_pWindow2->get_event(&pEventObj);
	pEventObj->get_srcElement(&pElement);
	//pElement->get_tagName(&bstr);
	pElement->get_id(&bstr);

	char szElement[255] = "";
	char szTargetButton[255] = "button";
	char szTargetTitle[255] = "title";
	char szTargetTitleApp[255] = "申請";
	char *adrCompResult;

	bstrIdContents = SysAllocString(L"contents");
	m_pDocument3->getElementById(bstrIdContents, &pElementContents);

	WideCharToMultiByte(CP_ACP,0,(OLECHAR*)bstr,-1,szElement,sizeof(szElement) - 1,NULL,NULL);

	adrCompResult = strstr(szElement, szTargetButton);
	if (adrCompResult != NULL) {
		MessageBoxW(NULL, bstr, L"ボタンが押されました。", MB_OK);
	}
	adrCompResult = strstr(szElement, szTargetTitle);
	if (adrCompResult != NULL) {
		pElement->QueryInterface(IID_PPV_ARGS(&pInputElement));
		pInputElement->get_value(&bstrValue);
		WideCharToMultiByte(CP_ACP, 0, (OLECHAR*)bstrValue, -1, szElement, sizeof(szElement) - 1, NULL, NULL);
		adrCompResult = strstr(szElement, szTargetTitleApp);
		if (adrCompResult != NULL) {
			MessageBoxW(NULL, L"〇〇申請のフォーマットを適用しますか?", L"フォーマット適用確認", MB_OK);
			bstrContents = SysAllocString(L"1. 会社名\n\n2.金額\n\n3.実施日");
			pElementContents->put_innerText(bstrContents);
		}
	}
	SysFreeString(bstr);
	pElement->Release();
	pEventObj->Release();

	return S_OK;
}

//// MSHTML追加ここまで



//
//  関数: MyRegisterClass()
//
//  目的: ウィンドウ クラスを登録します。
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEXW wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WINDOWSPROJECT1));
    wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_WINDOWSPROJECT1);
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

    return RegisterClassExW(&wcex);
}

//
//   関数: InitInstance(HINSTANCE, int)
//
//   目的: インスタンス ハンドルを保存して、メイン ウィンドウを作成します。
//
//   コメント:
//
//        この関数で、グローバル変数でインスタンス ハンドルを保存し、
//        メイン プログラム ウィンドウを作成および表示します。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   hInst = hInstance; // グローバル変数にインスタンス処理を格納します。

   HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);

   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

//
//  関数: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  目的:    メイン ウィンドウのメッセージを処理します。
//
//  WM_COMMAND  - アプリケーション メニューの処理
//  WM_PAINT    - メイン ウィンドウの描画
//  WM_DESTROY  - 中止メッセージを表示して戻る
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_COMMAND:
        {
            int wmId = LOWORD(wParam);
            // 選択されたメニューの解析:
            switch (wmId)
            {
            case IDM_ABOUT:
                DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
                break;
            case IDM_EXIT:
                DestroyWindow(hWnd);
                break;
            default:
                return DefWindowProc(hWnd, message, wParam, lParam);
            }
        }
        break;
    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            // TODO: HDC を使用する描画コードをここに追加してください...
            EndPaint(hWnd, &ps);
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

// バージョン情報ボックスのメッセージ ハンドラーです。
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    UNREFERENCED_PARAMETER(lParam);
    switch (message)
    {
    case WM_INITDIALOG:
        return (INT_PTR)TRUE;

    case WM_COMMAND:
        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
        {
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        break;
    }
    return (INT_PTR)FALSE;
}