0

ソースコードがなく、それを開発した会社が存在しない、古いカスタムビルドの ERP アプリケーションを使用している顧客がいます。アプリケーションは 2000 年に開発され、Delphi で構築されています。最後の実行可能ファイルは 2003 年のものなので、D6 または D7 である可能性があります。

ある重要なフォームには、顧客が他のデータベースからの追加データを表示したいフィールドがいくつかあり、既存のフォームにデータを「ダクトテープ」することが可能かどうか尋ねられました。

私が最初に思いついたのは、次のようなアプリケーションを構築することです。

  • Windows ターゲット アプリケーションのリストを参照して、フォーム上のコントロールを作成および検索します
  • 対象のフォームが表示されたときに通知を受け取る「何らかの」イベントをアタッチする
  • ターゲットフォームのフィールドが変更されたときに通知を受け取る「何らかの」イベントを添付する
  • ターゲット フォームに重ねて小さなウィンドウに追加情報を表示する

このようなことを行う方法の例はありますか。この質問のタイトルのバリエーションでグーグルを検索しましたが、成功しませんでした。

注 - ERP アプリケーションの書き換えは予定されていません。

言語について - C# や Delphi でできます。

4

1 に答える 1

4

私は Delphi やそのライブラリを知らないので、純粋に C と Win32 の観点からこれに答えるつもりです。これを C# に変換するには p/invoke を使用しますが、一部の部分はアンマネージする必要がある場合があります。

まず、保証はありません。ターゲット アプリケーションがウィンドウなしのコントロールを実行している場合 (HWNDすべてのオンスクリーン コントロールの下に がない場合)、ほとんど運がありません。これはそれほど珍しいことではありません。

ステップ 1、ターゲット プロセスによって作成された新しいウィンドウをリッスンするウィンドウ フックを登録します*:

//dllHMod is an HMODULE that refers to the DLL containing ShellHookProc
HHOOK hook = SetWindowsHookEx(WH_SHELL, ShellHookProc, dllHMod, 0);
// error handling, stashing hook away for unregistering later, etc...

LRESULT CALLBACK ShellHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
  if(nCode < 0) return CallNextHookEx(NULL, nCode, wParam, lParam);

  if(nCode == HSHELL_WINDOWCREATED)
  {
    WindowCreate((HWND)wParam);
  }

  return 0;
}

WindowCreated(HWND)GetWindowThreadProcessId正しいプロセス (で決定) がそれを所有している場合、HWND を隠しておく必要があります。この時点で、ターゲット プロセスが所有するすべてのトップレベル ウィンドウを取得できます。グローバルフックを登録すると、パフォーマンスが大幅に低下することに注意してください。実際には問題ではありませんが、予想する必要があります。

さて、楽しい部分です。ウィンドウがいつ完全に構築されたか、いつレンダリングが完了したかを知る信頼できる方法はありません (いつレンダリングを開始するかを知る方法はありますが、それは実際には役に立ちません)。私のアドバイス、推測します。そこに任意の待機を投げてから、すべての子ウィンドウを列挙してみてください。

子ウィンドウを列挙するには (ターゲット ウィンドウについて十分に知っている場合は、これを行うためのより良い方法があります。ただし、検索が最も簡単であると想定しています)。

//targetHWND is an HWND of one of the top-level windows you've found
EnumChildWindows(targetHWND, ChildWindowCallback, NULL);
//more code...

BOOL ChildWindowCallback(HWND window, LPARAM ignored)
{
  if(IsTargetWindow(window)) { /* Do something */ }

  return TRUE;
}

実装IsTargetWindowは、もう 1 つのトリッキーな部分です。そうするための信頼できるテストが見つかることを願っています (クラス名、ウィンドウ名、スタイルなどをチェックするなど。 を参照してくださいGetWindowInfo)。

監視したいウィンドウを取得したら、 と を使用して、ウィンドウが受信するすべてのメッセージを監視できSetWindowLongPtrますGWLP_WNDPROC。これにはコード インジェクション (したがってアンマネージ コード) が必要であり、非常に低レベルです。あなたがそれを避けることができるなら、私はそれに反対することをお勧めしますが、ソースがありません...

この回答は適切な出発点だと思いますが、これが可能であったとしても、これは信じられないほど苦痛になるでしょう。幸運を。

*または、ターゲット アプリが起動時 (または検出可能/予測可能な時点) 以外にウィンドウを作成しないことがわかっている場合は、EnumWindows.

于 2010-01-02T19:19:56.260 に答える