You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在MFC应用中实现IServiceProvider接口的技术咨询

Hey there! Let's walk through how to implement IServiceProvider for your MFC TTSApp to support IAccessibleApplication—without relying on ATL's CComObjectRootEx.

The Best Class to Inherit: Your CWinApp-Derived Class

First off, the application-level class (your CWinApp subclass) is the right place to implement these interfaces. Here's why:

  • IAccessibleApplication is designed to expose metadata (app name, version) for the entire application, not just a single window/dialog.
  • Screen readers typically traverse the UI automation tree up to the application root object to request this service, which aligns perfectly with the lifecycle and scope of your CWinApp instance.
  • A CDialogEx subclass would only provide this service when that specific dialog is in focus, which doesn't meet the requirement of exposing app-wide info.

Step-by-Step Implementation

Since you're avoiding ATL's COM root classes, we'll manually implement the COM interfaces while leveraging MFC's existing CCmdTarget base (which CWinApp already inherits from).

1. Update Your App Class Header

Modify your CTTSApp class to inherit from both IServiceProvider and IAccessibleApplication, and declare the required methods:

#include <oleacc.h>
#include <objbase.h>

class CTTSApp : public CWinApp, public IServiceProvider, public IAccessibleApplication
{
protected:
    LONG m_cRef; // COM reference count

public:
    CTTSApp();

    // MFC overrides
    virtual BOOL InitInstance();
    virtual int ExitInstance();

    // IUnknown methods
    STDMETHOD_(ULONG, AddRef)();
    STDMETHOD_(ULONG, Release)();
    STDMETHOD(QueryInterface)(REFIID riid, void** ppvObject);

    // IServiceProvider method
    STDMETHOD(QueryService)(REFGUID guidService, REFIID riid, void** ppvObject);

    // IAccessibleApplication methods
    STDMETHOD(get_ApplicationName)(BSTR* pbstrName);
    STDMETHOD(get_ApplicationVersion)(BSTR* pbstrVersion);

    // MFC interface map (for optional COM integration)
    DECLARE_INTERFACE_MAP()
};

2. Implement the Interface Methods in Your .cpp File

Start with initializing the reference count, then implement each COM method:

Reference Count & IUnknown Methods

CTTSApp::CTTSApp() : m_cRef(0) {}

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

STDMETHODIMP_(ULONG) CTTSApp::Release()
{
    // Note: MFC manages the CWinApp instance globally, so we don't delete it here
    return InterlockedDecrement(&m_cRef);
}

STDMETHODIMP CTTSApp::QueryInterface(REFIID riid, void** ppvObject)
{
    if (!ppvObject) return E_POINTER;
    *ppvObject = nullptr;

    // Map requested IIDs to our interfaces
    if (riid == IID_IUnknown)
        *ppvObject = static_cast<IUnknown*>(this);
    else if (riid == IID_IServiceProvider)
        *ppvObject = static_cast<IServiceProvider*>(this);
    else if (riid == IID_IAccessibleApplication)
        *ppvObject = static_cast<IAccessibleApplication*>(this);
    else
        return E_NOINTERFACE;

    AddRef();
    return S_OK;
}

IServiceProvider's QueryService

This method is where we expose the IAccessibleApplication service to screen readers:

STDMETHODIMP CTTSApp::QueryService(REFGUID guidService, REFIID riid, void** ppvObject)
{
    if (!ppvObject) return E_POINTER;
    *ppvObject = nullptr;

    // Check if the requested service is IAccessibleApplication
    if (guidService == __uuidof(IAccessibleApplication))
    {
        return QueryInterface(riid, ppvObject);
    }

    return E_NOINTERFACE;
}

IAccessibleApplication Methods

Return your app's name and version here:

STDMETHODIMP CTTSApp::get_ApplicationName(BSTR* pbstrName)
{
    if (!pbstrName) return E_POINTER;
    *pbstrName = SysAllocString(L"TTSApp"); // Replace with your actual app name
    return *pbstrName ? S_OK : E_OUTOFMEMORY;
}

STDMETHODIMP CTTSApp::get_ApplicationVersion(BSTR* pbstrVersion)
{
    if (!pbstrVersion) return E_POINTER;
    *pbstrVersion = SysAllocString(L"1.0.0"); // Replace with your actual app version
    return *pbstrVersion ? S_OK : E_OUTOFMEMORY;
}

Optional: MFC Interface Map

If you want to integrate with MFC's existing COM support, add this to your .cpp file:

BEGIN_INTERFACE_MAP(CTTSApp, CWinApp)
    INTERFACE_PART(CTTSApp, IID_IServiceProvider, ServiceProvider)
    INTERFACE_PART(CTTSApp, IID_IAccessibleApplication, AccessibleApplication)
END_INTERFACE_MAP()

// Implement thunks for the interface map (if needed)
// These are minimal wrappers to route calls to your methods
ULONG FAR EXPORT CTTSApp::XServiceProvider::AddRef()
{
    return ((CTTSApp*)this)->AddRef();
}
ULONG FAR EXPORT CTTSApp::XServiceProvider::Release()
{
    return ((CTTSApp*)this)->Release();
}
HRESULT FAR EXPORT CTTSApp::XServiceProvider::QueryInterface(REFIID riid, void** ppvObject)
{
    return ((CTTSApp*)this)->QueryInterface(riid, ppvObject);
}
HRESULT FAR EXPORT CTTSApp::XServiceProvider::QueryService(REFGUID guidService, REFIID riid, void** ppvObject)
{
    return ((CTTSApp*)this)->QueryService(guidService, riid, ppvObject);
}

// Repeat similar thunks for XAccessibleApplication if needed

Key Notes

  • No ATL Dependency: All code uses native MFC and Win32 COM APIs, so you don't need to link against ATL libraries.
  • Reference Counting: Since CWinApp is a global instance managed by MFC, we skip deleting the object in the Release method.
  • Header Includes: Make sure to include <oleacc.h> (for IAccessibleApplication) and <objbase.h> (for COM helper functions like SysAllocString).

内容的提问来源于stack exchange,提问作者Benilda Key

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:35:15