IAccessiable的学习和使用

前几天听群里大神讨论IAccessiable借口,于是动念学习一下。打开百度,输入IAccessiable,得到一大堆的词条,仔细看就可以搞懂IAccessiable到底是个什么东东。以下摘自MSDN的一段描述:

The IAccessible interface and all of its exposed members are part of a
managed wrapper for the Component Object Model (COM) IAccessible
interface.

概念啥的一百就出来,但是这个东西到底怎么用呢?还是老办法,看看别人怎么用。以下为我找的一篇博客:
IAccessible ( 二 )
根据这篇博客弄了一个demo编译一下。结果,啊哈,果然有错,有错误不打紧,debug先。
debug1
很明显不认识IAccessiable这个类型啊。查阅MADN需要包含头文件,和lib文件

#include <OleAcc.h>

添加完成,再次编译,果然错误少了很多。
Debug2
查阅代码发现有如下函数调用

GetObjectName(*paccChild, &varChild, szObjName, sizeof(szObjName));
GetObjectRole(*paccChild, &varChild, szObjRole, sizeof(szObjRole));
GetObjectClass(*paccChild, szObjClass, sizeof(szObjClass));

这三个函数在给定的Demo代码中并没有给出实现。仔细分析代码流程会发现,这三个函数功能其实很简单,就是获取给定子空间的Name, Role 和Class。没有枪没有炮,我们自己造。先造第一个GetObjectName函数原型很容易推断出,返回值我们不妨先不设,因为程序中也没有用到。以下函数原型:

void GetObjectName(IAccessible* child, VARIANT* varChild, char* objName, int len)

那么如何实现这个功能呢。翻阅MSDN我们发现IAccessable接口有这么个函数

HRESULT get_accName(
  [in]          VARIANT varID,
  [out, retval] BSTR    *pszName
);

参数返回一个BSTR类型的Name,而我们需要一个char*类型。如何搞?用下微软的_bstr_t转换下。上代码:

void GetObjectName(IAccessible* child, VARIANT* varChild, char* objName, int len)
{
    BSTR strTmp;
    HRESULT hr = child->get_accName(*varChild, &strTmp);
    if (S_OK != hr)
    {
        return;
    }
    _bstr_t str = strTmp;
    char* tmp = str;
    strcpy_s(objName, MAX_PATH, tmp);
}

调试下,果然成功获取到Name值。
接下来的Class和Role过程大致类似,直接上代码:

void GetObjectRole(IAccessible* child, VARIANT* varChild, char* objRole, int len)
{
    VARIANT pvarRole;
    DWORD roleId;
    child->get_accRole(*varChild, &pvarRole);

    if (varChild->vt != VT_I4)
    {
        pvarRole.vt = VT_EMPTY;
        return /*E_INVALIDARG*/;
    }
    roleId = pvarRole.lVal;
    UINT   roleLength;
    LPTSTR lpszRoleString;

    // Get the length of the string.
    roleLength = GetRoleText(roleId, NULL, 0);

    // Allocate memory for the string. Add one character to
    // the length you got in the previous call to make room
    // for the null character.
    lpszRoleString = (LPTSTR)malloc((roleLength + 1) * sizeof(TCHAR));
    if (lpszRoleString != NULL)
    {
        // Get the string.
        GetRoleText(roleId, lpszRoleString, roleLength + 1);
    }
    char* tmp = TCHAR2char(lpszRoleString);
    free(lpszRoleString);
    strcpy_s(objRole, MAX_PATH, tmp);
    return /*S_OK*/;

}

void GetObjectClass(IAccessible* child, char* objClass, int len)
{
    HWND htmp;
    LPTSTR strClass;
    strClass = (LPTSTR)malloc(MAX_PATH);
    ::WindowFromAccessibleObject(child, &htmp);
    if (0 == ::GetClassName(htmp, strClass, MAX_PATH))
    {
        free(strClass);
        return;
    }
    char* tmp = TCHAR2char(strClass);

    strcpy_s(objClass, MAX_PATH, tmp);
    free(strClass);
}

其中涉及到一个问题,VS的默认编码是Unicode而我们需要一个char*这个绝对需要转换一下。如何转换呢?百一下得到了一个如下答案:

char* TCHAR2char(TCHAR* tchStr)
{
    int iLen = 2 * wcslen(tchStr);
    char* chRtn = new char[iLen + 1];
    int len = wcstombs(chRtn,tchStr, iLen + 1);
    return chRtn;
}

还需要注意我们用到了_bstr_t和CComBSTR所以需要包含头文件和库文件查阅MSDN需要comsuppw.lib和头文件

#include <atlbase.h>

至此应该能编译通过了,但是回到宿舍,运行在中文环境的VS2015下并不能得到预期的结果。Debug之。发现,GetObjectName中的下列代码

wcstombs(buf, lpString, len);

返回值为-1,这个不科学啊,百度之。得到一个答案。没看明白,但是修改之后确实可以获取成功了。修改之后的代码:

char* TCHAR2char(TCHAR* tchStr)
{
    int iLen = 2 * wcslen(tchStr);
    char* chRtn = new char[iLen + 1];
    _tsetlocale(LC_ALL, _T(""));
    int len = wcstombs(chRtn,tchStr, iLen + 1);
    return chRtn;
}

当然需要先加上头文件:

#include <locale.h>

大功告成,运行结果果然如预期一样。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值