私はC++/CLIインターフェイスを介してMS UIA(COM)を使用していますが、C#アプリケーションはそのC++/CLIインターフェイスを使用しています(uiacppとしてこのインターフェイス/ dllを呼び出しましょう)COM UIAイベントは登録解除後にのみ呼び出されます
私はほとんど私が直面してる問題は、私は同じイベント(同じ毎回/異なるイベントの登録を解除した後、UIAに私が登録したイベントハンドラがのみ呼び出され、あるhttps://msdn.microsoft.com/en-us/library/windows/desktop/ff625914(v=vs.85).aspx
の例を以下uiacpp機構を扱うイベントを作成しました/イベントタイプ&テスト)。イベントを登録すると、イベントクラスのQueryInterfaceメソッドがUIAから2回呼び出されることがわかります。そのため、UIAは何かを実行します。それから私はテストでイベントを起こしますが、何も起こりません。そして、QueryInterfaceが2回以上呼び出されたイベントの登録を解除すると、イベントハンドラが呼び出されます。次に、UIAによってクリーンアップされた残りの参照(この時点で約6つ以上)が解放メソッドに呼び出されます。
C++/CLIクラス:
class CppUIAutomationEventHandler :
public ::IUIAutomationEventHandler
{
private:
LONG _refCount;
public:
int _eventCount;
gcroot<UIAMan::IUIAutomationEventHandler^> myHandler;
static std::list<IUIAutomationEventHandler*> *EventRegister;
// Constructor.
CppUIAutomationEventHandler() : _refCount(1), _eventCount(0)
{
}
// Constructor.
CppUIAutomationEventHandler(
UIAMan::IUIAutomationEventHandler^ aHandler)
: _refCount(1)
, _eventCount(0)
, myHandler(aHandler)
{
}
// IUnknown methods.
ULONG STDMETHODCALLTYPE AddRef()
{
ULONG ret = InterlockedIncrement(&_refCount);
return ret;
}
ULONG STDMETHODCALLTYPE Release()
{
ULONG ret = InterlockedDecrement(&_refCount);
if (ret == 0)
{
delete this;
return 0;
}
return ret;
}
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppInterface)
{
if (riid == __uuidof(IUnknown) || riid == __uuidof(IUIAutomationEventHandler))
*ppInterface = static_cast<IUIAutomationEventHandler*>(this);
else
{
*ppInterface = NULL;
return E_NOINTERFACE;
}
this->AddRef();
return S_OK;
}
// IUIAutomationEventHandler methods
HRESULT STDMETHODCALLTYPE HandleAutomationEvent(::IUIAutomationElement * pSender, EVENTID eventID)
{
_eventCount++;
myHandler->HandleAutomationEvent(gcnew CUIAutomationElement(pSender, false), eventID);
return S_OK;
}
};
、ここでC#は、最後のコードを使用して(イベントを登録するために呼び出すREF(マネージC++)クラスメソッドである。ここ
コードです最後に):
void CUIAutomation::AddAutomationEventHandler(
int eventId
, IUIAutomationElement^ element
, TreeScope scope
, IUIAutomationCacheRequest^ cacheRequest
, IUIAutomationEventHandler^ handler)
{
::IUIAutomationElement* el = safe_cast<CUIAutomationElement^>(element)->getElement();
::IUIAutomationEventHandler* _handler = new CppUIAutomationEventHandler(handler);
LastHResult = puia->AddAutomationEventHandler(
eventId
, el
, (::TreeScope)(int)scope
, (cacheRequest != nullptr) ? ((CUIAutomationCacheRequest^)cacheRequest)->getElement() : NULL
, _handler);
CppUIAutomationEventHandler::EventRegister->push_back(_handler);
};
私はハンドラのリストを使用してそれらの登録を解除しています。
CUIAutomation::CUIAutomation()
{
CoInitializeEx(NULL, COINIT_MULTITHREADED);
::IUIAutomation* _puia;
HRESULT hr = CoCreateInstance(CLSID_CUIAutomation, NULL,
CLSCTX_INPROC_SERVER, IID_IUIAutomation,
(void**)&_puia);
if (SUCCEEDED(hr))
puia = _puia;
}
そして最後に、これはC#の呼び出しです:uiacppを使用して
automationhandlerクラスの実装:
class AutomationHandler : IUIAutomationEventHandler
{
public AutomationHandler()
{
}
public void HandleAutomationEvent(IUIAutomationElement sender, int eventId)
{
Console.WriteLine("IUIAutomationEventHandler called");
}
}
とC#のレジスタ/またによって作成されたCOMポインタをされプイア登録解除ライン:
var aHandler = new AutomationHandler();
uia.AddAutomationEventHandler(UIA_EventIds.UIA_Window_WindowOpenedEventId, uia.GetRootElement(), TreeScope.TreeScope_Subtree, null, aHandler);
// for debugging
bool loop = true;
while(loop)
{
Thread.Sleep(500);
}
uia.RemoveAutomationEventHandler(UIA_EventIds.UIA_Window_WindowOpenedEventId, uia.GetRootElement(), aHandler);
[System.Windows.Automation]の[AutomationEventHandler'](https://msdn.microsoft.com/en-us/library/system.windows.automationeventhandler.aspx)を使用していないのはなぜですか? https://msdn.microsoft.com/en-us/library/system.windows.automation.aspx)? –
これは、pinvokeまたはtlbimpを使用してC#用に作成されたインターフェイスを最初に作成することを意味するためです。そして、そのアプローチでCOM呼び出しの詳細を監視することはできません。代わりにC++で独自のカスタム作成インターフェイスを使用しています。さらに、C#用のこれらの自動インターフェイスを使用すると安定性が低下するようですが、追加することはできますが、まだ証明できません。それが理由です。 – MattAPiroglu
* System.Windows.Automation *は既に管理されており、C#から使用する必要のあるP/Invokeまたはtlbimpはありません。 –