質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.92%

C++ で起動済みの IE の URL を列挙するソースについての疑問点

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 234

busyoda

score 52

以下サイトを参考に、後述のプログラムを作成しました。
https://www.usefullcode.net/2006/12/ieihtmldocument2.html

プログラムは正常に動作しているのですが、
後続の疑問点が解消できない為、
ご存じの方がおりましたら、ご回答をお願いいたします。

言語:C++
環境:Windows10 64bit / Visual Studio 2019

作成したプログラム

#include <atlstr.h>
#include <exdisp.h>
#include <mshtml.h>

bool GetHTMLDocument2FromHWND(HWND hWnd, IHTMLDocument2** ppIHTMLDocument2, bool bHwndIsServer = true)
{
    HINSTANCE    hInst;
    LRESULT        lRes;
    UINT        nMsg;
    LRESULT        ret;

    LPFNOBJECTFROMLRESULT pfObjectFromLresult;

    if (ppIHTMLDocument2 == NULL || hWnd == NULL || IsWindow(hWnd) == FALSE)
        return false;

    if (bHwndIsServer == false)
    {
        hWnd = FindWindowEx(hWnd, NULL, _T("Internet Explorer_Server"), NULL);
        if (hWnd == NULL)
            return    false;
    }

    hInst = LoadLibrary(_T("OLEACC.DLL"));
    if (hInst == NULL)
        return    false;

    nMsg = RegisterWindowMessage(_T("WM_HTML_GETOBJECT"));
    ret = SendMessageTimeout(hWnd, nMsg, 0, 0, SMTO_ABORTIFHUNG, 1000, (DWORD*)&lRes);
    if (ret == 0)
        return    false;

    pfObjectFromLresult = (LPFNOBJECTFROMLRESULT)GetProcAddress(hInst, "ObjectFromLresult");
    if (pfObjectFromLresult)
        (*pfObjectFromLresult)(lRes, IID_IHTMLDocument2, 0, (void**)ppIHTMLDocument2);

    FreeLibrary(hInst);

    return *ppIHTMLDocument2 ? true : false;
}

class CDnpEnumInternetExplore
{
    //    EnumWindowsのコールバック関数
    static BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
    {
        int        nRet;
        TCHAR    pszName[1024];

        nRet = GetClassName(hwnd, pszName, sizeof(pszName));
        if (nRet == 0)
            return TRUE;

        nRet = _tcscmp(pszName, _T("IEFrame"));
        if (nRet != 0)
            return TRUE;

        EnumChildWindows(hwnd, EnumChildProc, (LPARAM)NULL);

        return TRUE;
    }

    //    EnumChildWindowsのコールバック関数
    static BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM lParam)
    {
        int        nRet;
        bool    ret;
        HRESULT    hr;
        BSTR    bstrURL;
        TCHAR    pszName[1024];
        IHTMLDocument2* pIHTMLDocument2;

        nRet = GetClassName(hwnd, pszName, sizeof(pszName));
        if (nRet == 0)
            return TRUE;

        nRet = _tcscmp(pszName, _T("Internet Explorer_Server"));
        if (nRet != 0)
            return TRUE;

        pIHTMLDocument2 = NULL;
        ret = GetHTMLDocument2FromHWND(hwnd, &pIHTMLDocument2);
        if (ret == false || pIHTMLDocument2 == NULL)
            return TRUE;

        bstrURL = NULL;
        hr = pIHTMLDocument2->get_URL(&bstrURL);
        if (SUCCEEDED(hr))
        {
            CAtlString    strURL;

            strURL = (WCHAR*)bstrURL;
            SysFreeString(bstrURL);

            printf("%ws\n", strURL);
        }

        pIHTMLDocument2->Release();

        return    TRUE;
    }

public:
    void EnumStart()
    {
        BOOL ret;
        ret = EnumWindows(EnumWindowsProc, (LPARAM)NULL);
    }
};

void main()
{
    CoInitialize(NULL);

    CDnpEnumInternetExplore    cEnum;

    cEnum.EnumStart();

    CoUninitialize();
}

疑問点その1

ObjectFromLresult を LoadLibrary(_T"OLEACC.DLL") を用いて使用している点について疑問に思いました。
ObjectFromLresult は oleacc.h で宣言されています。
なので、#include <oleacc.h> からでも利用できるのでは?と思い、実際にやってみました。

修正後のプログラム(GetHTMLDocument2FromHWND のみ)

#include <oleacc.h>

bool GetHTMLDocument2FromHWND(HWND hWnd, IHTMLDocument2** ppIHTMLDocument2, bool bHwndIsServer = true)
{
    LRESULT        lRes;
    UINT        nMsg;
    LRESULT        ret;

    if (ppIHTMLDocument2 == NULL || hWnd == NULL || IsWindow(hWnd) == FALSE)
        return false;

    if (bHwndIsServer == false)
    {
        //"Shell DocObject View"へのハンドルとして処理
        hWnd = FindWindowEx(hWnd, NULL, _T("Internet Explorer_Server"), NULL);
        if (hWnd == NULL)
            return    false;
    }

    nMsg = RegisterWindowMessage(_T("WM_HTML_GETOBJECT"));
    ret = SendMessageTimeout(hWnd, nMsg, 0, 0, SMTO_ABORTIFHUNG, 1000, (DWORD*)&lRes);
    if (ret == 0)
        return    false;

    HRESULT hRes;
    hRes = ObjectFromLresult(lRes, IID_IHTMLDocument2, 0, (void**)ppIHTMLDocument2);

    return *ppIHTMLDocument2 ? true : false;
}


この場合、下記2つのエラーが発生します。

LNK2019    未解決の外部シンボル _ObjectFromLresult@16 が関数 "bool cdecl GetHTMLDocument2FromHWND(struct HWND *,struct IHTMLDocument2 * *,bool)" (?GetHTMLDocument2FromHWND@@YA_NPAUHWND__@@PAPAUIHTMLDocument2@@_N@Z) で参照されました
LNK1120    1 件の未解決の外部参照

未解決の外部シンボルとのことだったので、
oleacc.h で extern "C" の記載がないのかと思いましたが、
確認した所、extern "C" は記載されていました。

C++ は不慣れなもので、根本的に使い方が間違っている可能性も否めませんが、
oleacc.h のインクルードでなく、動的に oleacc.dll を利用しているのは理由があるのでしょうか。

また、oleacc.h から該当の関数を使用する場合はどの様にコーディングしたらよいのでしょうか。

疑問点その2

LPFNOBJECTFROMLRESULT についてですが、
こちらは oleacc.h で宣言されています。

何故、oleacc.h をインクルードせずに利用できるのでしょうか。

疑問点その3

参考にしたサイトのソースでは、
EnumWindows から EnumWindowsProc_ を呼び出し、
EnumWindowsProc_ から EnumWindowsProc を呼び出していました。

個人的に、EnumWindows から EnumWindowsProc を呼び出せばよいのでは?と考え、
上述のソースコードにしたのですが、
一度 EnumWindowsProc_ を経由するのには理由があるのでしょうか。

明確な理由は作った本人にしか分からないかもしれませんが、
何かしら思い当たる点がございましたらご教示下さい。

疑問点その4

参考にしたサイトのソースでは、
::IsWindow の様に、グローバル名前空間からの解決を明示していました。

上記ソースでは衝突も起こらない為、個人的に要らないかなと考えて省略しましたが、
明示した方がよいのでしょうか。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

  • 疑問点その1

LNK2019    未解決の外部シンボル _ObjectFromLresult@16 が関数 "bool cdecl GetHTMLDocument2FromHWND(struct HWND *,struct IHTMLDocument2 * *,bool)" (?GetHTMLDocument2FromHWND@@YA_NPAUHWND__@@PAPAUIHTMLDocument2@@_N@Z) で参照されました

oleacc.libをリンクしていないから。
ObjectFromLresult function
Library    Oleacc.lib

  • 疑問点その2

何故、oleacc.h をインクルードせずに利用できるのでしょうか。

atlstr.hをインクルードするとその先でインクルードされているため。

  • 疑問点その3

一度 EnumWindowsProc_ を経由するのには理由があるのでしょうか。

staticではないメンバ関数を呼ぶためにはthisポインタがいるため。
リンク先の例ではクラスのメンバ変数等を使用していないのでstaticメンバ関数のみでも実現は可能ですが…

  • 疑問点その4
    好みによるでしょう。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/07/13 14:12

    ご回答ありがとうございました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.92%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る