山本ワールド
Windowsプログラミング
アルゴリズム Vitual C++ 2008/2013によるWin32/Win64 APIレベルのプログラム 基礎 Vitual C++ 2008/2013によるAPIレベルのプログラム(32/64bit) Wix3でインストーラーを作る Visual C++ 2008 Standard Editonによるフォームアプリケーションのプログラム(32/64bit) Vitual C++ 2008 Standard EditonによるAPIレベルのプログラム(32/64bit) Windows 7対応 Visual C++ 2008 ExpressによるAPIレベルのプログラム Visual C++ 2005 ExpressによるAPIレベルのプログラム Visual C++ Versiosn 5 BORLAND C++ Windowsプログラム全般 Excel VBA その他MSHTMLを使用して特定のidのaタグを取得(32/64bit)
概要
MSHTMLを使用してidがid5のエレメントを取得しそのエレメントのaタグのリンク等を取得しエディットボックスに表示します。
MSHTMLとは、インターネットエクスプローラーのhtmlファイルを解析するためのモジュールです。
ここでは、http://yamatyuu.net/computer/program/vc2013/htmlget3/htmlget3.htmlを呼び出しています。
ダイアログボックスはマウスによるサイズの変更に対応しています。
マウスによるサイズ変更をする必要がない場合は、htmlget3.cppの#define SIZE_CHG 1をコメントアウトし、resource.rcの| WS_THICKFRAMEを削除します。
使い方は、プログラムを起動し読み込みをクリックするとソースが表示されます。
テスト環境
コンパイラ
Visual C++ 2008/2013 Express 32/64bit UNICODE実行環境
Windows XP Professional Service Pack 3 32bit(Virtual Box上の仮想マシーン)Windows 7 Enterprise Service Pack 1 64bit
プログラムソースの概要
htmlget3.cpp
WinMain
CoInitialize APIによりCOMを初期化後、ダイアログボックスを呼び出します。ダイアログボックスが終了したらCoUninitialize APIによりCOMを解放します。
DlgProc
WM_INITDIALOG
ダイアログボックスの初期化時に呼び出されます。ダイアログボックスのサイズの変更に備えて各種コモンコントロールの位置や大きさを取得します。
WM_SIZE
ダイアログボックスの大きさが変更された時に呼び出されます。ダイアログボックスの大きさに合わせて、ボタンはダイアログボックスの高さにあわせて移動させます。
エディットボックスは、ダイアログボックスの大きさに合わせてサイズを変化させます。
WM_COMMAND
IDC_READ_BUTTON
読み込みボタンがクリックされた時に呼び出されます。カーソルを処理中に変更し、htmlRead関数を呼び出しエディットボックスにソースを表示させ、関数から戻ったときにカーソルを元に戻します。
IDCANCEL
キャンセルボタンがクリックされた時に呼び出されます。EndDialog APIによりダイアログボックスを終了させます。
htmlRead
URLを読み込む元になるオブジェクトの作成
MSHTML::IHTMLDocument4Pt doc4pをCreateInstanceメンバー関数により初期化します。指定したURLを呼び出すcreateDocumentFromUrlメンバー関数は、元になるオブジェクトが必要なため、<html></html>という内容を含んだSAFEARRAY型を作成し、writeメンバー関数によりIHTMLDocument2インターフェースに書き込みcloseメンバー関数により書き込みを終了させます。
URLの読み込み
元になるオブジェクトを元にcreateDocumentFromUrlメンバー関数を読み出し、MSHTML::IHTMLDocument2Ptr doc2pに保存します。createDocumentFromUrlメンバー関数は読み込みが終了する前に呼び出し元に戻るので、MSHTML::IHTMLDocument2Ptr doc2p->readyState != cmpで読み込み終了をチェックしています。COMをSTAで初期化したので、PeekMessage~DispatchMessageによりメッセージループを設けてあげないとCOMと本プログラム間でメッセージが届かないのでプログラムが正常に動作しません。
IDからタグを取得
doc2pからMSHTML::IHTMLDocument3Ptr doc3へキャストします。MSHTML::IHTMLDocument3Ptr getElementByIdによりdoc3からid名がid5のエレメントを取得しHTML::IHTMLElementPtr elementに保存します。
aタグの取得
IHTMLDocument3Ptr elementp->QueryInterfaceによりMSHTML::IHTMLAnchorElementPtr インターフェースを取得しpAnchorElementに保存します。 ElementPut関数を呼び出しname,href等をbufに取得します。bufをエディットボックスに表示します。
作成された、doc4p,doc2p,elementpを0を代入することにより解放されます。解放しないとエラーが発生して正常に動作しません。
なお、MSHTMLとは、#importでmshtml.tlbを読み込むときに変更した名前であり、import.hの中で定義しています。ほかの人ではHTMLとかに定義している人もいます。気に入らなければ変更することができます。
MSHTML::IHTMLDocument2Ptr、MSHTML::IHTMLDocument3Ptr、MSHTML::IHTMLDocument4Ptrはメンバーが異なるのみでキャストすれば自由に使い分けできます。たとえばwriteメンバー関数を呼び出すためにMSHTML::IHTMLDocument4PtrをMSHTML::IHTMLDocument2Ptrにキャストしています。
ソースに出てくるBSTR型、VARIANT型、SAFEARRAY型はCOMでよく使われるものです。
ElementPut
MSHTML::IHTMLAnchorElementPtrのnameメンバよりname属性を取得します。MSHTML::IHTMLAnchorElementPtrのhrefメンバよリンク先を取得します。
MSHTML::IHTMLAnchorElementPtrのtargetメンバよりtarget属性を取得します。
MSHTML::IHTMLAnchorElementPtrのhostnameメンバよりリンク先のホスト名を取得します。
MSHTML::IHTMLAnchorElementPtrをMSHTML::IHTMLElementPtrへキャストして変換します。
MSHTML::IHTMLElementPtrのouterHTMLにより<a href ~ </a>全部を取得します。
MSHTML::IHTMLElementPtrよりinnerHTMLによりaタグに囲まれた中身を取得します。
取得されたname,href等をbufに保存します。 各属性を保存するために動的に割り付けたメモリをfreeで開放します。
ソースコード
htmlget3.cpp
// htmlget3.htmlを読み込み特定のIDのAタグを解析してエディットボックスに表示する
// getElementByIdでIDのエレメントを抽出、QueryInterfaceを使用してIHTMLAnchorElementに変換
#include <windows.h>
#include <tchar.h>
#include <docobj.h>
#include <commctrl.h>
#define SIZE_CHG 1 // ダイアログボックスの大きさを変更した場合に各コントロールの大きさ位置を変更させる場合に定義してください
#include "resource.h"
#include "import.h"
#pragma comment(lib,"comctl32.lib")
using namespace std;
// ダイアログボックスプロシージャー
LRESULT CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst,LPSTR lpsCmdLine, int nCmdShow){
InitCommonControls();
if( FAILED( CoInitialize(NULL) )){ // COMの初期化 STA(シングルスレッドアパートメント)
MessageBox(0,_TEXT("COMの初期化に失敗しました"),_TEXT("エラー"),MB_OK);
return -1;
}
// ダイアログボックスの表示
DialogBox(hCurInst, TEXT("DLG1"), 0, (DLGPROC)DlgProc);
CoUninitialize(); // COMの解放
return (int)0;
}
// Htmlファイルを読み込みエディットコントロールにbodyタグに含まれるソースを張り付ける
void htmlRead(TCHAR* url,HWND hEdit);
// ダイアログボックスプロシージャー
LRESULT CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam){
static HWND hEdit;
#ifdef SIZE_CHG // ダイアログボックスの大きさを変更した場合に各コントロールの大きさ位置を変更させる場合に必要
static HWND hCANCLE,hBUTTON102;
static int hEditx,hEdity,hEditWidth,hEditHeight;
static int hCANCLEx,hCANCLEy,hCANCLEWidth,hCANCLEHeight;
static int hBUTTON102x,hBUTTON102y,hBUTTON102Width,hBUTTON102Height;
RECT hDlgrect;
RECT rect;
POINT point;
#endif
static HCURSOR wait_icon=0;
static HCURSOR org_icon=0;
switch (msg) {
case WM_INITDIALOG:{
wait_icon=LoadCursor(NULL,IDC_WAIT); // 処理中アイコンの取得
hEdit=GetDlgItem(hDlg,IDC_EDIT);
#ifdef SIZE_CHG // ダイアログボックスの大きさを変更した場合に各コントロールの大きさ位置を変更させる場合に必要
hCANCLE=GetDlgItem(hDlg,IDCANCEL);
hBUTTON102=GetDlgItem(hDlg,IDC_READ_BUTTON);
// ダイアログボックスクライアント領域の大きさを取得
GetClientRect(hDlg,&hDlgrect);
int width=hDlgrect.right;
int height=hDlgrect.bottom;
GetWindowRect(hDlg,&hDlgrect);
// エディットボックスのダイアログボックスのクライアント座標・大きさとダイアログボックスの大きさの差を取得
GetWindowRect(hEdit,&rect);
point.x=rect.left;
point.y=rect.top;
ScreenToClient(hDlg,&point);
hEditx=point.x;
hEdity=point.y;
hEditWidth=(rect.right-rect.left)-width;
hEditHeight=(rect.bottom-rect.top)-height;
// ボタンコントロールのイアログボックスのクライアント座標(ダイアログbottomを基準)・大きさを取得
GetWindowRect(hBUTTON102,&rect);
point.x=rect.left;
point.y=rect.top;
ScreenToClient(hDlg,&point);
hBUTTON102x=point.x - (width)/2;
hBUTTON102y=point.y-height;
hBUTTON102Width=(rect.right-rect.left);
hBUTTON102Height=(rect.bottom-rect.top);
GetWindowRect(hCANCLE,&rect);
point.x=rect.left;
point.y=rect.top;
ScreenToClient(hDlg,&point);
hCANCLEx= point.x -(width)/2;
hCANCLEy=point.y-height;
hCANCLEWidth=(rect.right-rect.left);
hCANCLEHeight=(rect.bottom-rect.top);
#endif
return TRUE;
}
#ifdef SIZE_CHG
case WM_SIZE:{ // ウィンドウサイズが変更された
RECT hDlgrect;
GetWindowRect(hDlg,&hDlgrect);
int width=LOWORD(lParam);
int height=HIWORD(lParam);
MoveWindow(hEdit , hEditx,hEdity, width + hEditWidth, height+hEditHeight,TRUE);
MoveWindow(hBUTTON102 , width/2+hBUTTON102x,height+hBUTTON102y, hBUTTON102Width, hBUTTON102Height,TRUE);
MoveWindow(hCANCLE , width/2+hCANCLEx,height+hCANCLEy,hCANCLEWidth, hCANCLEHeight,TRUE);
return FALSE;
}
#endif
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDC_READ_BUTTON:{
org_icon=GetCursor();
SetCursor(wait_icon);
htmlRead(_TEXT("http://yamatyuu.net/computer/program/vc2013/htmlget3/htmlget3.html"),hEdit);
SetCursor(org_icon);
return FALSE;
}
case IDCANCEL:
EndDialog(hDlg,TRUE);
return TRUE;
default:
return FALSE;
}
default:
return FALSE;
}
return TRUE;
}
// エレメントを表示
void ElementPut(MSHTML::IHTMLAnchorElementPtr e,TCHAR* buf,int sz){
TCHAR* name=_tcsdup(e->name);
TCHAR* href=_tcsdup(e->href);
TCHAR* target=_tcsdup(e->target);
TCHAR* hostname=_tcsdup(e->hostname);
TCHAR* pathname=_tcsdup(e->pathname);
MSHTML::IHTMLElementPtr elementp=(MSHTML::IHTMLElementPtr)e;
TCHAR* inner=_tcsdup(elementp->innerHTML);
TCHAR* outer=_tcsdup(elementp->outerHTML);
_stprintf_s(buf,sz,_TEXT("tag:A\r\nname:%s\r\nhref:%s\r\ntarget:%s\r\nhost:%s\r\npathname:%s\r\n%s\r\n%s\r\n"),name,href,target,hostname,pathname,inner,outer );
e=0;
free(outer);
free(inner);
free(pathname);
free(hostname);
free(target);
free(href);
free(name);
}
// Htmlファイルを読み込みエディットコントロールにbodyタグに含まれるソースを張り付ける
void htmlRead(TCHAR* urls,HWND hEdit){
MSHTML::IHTMLDocument2Ptr doc2p;
MSHTML::IHTMLDocument4Ptr doc4p;
MSHTML::IHTMLElementPtr elementp;
HRESULT hr;
// IHTMLDocument4Ptrの初期化
hr=doc4p.CreateInstance( MSHTML::CLSID_HTMLDocument );
if( FAILED(hr) ){
MessageBox(0,_TEXT("CreateInstance 失敗"),_TEXT("エラー"),MB_OK);
return;
}
// doc4に最低限のオブジェクトを作成
VARIANT* param;
SAFEARRAY* sfArray=NULL;
BSTR bstr=NULL;
bstr= ::SysAllocString(OLESTR("<html></html>"));
if(bstr==NULL){
return;
}
sfArray=::SafeArrayCreateVector(VT_VARIANT,0,1);
if(sfArray==NULL){
::SysFreeString(bstr);
return;
}
hr=::SafeArrayAccessData(sfArray,(LPVOID*)¶m);
param->vt=VT_BSTR;
param->bstrVal=bstr;
hr=::SafeArrayUnaccessData(sfArray);
hr=((MSHTML::IHTMLDocument2Ptr)doc4p)->write(sfArray);
((MSHTML::IHTMLDocument2Ptr)doc4p)->close();
// doc4を親オブジェクトとしてurlを読み込む。
BSTR url=::SysAllocString(urls);
BSTR obj=0; // 表示対象をプリンターが以外に設定
_bstr_t cmp=::SysAllocString(_TEXT("complete"));
doc2p=doc4p->createDocumentFromUrl(url,obj);
MSG msg;
unsigned n=0;
do{ // COMをSTAで初期化したため、メッセージループを設けないと読み込み完了が検出できない
if (PeekMessage(&msg, 0, 0 ,0, PM_REMOVE)){
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
++n;
Sleep(100);
}while( doc2p->readyState != cmp ); // 読み込み完了をチェック
::SysFreeString(url);
MSHTML::IHTMLElementCollectionPtr elment;
MSHTML::IHTMLDocument3Ptr doc3p=(MSHTML::IHTMLDocument3Ptr)doc2p;
BSTR bstrId = SysAllocString(_TEXT("id5"));
elementp=doc3p->getElementById(bstrId );
if(elementp == NULL){
MessageBox(0,bstrId,_TEXT("下記のIDが見つかりませんでした。"),MB_OK);
::SysFreeString(bstrId);
return;
}
MSHTML::IHTMLAnchorElementPtr pAnchorElement;
elementp->QueryInterface(IID_PPV_ARGS(&pAnchorElement));
TCHAR buf[256];
::SysFreeString(bstrId);
ElementPut(pAnchorElement,buf,sizeof(buf)/sizeof(TCHAR));
SetWindowText(hEdit, buf); // 取得したオブジェクトのソースをエディットボックスに張り付ける
::SafeArrayDestroy(sfArray); // SAFEARRAYの解放
// 作成されたオブジェクトの解放
elementp=0;
doc2p=0;
doc4p=0;
}
import.h
#pragma warning(disable:4192)
#pragma warning(disable:4278)
#import <shdocvw.dll> rename_namespace("SHDocVw") named_guids
#import <mshtml.tlb> rename_namespace("MSHTML") named_guids
#pragma warning(default:4192)
#pragma warning(default:4278)
resource.h
#define IDC_EDIT 100
#define IDC_READ_BUTTON 102
resource.rc
#include <windows.h>
#include "resource.h"
DLG1 DIALOG DISCARDABLE 0, 0, 414, 366
EXSTYLE WS_EX_DLGMODALFRAME
STYLE WS_POPUP| WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | DS_SETFONT | WS_THICKFRAME
CAPTION "IHTMLAnchorElementPtr"
FONT 9, "MS 明朝"
{
CONTROL "ソース", -11, "STATIC", WS_CHILD | WS_VISIBLE | SS_NOTIFY, 7, 7, 54, 12
CONTROL "読み込まれていません。", IDC_EDIT, "EDIT", WS_CHILD | WS_DLGFRAME | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL
| ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_MULTILINE | ES_READONLY, 7, 20, 400, 300
CONTROL "読み込み(&R)", IDC_READ_BUTTON, "BUTTON", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 146, 334, 54, 18
CONTROL "キャンセル(&C)", IDCANCEL, "BUTTON", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 214, 334, 54, 18
}
Copyright (C) 2012 山本ワールド All Rights Reserved.