How to get the most current IHTMLDocument2 object from IE DOM - c++

Currently, I use MSAA to get an IHTMLDocument2 object from a IE HWND. However, with some complicated web applications, this IHTMLDocument2 object may contain several IHTMLDocument2 objects, some of them are not belong to the current displaying page, but the previous page.
It seems to me, IE sometimes doesn't refesh its DOM object, but keep adding more IHTMLDocument2 object into its DOM. My question is how can I get the current displaying IHTMLDocument2 object from the DOM object.
Thanks in advance
Update
Hi Remy,
Thanks for your answer.
Yes, you are right, I do use frames to get to other IHTMLDocument2 objects. My understanding is that the IHTMLDocument2 object that I get from a HWND is the top object in its DOM. IE sometimes puts the prevous IHTMLDocument2 objects inside one of the frames as well.
Here is part of my code.
BOOL IESpy::GetHTMLText( CComPtr<IHTMLDocument2> spDoc, int tagNo, int schNo)
{
USES_CONVERSION;
HRESULT hr = NULL;
BOOL res = TRUE;
BOOL doneSearch = FALSE;
// Extract the source code of the document
if (spDoc) {
IHTMLFramesCollection2* pFrames = NULL;
if (hr = (spDoc->get_frames(&pFrames)) == S_OK){
LONG framesCount;
pFrames->get_length(&framesCount);
if (framesCount > 0) {
for( long i=0; i < framesCount; i++) {
VARIANT varIdx;
varIdx.vt=VT_I4;
VARIANT varResult;
varIdx.lVal=i;
VariantInit(&varResult);
hr = pFrames->item(&varIdx, &varResult);
if (SUCCEEDED(hr) && (varResult.vt == VT_DISPATCH)){
CComQIPtr<IHTMLWindow2> pFrameWnd;
CComQIPtr<IHTMLDocument2> pFrameDoc;
CComBSTR description=NULL;
pFrameWnd = varResult.pdispVal;
VariantClear(&varResult);
if (pFrameWnd == 0) {
continue;
}
hr = pFrameWnd->get_document(&pFrameDoc);
if (SUCCEEDED(hr) && pFrameDoc){
GetHTMLText( pFrameDoc, tagNo, schNo );
if ( m_foundText ) {
break;
}
} else if ( hr == E_ACCESSDENIED ) {
CComQIPtr<IWebBrowser2> spBrws = HtmlWindowToHtmlWebBrowser(pFrameWnd);
if ( spBrws != NULL) {
// Get the document object from the IWebBrowser2 object.
CComQIPtr<IDispatch> spDisp;
hr = spBrws->get_Document(&spDisp);
if ( hr == S_OK ) {
pFrameDoc = spDisp;
if ( pFrameDoc ) {
GetHTMLText( pFrameDoc, tagNo, schNo );
if ( m_foundText ) {
break;
}
}
}
}
}
}
}
}
pFrames->Release();
if ( !m_foundText ) {
res = ReadSearchText(spDoc, tagNo, schNo );
doneSearch = TRUE;
}
}
if ( !m_foundText && doneSearch == FALSE ) {
res = ReadSearchText(spDoc, tagNo, schNo );
}
}
return res;
}
BOOL IESpy::ReadSearchText(CComPtr<IHTMLDocument2> spDoc, int tagNo, int schNo )
{
USES_CONVERSION;
HRESULT hr = NULL;
BOOL found = FALSE;
IHTMLElementCollection *pAll;
hr = spDoc->get_all(&pAll);
if (FAILED(hr)) {
return FALSE;
}
long items;
IDispatch *ppvDisp;
IHTMLElement *ppvElement;
pAll->get_length(&items);
std::wstring foundText = L"";
for ( long j = 0; j < items; j++ ) {
VARIANT index;
index.vt = VT_I4;
index.lVal = j;
hr = pAll->item( index, index, &ppvDisp );
if (FAILED(hr)) {
return FALSE;
}
if ( ppvDisp ) {
ppvDisp->QueryInterface(IID_IHTMLElement, (void **)&ppvElement);
if ( ppvElement ) {
CComBSTR bstrTag;
ppvElement->get_tagName(&bstrTag);
wchar_t *wtemp = OLE2W(bstrTag);
if ( wtemp ) {
std::wstring text = ReadSearchText(ppvElement, wtemp, tagNo, schNo, found);
if ( !text.empty() ) {
if ( !foundText.empty() ) {
foundText += concat_string;
}
foundText += text;
}
ppvElement->Release();
if ( found ) {
BOOL stop = FALSE;
for ( size_t i = 0; i < m_tagName[tagNo]->size(); i++ ) {
if ( wcscmp(m_tagName[tagNo]->at(i).c_str(), L"HTML") == 0
|| wcscmp(m_tagName[tagNo]->at(i).c_str(), L"HEAD") == 0
|| wcscmp(m_tagName[tagNo]->at(i).c_str(), L"BODY") == 0 ) {
stop = TRUE;
break;
}
}
if ( stop ) {
break;
}
}
} else {
ppvElement->Release();
}
}
}
}
if ( !foundText.empty() ) {
if ( m_screenCompare ) {
// long timeStamp = GetHPTimeStamp(spDoc);
// m_temp_results[timeStamp] = foundText;
m_temp_results.push_back(foundText);
} else {
m_result += foundText;
m_result += L" ";
m_foundText = TRUE;
}
}
return TRUE;
}

An IHTMLDocument2 cannot contain other IHTMLDocument2 objects (unless they belong to frames on the page), and certainly not from previous pages. How are you determining that exactly? Can you show some code?

Related

LDAP C++ why is ldap_result always busy?

I tried copying this example: https://docs.oracle.com/cd/E19957-01/817-6707/search.html
I am trying to get the DN to bind to a user. But when searching ldap_result always says that the server is busy. Is there something else I need to do to get this to work?
LDAP *ld = NULL;
int iDebug = session.ini["ldap_debug_level"].Int32();
string sHostIP = session.ini["ldap_host"];
string sPort = session.ini["ldap_port"];
string sURL = sHostIP+":"+sPort;
int iErr;
iErr = ldap_initialize( &ld, sURL.c_str() );
if( iErr != LDAP_SUCCESS )
{
ldap_unbind(ld);
return false;
}
int iVersion = LDAP_VERSION3;
if( ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &iVersion ) != LDAP_OPT_SUCCESS )
{
ldap_unbind(ld);
return false;
}
string sLDAPPW = session.ini["ldap_server_pw"];
struct berval pServerPassword = { 0, NULL };
pServerPassword.bv_val = ber_strdup( &sLDAPPW[0] );
pServerPassword.bv_len = strlen( pServerPassword.bv_val );
//mysterious code required to prevent crashing
int nsctrls = 0;
LDAPControl c;
c.ldctl_oid = LDAP_CONTROL_PASSWORDPOLICYREQUEST;
c.ldctl_value.bv_val = NULL;
c.ldctl_value.bv_len = 0;
c.ldctl_iscritical = 0;
LDAPControl sctrl[3];
sctrl[nsctrls] = c;
LDAPControl *sctrls[4];
sctrls[nsctrls] = &sctrl[nsctrls];
sctrls[++nsctrls] = NULL;
LDAPControl **sctrlsp = NULL;
if ( nsctrls )
{
sctrlsp = sctrls;
}
string sBindDN = session.ini["ldap_bind_dn"];
ber_int_t iMsgid;
iErr = ldap_sasl_bind( ld, sBindDN.c_str(), LDAP_SASL_SIMPLE, &pServerPassword, sctrlsp, NULL, &iMsgid );
ber_memfree( pServerPassword.bv_val );
if( iErr != LDAP_SUCCESS )
{
ldap_unbind(ld);
return false;
}
string sBaseDN = session.ini["ldap_base_dn"];
string sFilters = "(uid="+sUserName+")";
LDAPMessage *res;
iErr = ldap_search_ext(ld, // LDAP * ld
&sBaseDN[0], // char * base
LDAP_SCOPE_SUBORDINATE,// int scope
&sFilters[0], // char * filter
NULL, // char * attrs[]
0, // int attrsonly
NULL, // LDAPControl ** serverctrls
NULL, // LDAPControl ** clientctrls
NULL, //struct timeval *timeoutp
LDAP_NO_LIMIT, //int sizelimit
&iMsgid //ber_int_t iMsgid
);
if (iErr != LDAP_SUCCESS)
{
ldap_unbind(ld);
return false;
}
struct timeval zerotime;
zerotime.tv_sec = zerotime.tv_usec = 0L;
int i, parse_rc, finished = 0, num_entries = 0, num_refs = 0;
char *a, *dn, *matched_msg = NULL, *error_msg = NULL;
BerElement *ber;
char **vals, **referrals;
LDAPControl **serverctrls;
while ( !finished )
{
iErr = ldap_result( ld, iMsgid, LDAP_MSG_ONE, &zerotime, &res );
switch ( iErr )
{
case -1:
Log(1, "BasicAuthenticate: error in ldap_result:{}", ldap_err2string(iErr));
ldap_unbind(ld);
return false;
break;
case 0:
// The timeout period specified by zerotime was exceeded keep polling
Log(1, "BasicAuthenticate: server busy: keep polling");
sleep(1);
break;
case LDAP_RES_SEARCH_ENTRY:
num_entries++;
//Get and print the DN of the entry.
if (( dn = ldap_get_dn( ld, res )) != NULL )
{
Log (1, "ldap_get_dn: {}", dn );
ldap_memfree( dn );
}
for ( a = ldap_first_attribute( ld, res, &ber ); a != NULL; a = ldap_next_attribute( ld, res, ber ) )
{
// Get and print all values for each attribute.
if (( vals = ldap_get_values( ld, res, a )) != NULL )
{
for ( i = 0; vals[ i ] != NULL; i++ )
{
Log (1, "ldap_get_values: {}:{}", a, vals[ i ] );
}
ldap_value_free( vals );
}
ldap_memfree( a );
}
if ( ber != NULL )
{
ber_free( ber, 0 );
}
ldap_msgfree( res );
break;
case LDAP_RES_SEARCH_REFERENCE:
num_refs++;
parse_rc = ldap_parse_reference( ld, res, &referrals, NULL, 1 );
if ( parse_rc != LDAP_SUCCESS )
{
ldap_unbind(ld);
return false;
}
if ( referrals != NULL )
{
for ( i = 0; referrals[ i ] != NULL; i++ )
{
Log(1, "BasicAuthenticate: Search reference:{}", referrals[ i ]);
}
ldap_value_free( referrals );
}
break;
case LDAP_RES_SEARCH_RESULT:
finished = 1;
parse_rc = ldap_parse_result( ld, res, &iErr, &matched_msg, &error_msg, NULL, &serverctrls, 1 );
if ( parse_rc != LDAP_SUCCESS )
{
kDebugLog(1, "BasicAuthenticate: error in ldap_parse_result:{}", ldap_err2string(parse_rc));
ldap_unbind(ld);
return false;
}
break;
default:
break;
}
}
The error I get is:
BasicAuthenticate: server busy keep polling
BasicAuthenticate: error in ldap_parse_result:Server is busy
Am I missing a line of code so the server won't be busy? Is there some sort of incompatibility with the methods I'm using?

rapid TS fragment ffmpeg decoding - memory leak

Environment:
Ubuntu 16.04 (x64)
C++
ffmpeg
Use-case
Multiple MPEG-TS fragments are rapidly decoded ( numerous every sec )
The format of the TS fragments is dynamic and can't be known ahead of time
The first A/V frames of each fragment are needed to be extracted
Problem statement
The code bellow successfully decodes A/V, BUT, has a huge memory leak ( MBytes/sec )
According to the docs seems all memory is freed as it should ( does it... ? )
Why do I get this huge mem leak, what am I missing in the following code snap ?
struct MEDIA_TYPE {
ffmpeg::AVMediaType eType;
union {
struct {
ffmpeg::AVPixelFormat colorspace;
int width, height;
float fFPS;
} video;
struct : WAVEFORMATEX {
short sSampleFormat;
} audio;
} format;
};
struct FRAME {
enum { MAX_PALNES = 3 + 1 };
int iStrmId;
int64_t pts; // Duration in 90Khz clock resolution
uint8_t** ppData; // Null terminated
int32_t* pStride;// Zero terminated
};
HRESULT ProcessTS(IN Operation op, IN uint8_t* pTS, IN uint32_t uiBytes, bool(*cb)(IN const MEDIA_TYPE& mt, IN FRAME& frame, IN PVOID pCtx), IN PVOID pCbCtx)
{
uiBytes -= uiBytes % 188;// align to 188 packet size
struct CONTEXT {
uint8_t* pTS;
uint32_t uiBytes;
int32_t iPos;
} ctx = { pTS, uiBytes, 0 };
LOGTRACE(TSDecoder, "ProcessTS(%d, 0x%.8x, %d, 0x%.8x, 0x%.8x), this=0x%.8x\r\n", (int)op, pTS, uiBytes, cb, pCbCtx, this);
ffmpeg::AVFormatContext* pFmtCtx = 0;
if (0 == (pFmtCtx = ffmpeg::avformat_alloc_context()))
return E_OUTOFMEMORY;
ffmpeg::AVIOContext* pIoCtx = ffmpeg::avio_alloc_context(pTS, uiBytes, 0, &ctx
, [](void *opaque, uint8_t *buf, int buf_size)->int {
auto pCtx = (CONTEXT*)opaque;
int size = pCtx->uiBytes;
if (pCtx->uiBytes - pCtx->iPos < buf_size)
size = pCtx->uiBytes - pCtx->iPos;
if (size > 0) {
memcpy(buf, pCtx->pTS + pCtx->iPos, size);
pCtx->iPos += size;
}
return size;
}
, 0
, [](void* opaque, int64_t offset, int whence)->int64_t {
auto pCtx = (CONTEXT*)opaque;
switch (whence)
{
case SEEK_SET:
pCtx->iPos = offset;
break;
case SEEK_CUR:
pCtx->iPos += offset;
break;
case SEEK_END:
pCtx->iPos = pCtx->uiBytes - offset;
break;
case AVSEEK_SIZE:
return pCtx->uiBytes;
}
return pCtx->iPos;
});
pFmtCtx->pb = pIoCtx;
int iRet = ffmpeg::avformat_open_input(&pFmtCtx, "fakevideo.ts", m_pInputFmt, 0);
if (ERROR_SUCCESS != iRet) {
assert(false);
pFmtCtx = 0;// a user-supplied AVFormatContext will be freed on failure.
return E_FAIL;
}
struct DecodeContext {
ffmpeg::AVStream* pStream;
ffmpeg::AVCodec* pDecoder;
int iFramesProcessed;
};
HRESULT hr = S_OK;
int iStreamsProcessed = 0;
bool bVideoFound = false;
int64_t ptsLast = 0;
int64_t dtsLast = 0;
auto pContext = (DecodeContext*)alloca(sizeof(DecodeContext) * pFmtCtx->nb_streams);
for (unsigned int i = 0; i < pFmtCtx->nb_streams; i++) {
assert(pFmtCtx->streams[i]->index == i);
pContext[i].pStream = pFmtCtx->streams[i];
pContext[i].pDecoder = ffmpeg::avcodec_find_decoder(pFmtCtx->streams[i]->codec->codec_id);
pContext[i].iFramesProcessed= 0;
if (0 == pContext[i].pDecoder)
continue;
if ((iRet = ffmpeg::avcodec_open2(pFmtCtx->streams[i]->codec, pContext[i].pDecoder, NULL)) < 0) {
_ASSERT(FALSE);
hr = E_FAIL;
goto ErrExit;
}
}
while (S_OK == hr) {
ffmpeg::AVFrame* pFrame = 0;
ffmpeg::AVPacket pkt;
ffmpeg::av_init_packet(&pkt);
if (ERROR_SUCCESS != (iRet = ffmpeg::av_read_frame(pFmtCtx, &pkt))) {
hr = E_FAIL;
break;
}
if ((0 == dtsLast) && (0 != pkt.dts))
dtsLast = pkt.dts;
if ((0 == ptsLast) && (0 != pkt.pts))
ptsLast = pkt.pts;
DecodeContext& ctx = pContext[pkt.stream_index];
if (Operation::DECODE_FIRST_FRAME_OF_EACH_STREAM == op) {
if (iStreamsProcessed == pFmtCtx->nb_streams) {
hr = S_FALSE;
goto Next;
}
if (ctx.iFramesProcessed > 0)
goto Next;
iStreamsProcessed++;
}
if (0 == ctx.pDecoder)
goto Next;
if (0 == (pFrame = ffmpeg::av_frame_alloc())) {
hr = E_OUTOFMEMORY;
goto Next;
}
LOGTRACE(TSDecoder, "ProcessTS(%d, 0x%.8x, %d, 0x%.8x, 0x%.8x), this=0x%.8x, decode, S:%d, T:%d\r\n", (int)op, pTS, uiBytes, cb, pCbCtx, this, pkt.stream_index, ctx.pStream->codec->codec_type);
int bGotFrame = false;
int iBytesUsed = 0;
MEDIA_TYPE mt;
memset(&mt, 0, sizeof(mt));
mt.eType = ctx.pStream->codec->codec_type;
switch (mt.eType) {
case ffmpeg::AVMediaType::AVMEDIA_TYPE_AUDIO:
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
if((iRet = ffmpeg::avcodec_decode_audio4(ctx.pStream->codec, pFrame, &bGotFrame, &pkt)) < 0) {
hr = E_FAIL;
goto Next;
}
_ASSERT(pkt.size == iRet);
// FFMPEG AAC decoder oddity, first call to 'avcodec_decode_audio4' results mute audio where the second result the expected audio
bGotFrame = false;
if ((iRet = ffmpeg::avcodec_decode_audio4(ctx.pStream->codec, pFrame, &bGotFrame, &pkt)) < 0) {
hr = E_FAIL;
goto Next;
}
_ASSERT(pkt.size == iRet);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
if (false == bGotFrame)
goto Next;
iBytesUsed = ctx.pStream->codec->frame_size;
mt.format.audio.nChannels = ctx.pStream->codec->channels;
mt.format.audio.nSamplesPerSec = ctx.pStream->codec->sample_rate;
mt.format.audio.wBitsPerSample = ffmpeg::av_get_bytes_per_sample(ctx.pStream->codec->sample_fmt) * 8;
mt.format.audio.nBlockAlign = mt.format.audio.nChannels * mt.format.audio.wBitsPerSample / 8;
mt.format.audio.sSampleFormat = (short)pFrame->format;
break;
case ffmpeg::AVMediaType::AVMEDIA_TYPE_VIDEO:
if ((iRet = ffmpeg::avcodec_decode_video2(ctx.pStream->codec, pFrame, &bGotFrame, &pkt)) < 0) {
hr = E_FAIL;
break;
}
if (false == bGotFrame)
goto Next;
assert(ffmpeg::AVPixelFormat::AV_PIX_FMT_YUV420P == ctx.pStream->codec->pix_fmt);// Thats is the only color space currently supported
iBytesUsed = (ctx.pStream->codec->width * ctx.pStream->codec->height * 3) / 2;
mt.format.video.width = ctx.pStream->codec->width;
mt.format.video.height = ctx.pStream->codec->height;
mt.format.video.colorspace = ctx.pStream->codec->pix_fmt;
mt.format.video.fFPS = (float)ctx.pStream->codec->framerate.num / ctx.pStream->codec->framerate.den;
bVideoFound = true;
break;
default:
goto Next;
}
ctx.iFramesProcessed++;
{
FRAME f = { ctx.pStream->index, ((0 == ptsLast) ? dtsLast : ptsLast), (uint8_t**)pFrame->data, (int32_t*)pFrame->linesize };
if ((iRet > 0) && (false == cb(mt, f, pCbCtx)))
hr = S_FALSE;// Breaks the loop
}
Next:
ffmpeg::av_free_packet(&pkt);
if (0 != pFrame) {
//ffmpeg::av_frame_unref(pFrame);
ffmpeg::av_frame_free(&pFrame);
pFrame = 0;
}
}
ErrExit:
for (unsigned int i = 0; i < pFmtCtx->nb_streams; i++)
ffmpeg::avcodec_close(pFmtCtx->streams[i]->codec);
pIoCtx->buffer = 0;// We have allocated the buffer, no need for ffmpeg to free it 4 us
pFmtCtx->pb = 0;
ffmpeg::av_free(pIoCtx);
ffmpeg::avformat_close_input(&pFmtCtx);
ffmpeg::avformat_free_context(pFmtCtx);
return hr;
}
You need to unref the packets before reusing them. And there's no need to allocate and deallocate them all the time.
Here's how I do it which might help you:
// Initialise a packet queue
std::list<AVPacket *> packets;
...
for (int c = 0; c < MAX_PACKETS; c++) {
ff->packets.push_back(av_packet_alloc());
}
while (!quit) {
... get packet from queue
int err = av_read_frame(ff->context, packet);
... process packet (audio, video, etc)
av_packet_unref(packet); // add back to queue for reuse
}
// Release packets
while (ff->packets.size()) { // free packets
AVPacket *packet = ff->packets.front();
av_packet_free(&packet);
ff->packets.pop_front();
}
In your code you've freed a packet which wasn't allocated in the first place.

VisualGestureBuilder API not working when more than one player

I'm using the VisualGestureBuilder C++ API to track three simple discrete gestures.
When there is only one player in front of the Kinect, it works great.
But as soon as a second player arrives, the gesture analysis seems to go crazy, and for the two players, I get erratic but smooth results, as if the data for the two players and for the three gestures were mixed together, and random data was added...
And while the VGB API is going wrong, I still get valid body data (I'm drawing skeletons at the same time)
I discovered that this phenomenon was triggered as soon as I have more than one IVisualGestureBuilderFrameReader in the not-paused state.
Here are some portions of my code :
class GESTURES_STREAM
{
friend class MY_KINECT;
private:
struct SLOT
{
IVisualGestureBuilderDatabase* database = nullptr;
IGesture** gestures = nullptr;
UINT gestures_count = 0;
IVisualGestureBuilderFrameSource* source = nullptr;
IVisualGestureBuilderFrameReader* reader = nullptr;
IVisualGestureBuilderFrame* frame = nullptr;
};
SLOT slots[BODY_COUNT];
public:
GESTURES_RESULTS gestures_results[BODY_COUNT];
};
GESTURES_STREAM gestures_stream;
//----------------------------------------------------------------------------------------------------
void MY_KINECT::start_gestures_stream(wstring vgb_file)
{
for (int i = 0; i < BODY_COUNT; i++)
{
hr = CreateVisualGestureBuilderDatabaseInstanceFromFile(vgb_file.c_str(), &gestures_stream.slots[i].database);
if (FAILED(hr)) MY_UTILITIES::fatal_error("Erreur initialisation Kinect : gestures");
gestures_stream.slots[i].gestures_count = 0;
hr = gestures_stream.slots[i].database->get_AvailableGesturesCount(&gestures_stream.slots[i].gestures_count);
if (FAILED(hr)) MY_UTILITIES::fatal_error("Erreur initialisation Kinect : gestures");
if (gestures_stream.slots[i].gestures_count == 0)
{
MY_UTILITIES::fatal_error("Erreur initialisation Kinect : gestures");
}
gestures_stream.slots[i].gestures = new IGesture*[gestures_stream.slots[i].gestures_count];
hr = gestures_stream.slots[i].database->get_AvailableGestures(gestures_stream.slots[i].gestures_count, gestures_stream.slots[i].gestures);
if (FAILED(hr)) MY_UTILITIES::fatal_error("Erreur initialisation Kinect : gestures");
/////
hr = CreateVisualGestureBuilderFrameSource(kinect_sensor, 0, &gestures_stream.slots[i].source);
if (FAILED(hr)) MY_UTILITIES::fatal_error("Erreur initialisation Kinect : gestures");
hr = gestures_stream.slots[i].source->AddGestures(gestures_stream.slots[i].gestures_count, gestures_stream.slots[i].gestures);
if (FAILED(hr)) MY_UTILITIES::fatal_error("Erreur initialisation Kinect : gestures");
hr = gestures_stream.slots[i].source->OpenReader(&gestures_stream.slots[i].reader);
if (FAILED(hr)) MY_UTILITIES::fatal_error("Erreur initialisation Kinect : gestures");
hr = gestures_stream.slots[i].reader->put_IsPaused(TRUE);
if (FAILED(hr)) MY_UTILITIES::fatal_error("Erreur initialisation Kinect : gestures");
/////
safe_release(&gestures_stream.slots[i].database);
}
}
//----------------------------------------------------------------------------------------------------
void MY_KINECT::update()
{
//...
//...
// handling all the different stream, including body
//...
//...
if (body_stream.data_is_new == true)
{
for (int i = 0; i < BODY_COUNT; i++)
{
if (gestures_stream.slots[i].source != nullptr)
{
BOOLEAN is_tracked;
if (body_stream.bodies[i]->get_IsTracked(&is_tracked) == S_OK)
{
if (is_tracked == TRUE)
{
UINT64 a;
if (body_stream.bodies[i]->get_TrackingId(&a) == S_OK)
{
UINT64 b;
if (gestures_stream.slots[i].source->get_TrackingId(&b) == S_OK)
{
if (a != b)
{
gestures_stream.slots[i].source->put_TrackingId(a);
}
}
}
BOOLEAN paused;
if (gestures_stream.slots[i].reader->get_IsPaused(&paused) == S_OK)
{
if (paused == TRUE)
{
gestures_stream.slots[i].reader->put_IsPaused(FALSE);
}
}
}
else
{
BOOLEAN paused;
if (gestures_stream.slots[i].reader->get_IsPaused(&paused) == S_OK)
{
if (paused == FALSE)
{
gestures_stream.slots[i].reader->put_IsPaused(TRUE);
}
}
}
}
}
if (gestures_stream.slots[i].reader != nullptr)
{
if (gestures_stream.slots[i].reader->CalculateAndAcquireLatestFrame(&gestures_stream.slots[i].frame) == S_OK)
{
BOOLEAN is_valid;
if (gestures_stream.slots[i].frame->get_IsTrackingIdValid(&is_valid) == S_OK)
{
if (is_valid == TRUE)
{
for (int j = 0; j < gestures_stream.slots[i].gestures_count; j++)
{
wchar_t gesture_name[256];
if (gestures_stream.slots[i].gestures[j]->get_Name(sizeof(gesture_name), gesture_name) == S_OK)
{
IDiscreteGestureResult* discrete_result = nullptr;
if (gestures_stream.slots[i].frame->get_DiscreteGestureResult(gestures_stream.slots[i].gestures[j], &discrete_result) == S_OK)
{
BOOLEAN detected;
if (discrete_result->get_Detected(&detected) == S_OK)
{
if (detected == TRUE)
{
float confidence;
if (discrete_result->get_Confidence(&confidence) == S_OK)
{
gestures_stream.gestures_results[i].results[gesture_name] = confidence;
}
}
else
{
gestures_stream.gestures_results[i].results[gesture_name] = 0;
}
}
safe_release(&discrete_result);
}
}
}
}
}
safe_release(&gestures_stream.slots[i].frame);
}
}
}
}
}
//----------------------------------------------------------------------------------------------------

C++ CHTMLView element page loading and then disappearing

In my C++ application, a CHTMLView is used to load some HTML into a web page. It works by writing the HTML to a temporary file, and then calling Navigate2() on the CHTMLView to navigate to the file location.
What we are finding happens is that the navigation occurs, the file is written, the completely correct contents of the page appears, but then it quickly disappears and becomes blank. But it's a visual thing; right-clicking and saying "View Source" shows the correct source, and hovering over elements on the page that react to hovering make them appear again (but everything else stays white). Resizing the window or scrolling is the only way to make everything appear.
I have tried navigating first to about:blank and then triggering a navigation to the correct place with a OnDocumentComplete() event. I have even tried navigating first to blank dummy page and then going from there. Nothing changes.
Any advice?!
The derived class is ScriptViewer.
ScriptViewer.h
class CScriptViewer : public CHtmlView
{
protected:
CScriptViewer(); // protected constructor used by dynamic creation
DECLARE_DYNCREATE(CScriptViewer)
// html Data
public:
//{{AFX_DATA(CScriptViewer)
// NOTE: the ClassWizard will add data members here
//}}AFX_DATA
// Attributes
public:
CAMAgentDesktopDoc* m_pDoc;
CScriptDlg* m_pDlg;
CString strScriptLocation;
BOOL m_bInitialLoad;
// Operations
public:
void GetAllValues( map<CString,CString>& mValues );
void GetValuesIn( IHTMLDocument2* pHTMLDoc, map<CString,CString>& mValues );
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CScriptViewer)
public:
virtual void OnInitialUpdate();
virtual void OnBeforeNavigate2(LPCTSTR lpszURL, DWORD nFlags, LPCTSTR lpszTargetFrameName, CByteArray& baPostedData, LPCTSTR lpszHeaders, BOOL* pbCancel);
virtual void OnDocumentComplete(LPCTSTR lpszURL);
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
virtual ~CScriptViewer();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
CAMTrace m_trace;
// Generated message map functions
//{{AFX_MSG(CScriptViewer)
// NOTE - the ClassWizard will add and remove member functions here.
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
ScriptViewer.cpp
CScriptViewer::CScriptViewer()
{
//{{AFX_DATA_INIT(CScriptViewer)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
m_trace.SetEXEName( _T("CScriptViewer") );
m_trace.Trace( _T("constructor"), FALSE, 0 );
strScriptLocation = _T("");
m_bInitialLoad = FALSE;
m_pDoc = NULL;
m_pDlg = NULL;
}
CScriptViewer::~CScriptViewer()
{
/*
map<CString,CString> mValues;
GetAllValues( mValues );
m_pDlg->UpdateUserEnteredValues( mValues );
*/
m_trace.Trace( _T("destructor"), FALSE, 0 );
}
void CScriptViewer::DoDataExchange(CDataExchange* pDX)
{
CHtmlView::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CScriptViewer)
// NOTE: the ClassWizard will add DDX and DDV calls here
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CScriptViewer, CHtmlView)
//{{AFX_MSG_MAP(CScriptViewer)
// NOTE - the ClassWizard will add and remove mapping macros here.
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CScriptViewer diagnostics
#ifdef _DEBUG
void CScriptViewer::AssertValid() const
{
CHtmlView::AssertValid();
}
void CScriptViewer::Dump(CDumpContext& dc) const
{
CHtmlView::Dump(dc);
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CScriptViewer message handlers
void CScriptViewer::OnInitialUpdate()
{
try
{
m_trace.Trace( _T("OnInitialUpdate") );
ASSERT( m_pDoc );
ASSERT( m_pDlg );
}
catch(...)
{
}
}
void CScriptViewer::OnBeforeNavigate2(LPCTSTR lpszURL, DWORD nFlags, LPCTSTR lpszTargetFrameName, CByteArray& baPostedData, LPCTSTR lpszHeaders, BOOL* pbCancel)
{
try
{
map<CString,CString> mValues;
GetAllValues( mValues );
ASSERT( m_pDlg );
// GJS
if (!m_pDlg) return;
m_pDlg->UpdateUserEnteredValues( mValues );
CString strURL = lpszURL;
int nPosClose = strURL.Find( URL_INSTRUCTION_TO_ADAPTIVE_DESKTOP );
if ( nPosClose > 0 )
{
*pbCancel = TRUE;
CHtmlView::OnBeforeNavigate2(lpszURL, nFlags, lpszTargetFrameName, baPostedData, lpszHeaders, pbCancel);
m_pDlg->OnScriptInstructionToDesktop( strURL.Mid( nPosClose + _tcslen(URL_INSTRUCTION_TO_ADAPTIVE_DESKTOP) ), mValues );
}
else
{
CHtmlView::OnBeforeNavigate2(lpszURL, nFlags, lpszTargetFrameName, baPostedData, lpszHeaders, pbCancel);
}
}
catch(...)
{
}
}
void CScriptViewer::OnDocumentComplete(LPCTSTR lpszURL) {
if (!m_bInitialLoad) {
//Navigate2(strScriptLocation);
//m_bInitialLoad = TRUE;
}
}
///////////////////////////////////////////////////////////////////////////////////
// accessing data values from the HTML pages, after the user has fiddled with them
void CScriptViewer::GetValuesIn( IHTMLDocument2* pHTMLDoc, map<CString,CString>& mValues )
{
try
{
if ( pHTMLDoc != NULL )
{
BSTR bsURL;
VERIFY( SUCCEEDED( pHTMLDoc->get_URL( &bsURL ) ) );
// TRACE( _T("GetValuesIn(%s)\r\n"), CString(bsURL) );
IHTMLFramesCollection2* pFrames = NULL;
if ( SUCCEEDED( pHTMLDoc->get_frames( &pFrames ) ) )
{
long lNumFrames = 0;
VERIFY( SUCCEEDED( pFrames->get_length( &lNumFrames ) ) );
for( long l = 0; l < lNumFrames; l++ )
{
COleVariant v1(l);
VARIANT vDispFrame;
if ( SUCCEEDED( pFrames->item( v1, &vDispFrame ) ) )
{
if ( vDispFrame.vt == VT_DISPATCH )
{
IHTMLWindow2* pWindow = NULL;
VERIFY( SUCCEEDED( (vDispFrame.pdispVal)->QueryInterface( IID_IHTMLWindow2, (LPVOID*)&pWindow ) ) );
ASSERT( pWindow );
IHTMLDocument2* pSubDoc = NULL;
if ( SUCCEEDED( pWindow->get_document( &pSubDoc ) ) )
{
GetValuesIn( pSubDoc, mValues );
pSubDoc->Release();
}
pWindow->Release();
}
}
}
pFrames->Release();
}
IHTMLElementCollection* pElemColl = NULL;
HRESULT hr = pHTMLDoc->get_all(&pElemColl);
if (SUCCEEDED(hr) && pElemColl)
{
long lNumElements = 0;
VERIFY( SUCCEEDED( pElemColl->get_length( &lNumElements ) ) );
for( long l = 0; l < lNumElements; l++ )
{
COleVariant v1(l);
COleVariant vzero((long)0);
LPDISPATCH pDispTemp = NULL;
VERIFY( SUCCEEDED( pElemColl->item( v1, vzero, &pDispTemp ) ) );
ASSERT( pDispTemp != NULL );
IHTMLElement* pel = NULL;
VERIFY( SUCCEEDED( pDispTemp->QueryInterface( IID_IHTMLElement, (LPVOID*)&pel ) ) );
CString str;
BSTR bsid;
pel->get_id( &bsid );
VARIANT vValue;
pel->getAttribute( CString("value").AllocSysString(), 0, &vValue );
CString strID = CString(bsid);
if ( !strID.IsEmpty() )
{
CString strValue = _T("");
if ( vValue.vt == VT_BSTR ) {
strValue = CString(vValue.bstrVal);
} else if ( vValue.vt == VT_I2 || vValue.vt == VT_I4 ) {
strValue.Format( _T("%d"), vValue.intVal );
}
mValues[strID] = strValue;
// str.Format( _T("ID %s, value %s\r\n"),
// strID, strValue );
// strRetval += str;
}
pel->Release();
}
pElemColl->Release();
}
else
ASSERT(FALSE);
}
else
ASSERT(FALSE); // passed null object doc
}
catch(...)
{
}
}
void CScriptViewer::GetAllValues( map<CString,CString>& mValues )
{
try
{
mValues.clear();
LPDISPATCH pDisp = GetHtmlDocument();
if ( pDisp )
{
IHTMLDocument2* p = NULL;
if ( SUCCEEDED( pDisp->QueryInterface( IID_IHTMLDocument2, (LPVOID*)&p ) ) && p != NULL )
{
GetValuesIn( p, mValues );
p->Release();
}
else
ASSERT(FALSE); // unable to QI for IHTMLDocument2?
pDisp->Release();
}
}
catch(...)
{
}
}
Here is the code that handles the navigation:
CString strFilePath = CAMMiscSharedFilePaths::GetFullPathToWindowsTempDir() + _T("\\") + m_call->m_camCampaignSettings.m_scriptView.m_strName+_T("_temp.htm");
HRESULT hr = WriteStringToTextFile( strFilePath, strRedirect ); //intentionally left for html settings, as it stores data in windows temp
if ( SUCCEEDED(hr) ) {
pView->strScriptLocation = strFilePath;
CString str = strFilePath;
pView->Navigate2(str);
}
Here is my derived class of a CHTMLView. I load the HTML directly into the browser. Works for me, maybe you can use it:
#include "stdafx.h"
#include "GMHtmlView.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
IMPLEMENT_DYNCREATE(CGMHtmlView, CHtmlView)
CGMHtmlView::CGMHtmlView(IHtmlEventNotifier* pHEN)
{
EnableToolTips(FALSE);
m_pBrowser = NULL;
m_pBrowserDispatch = NULL;
m_pHEN = pHEN;
m_strPrefix = "http://";
}
void CGMHtmlView::DoDataExchange(CDataExchange* pDX)
{
CHtmlView::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CGMHtmlView, CHtmlView)
END_MESSAGE_MAP()
BOOL CGMHtmlView::Create(const RECT &rect,CWnd* pParentWnd)
{
BOOL bRet = CHtmlView::Create(NULL,NULL,WS_VISIBLE,rect,pParentWnd,AFX_IDW_PANE_FIRST);
// Pointer auf Browser herausfinden
if(bRet)
{
LPUNKNOWN unknown = GetDlgItem(0)->GetControlUnknown();
HRESULT hr = unknown->QueryInterface(IID_IWebBrowser2,(void **)&m_pBrowser);
if (SUCCEEDED(hr))
hr = unknown->QueryInterface(IID_IDispatch,(void **)&m_pBrowserDispatch);
}
return bRet;
}
void CGMHtmlView::SetPrefix(const CString& prefix)
{
m_strPrefix = prefix;
}
void CGMHtmlView::OnBeforeNavigate2(LPCTSTR lpszURL, DWORD nFlags, LPCTSTR lpszTargetFrameName, CByteArray& baPostedData, LPCTSTR lpszHeaders, BOOL* pbCancel)
{
CString url(lpszURL);
url.MakeLower();
// Sperre: alles andere als die leere Seite
// und unser Inhalt wird gesperrt
if(url == "about:blank")
{
CHtmlView::OnBeforeNavigate2(lpszURL,nFlags,lpszTargetFrameName,baPostedData,lpszHeaders,pbCancel);
return;
}
if(url.Find(m_strPrefix) != 0)
{
*pbCancel = TRUE;
return;
}
// jetzt die Adresse nach aussen weiterleiten
if(m_pHEN)
{
url = url.Right(url.GetLength() - m_strPrefix.GetLength());
m_pHEN->UrlNotify(url);
}
}
void CGMHtmlView::Clear()
{
if(!IsWindow(m_hWnd))
return;
IHTMLDocument2* pDoc = GetDocument();
if(!pDoc)
{
Navigate2("about:blank");
return;
}
pDoc->close();
VARIANT open_name;
VARIANT open_features;
VARIANT open_replace;
IDispatch *open_window = NULL;
::VariantInit(&open_name);
open_name.vt = VT_BSTR;
open_name.bstrVal = ::SysAllocString(L"_self");
::VariantInit(&open_features);
::VariantInit(&open_replace);
HRESULT hr = pDoc->open(::SysAllocString(L"text/html"),open_name,open_features,
open_replace,&open_window);
if (hr == S_OK)
Refresh();
if (open_window != NULL)
open_window->Release();
}
void CGMHtmlView::LoadHTML(const CString& html)
{
if(!IsWindow(m_hWnd))
return;
Clear();
IHTMLDocument2* pDoc = GetDocument();
if(!pDoc)
return;
SAFEARRAY* sa = SafeArrayCreateVector(VT_VARIANT,0,1);
VARIANT* var;
SafeArrayAccessData(sa,(LPVOID*) &var);
var->vt = VT_BSTR;
var->bstrVal = html.AllocSysString();
SafeArrayUnaccessData(sa);
pDoc->write(sa);
pDoc->Release();
}
IHTMLDocument2* CGMHtmlView::GetDocument()
{
IHTMLDocument2* document = NULL;
if (m_pBrowser != NULL)
{
IDispatch *document_dispatch = NULL;
HRESULT hr = m_pBrowser->get_Document(&document_dispatch);
if (SUCCEEDED(hr) && (document_dispatch != NULL))
{
hr = document_dispatch->QueryInterface(IID_IHTMLDocument2,(void **)&document);
document_dispatch->Release();
}
}
return document;
}
void CGMHtmlView::AssertValid() const
{
//CHtmlView::AssertValid();
}
void CGMHtmlView::PostNcDestroy()
{
//CHtmlView::PostNcDestroy();
}

Memory leaks in Webbrowser (COM)

This snippet of code generate huge memory leaks. Could you help me to find out where it happens?
This code does the following thing:
1) It gets IHTMLDocuments2 interface
2) Requests for all tags collection
3) Iterates over whole collection
4) and adds some of the tags' data to list
IDispatch* pDisp;
pDisp = this->GetHtmlDocument();
if (pDisp != NULL )
{
IHTMLDocument2* pHTMLDocument2;
HRESULT hr;
hr = pDisp->QueryInterface( IID_IHTMLDocument2,(void**)&pHTMLDocument2 );
if (hr == S_OK)
{
// I know that I could use IHTMLDocument3 interface to get collection by ID
// but it didn't worked and returned NULL on each call.
IHTMLElementCollection* pColl = NULL;
// get all tags
hr = pHTMLDocument2->get_all( &pColl );
if (hr == S_OK && pColl != NULL)
{
LONG celem;
hr = pColl->get_length( &celem );
if ( hr == S_OK )
{
//iterate through all tags
// if I iterate this block of code in cycle, it
// uses memory available upto 2GBs and then
// app crashes
for ( int i=0; i< celem; i++ )
{
VARIANT varIndex;
varIndex.vt = VT_UINT;
varIndex.lVal = i;
VARIANT var2;
VariantInit( &var2 );
IDispatch* pElemDisp = NULL;
hr = pColl->item( varIndex, var2, &pElemDisp );
if ( hr == S_OK && pElemDisp != NULL)
{
IHTMLElement* pElem;
hr = pElemDisp->QueryInterface(IID_IHTMLElement,(void **)&pElem);
if ( hr == S_OK)
{
// check INPUT tags only
BSTR tagNameStr = L"";
pElem->get_tagName(&tagNameStr);
CString tagname(tagNameStr);
SysFreeString(tagNameStr);
tagname.MakeLower();
if (tagname != "input")
{
continue;
}
//get ID attribute
BSTR bstr = L"";
pElem->get_id(&bstr);
CString idStr(bstr);
SysFreeString(bstr);
if (RequiredTag(pElem))
{
AddTagToList(pElem);
}
//release all objects
pElem->Release();
}
pElemDisp->Release();
}
}
}
// I looked over this code snippet many times and couldn't find what I'm missing here...
pColl->Release();
}
pHTMLDocument2->Release();
}
pDisp->Release();
}
Inside your loop, for each retreived element that does not have a tagname of "input" (which will be most elements), you are not calling pElem->Release() when calling continue, so you are leaking them:
if (tagname != "input")
{
pElem->Release(); // <-- add this
continue;
}
With that said, you should re-write your code to use ATL's smart pointer classes (CComPtr, CComQIPtr, CComBSTR, etc) to manage the memory for you so you do not have to manually release everything yourself anymore, eg:
CComPtr<IDispatch> pDisp;
pDisp.Attach(this->GetHtmlDocument());
if (pDisp.p != NULL)
{
CComQIPtr<IHTMLDocument2> pHTMLDocument2(pDisp);
if (pHTMLDocument2.p != NULL)
{
CComPtr<IHTMLElementCollection> pColl;
pHTMLDocument2->get_all(&pColl);
if (pColl.p != NULL)
{
LONG celem;
if (SUCCEEDED(pColl->get_length(&celem)))
{
for (LONG i = 0; i < celem; ++i)
{
VARIANT varIndex;
varIndex.vt = VT_UINT;
varIndex.lVal = i;
VARIANT var2;
VariantInit( &var2 );
CComPtr<IDispatch> pElemDisp;
pColl->item( varIndex, var2, &pElemDisp );
if (pElemDisp.p != NULL)
{
CComQIPtr<IHTMLElement> pElem(pElemDisp);
if (pElem.p != NULL)
{
CComBSTR tagNameStr;
pElem->get_tagName(&tagNameStr);
if (lstrcmpiW(tagNameStr.m_str, L"input") != 0)
continue;
CComBSTR idStr;
pElem->get_id(&idStr);
if (RequiredTag(pElem))
AddTagToList(pElem);
}
}
}
}
}
}
}