105次浏览

MS Active Accessibility 接口技术(二)-C++获取QQ聊天记录

搞了几天因为没有初始化, 可让我几天没睡好觉

CoInitialize(NULL); 下面是这个函数介绍
CoInitialize是Windows提供的API函数,用来告诉 Windows以单线程的方式创建com对象。应用程序调用com库函数(除CoGetMalloc和内存分配函数)之前必须初始化com库。

也就是说使用前千万千万记得初始化! 我因为这个问题没日没夜的弄了三天, 今天终于解决了! 能取到QQ聊天记录
真的是没毛病, 有付出就有收获 遇事咱不能放弃  百度百度百度!!

一些函数信息请看我的第一篇 MS Active Accessibility 接口技术文章 https://www.citext.cn/299.html.

附上效果图:

MS Active Accessibility 接口技术(二)效果运行图
MS Active Accessibility 接口技术(二)效果运行图

老样子 贴代码! 可能写的不是太好 毕竟新手 多多见谅!
代码有多处内存泄漏或溢出 不适宜长时间循环运行 请自行修改 我不想折腾了!!

Nice.h :

#include <OleAcc.h>
#pragma comment(lib,"OleAcc.lib")


#define SAFE_RELEASE(p_)					{ if (p_ != NULL) p_->Release(); p_ = NULL; }


Test.cpp:

#include <atlbase.h>
#include<Windows.h>
#include <comdef.h>
#include<iostream>
#include<string>
#include"Nice.h"
using namespace std;

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;
}
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);
}
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);
}

// UI元素的状态也表示成整型形式。因为一个状态可以有多个值,
//例如可选的、可做焦点的,该整数是反映这些值的位的或操作结果。

BOOL GetObjectState(IAccessible* pAcc,
	VARIANT* pvarChild,
	UINT& nState)
	//=============================================================================
{
	BOOL bRet = FALSE;

	nState = 0;

	_ASSERTE(pAcc);
	_ASSERTE(pvarChild);

	if (pAcc && pvarChild)
	{
		VARIANT varState;
		VariantInit(&varState);

		HRESULT hr = pAcc->get_accState(*pvarChild, &varState);

		if (SUCCEEDED(hr) && (varState.vt == VT_I4))
		{
			nState = varState.lVal;
			bRet = TRUE;
		}

		VariantClear(&varState);
	}

	return bRet;
}

BOOL Find(IAccessible* paccParent,
	LPSTR szName, //传入子控件Name值
	LPSTR szRole,//传入子控件Role值
	LPSTR szClass,//传入子控件Class值
	IAccessible** paccChild,//传出参数
	VARIANT* pvarChild//传出参数
	)
{
	_ASSERTE(paccParent);
	_ASSERTE(paccChild);
	_ASSERTE(pvarChild);

	HRESULT hr;
	long numChildren = 0;//子控件数量
	unsigned long numFetched = 0;//索引
	VARIANT varChild;
	IAccessible* pCAcc = NULL;
	IEnumVARIANT* pEnum = NULL;
	IDispatch* pDisp = NULL;
	BOOL found = false;
	char szObjName[256], szObjRole[256], szObjClass[256];


	//得到父亲支持的IEnumVARIANT接口
	hr = paccParent->QueryInterface(IID_IEnumVARIANT, (PVOID*)&pEnum);
	if (pEnum)
	{
		pEnum->Reset();
	}
	//取得父亲拥有的可访问的子的数目
	paccParent->get_accChildCount(&numChildren);
	//cout << endl << "取得父亲拥有的可访问的子的数目: " << numChildren << endl;
	//搜索并比较每一个子ID,找到名字、角色、类与输入相一致的。
	for (long index = 1; (index <= numChildren && !found); index++)
	{
		
		VariantClear(&varChild);
		pCAcc = NULL;
		//cout << "index: " << index << endl;
		
		// 如果支持IEnumVARIANT接口我们就调用Next方法,得到下一个子ID
		//以及其对应的 IDispatch 接口
		if (pEnum)
		{
			hr = pEnum->Next(1, &varChild, &numFetched);
			if (!SUCCEEDED(hr))
			{
				found = true;
				break;
			}
		}
		else
		{
			//如果一个父亲不支持IEnumVARIANT接口,子ID就是它的序号
			varChild.vt = VT_I4;
			varChild.lVal = index;
		}

		// 找到此子ID对应的 IDispatch 接口
		if (varChild.vt == VT_I4)
		{

			//通过子ID序号得到对应的 IDispatch 接口
			pDisp = NULL;
			hr = paccParent->get_accChild(varChild, &pDisp);
		}
		else
		{

			//如果父支持IEnumVARIANT接口可以直接得到子IDispatch 接口
			pDisp = varChild.pdispVal;
		}

		// 通过 IDispatch 接口得到子的 IAccessible 接口 pCAcc
		if (pDisp)
		{
			hr = pDisp->QueryInterface(IID_IAccessible, (void**)&pCAcc);
			SAFE_RELEASE(pDisp);
		}

		// Get information about the child
		if (pCAcc)
		{
			//如果子支持IAccessible 接口,那么子ID就是CHILDID_SELF
			VariantInit(&varChild);
			varChild.vt = VT_I4;
			varChild.lVal = CHILDID_SELF;

			*paccChild = pCAcc;
		}
		else
		{
			//如果子不支持IAccessible 接口
			*paccChild = paccParent;

		}
		//跳过了有不可访问状态的元素
		UINT nState = 0;
		GetObjectState(*paccChild, &varChild, nState);

		// check if object is available
		if (nState & (/*STATE_SYSTEM_UNAVAILABLE |*/ STATE_SYSTEM_INVISIBLE /*| STATE_SYSTEM_OFFSCREEN*/))
		{
			SAFE_RELEASE(pCAcc);
			continue;
		}


		//通过get_accName得到Name
		GetObjectName(*paccChild, &varChild, szObjName, sizeof(szObjName));
		//通过get_accRole得到Role
		GetObjectRole(*paccChild, &varChild, szObjRole, sizeof(szObjRole));
		//通过WindowFromAccessibleObject和GetClassName得到Class
		GetObjectClass(*paccChild, szObjClass, sizeof(szObjClass));
		//以上实现代码比较简单,大家自己看代码吧。

		//cout << "Name---" << szObjName << " Role---" << szObjRole << " Calss---" << szObjClass << endl;
		//cout << endl;
		//如果这些参数与输入相符或输入为NULL
		if ((!szName || !strcmp(szName, szObjName)) && (!szRole || !strcmp(szRole, szObjRole)) && (!szClass || !strcmp(szClass, szObjClass)))
		{
			found = true;
			*pvarChild = varChild;
			break;
		}

		if (!found && pCAcc)
		{
			// 以这次得到的子接口为父递归调用
			found = Find(
				pCAcc,
				szName,
				szRole,
				szClass,
				paccChild,
				pvarChild);

			if (*paccChild != pCAcc)
			{
				SAFE_RELEASE(pCAcc);
			}
		}


	}//End for

	// Clean up

	//SAFE_RELEASE(pCAcc);
	SAFE_RELEASE(pEnum);
	VariantClear(&varChild);

	return found;
}

int main()
{
	HANDLE hOut;

	//  获取输出流的句柄
	hOut = GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleTitle(L"GetQ - By: Citext");
	SetConsoleTextAttribute(hOut,
		FOREGROUND_GREEN |     // 前景色_绿色
		FOREGROUND_INTENSITY);// 前景色_加强

	CoInitialize(NULL);
	IAccessible *paccMainWindow = NULL;

	IAccessible*    paccControl = NULL;
	VARIANT         varControl;

	HWND hwnd = FindWindow(L"TXGuiFoundation", L"Citext");
	BSTR pszValue;
	string str1 = "";
	if (hwnd)//判断一下窗口是否存在 避免出错
	{
		HRESULT hr = AccessibleObjectFromWindow(hwnd, OBJID_WINDOW, IID_IAccessible, (void**)&paccMainWindow);
		Find(paccMainWindow, "消息", "可编辑文本", "TXGuiFoundation", &paccControl, &varControl);


		while (1)
		{

			paccControl->get_accValue(varControl, &pszValue);

			
			_bstr_t str = pszValue;
			char* tmp = str;
			str1 = tmp;
			cout << "字符串长度: " << str1.length() << endl << endl;
			for (unsigned int i = 0; i < str1.length(); i++)
			{
				if (str1[i] != '\r')
				{
					cout << str1[i];
				}
				else cout << endl;

			}

			system("cls");

                   SysFreeString(pszValue);//释放 如果不进行释放内存每秒+8kb
		
		}
	}//End if
	else cout << "请运行程序!!" << endl;
	VariantClear(&varControl);
	paccControl->Release();

	return 0;
}


	//hr = paccControl->get_accValue(varControl,&pszValue);

	/*hr = paccControl->get_accName(varControl, &pszValue);

	paccControl->Release();
	VariantClear(&varControl);

	_bstr_t str = pszValue;
	char* tmp = str;
	cout << tmp << endl;*/


	//// 找到确定按钮,并执行默认动作。
	//if (Find(paccMainWindow, "关闭", "按下按钮", "NAMELESS",
	//	&paccControl,
	//	&varControl))
	//{

	//	//这里执行按钮的默认动作,即"按下这个按钮"

	//	hr = paccControl->accDoDefaultAction(varControl);

	//	paccControl->Release();

	//	VariantClear(&varControl);
	//}


注: 转载请写出处

发表评论

电子邮件地址不会被公开。 必填项已用*标注