PDA

View Full Version : windows code troubling Qt



munna
7th November 2006, 12:13
Hi,

I am trying to read contents from Windows Address Book using the following code.




#include <list>
using namespace std;

WABImporter::WABImporter(ContactDetails *cd,QWidget *parent) : QDialog(parent),contactDetails(cd)
{
setAttribute(Qt::WA_DeleteOnClose);
setWindowTitle(tr("Windows Address Book"));

cWAB = new CWAB("");//This object has no Qt code and is used to read from windows address book

contactData = new ContactData(this);

splitter = new QSplitter(Qt::Horizontal,this);

listWidget = new QListWidget(this);

viewMode = new ViewMode(this);
cardArea = new QScrollArea(this);
cardArea->setMinimumWidth(300);
cardArea->setWidget(viewMode);
cardArea->setWidgetResizable(true);
cardArea->setFrameStyle(QFrame::Box|QFrame::Plain);

splitter->addWidget(listWidget);
splitter->addWidget(cardArea);

importCurrentButton = new QPushButton(tr("&Import current contact"),this);
importAllButton = new QPushButton(tr("&Import &All"),this);
cancelButton = new QPushButton(tr("&Cancel"),this);

connect(importCurrentButton,SIGNAL(pressed()),this ,SLOT(importCurrent()));
connect(importAllButton,SIGNAL(pressed()),this,SLO T(importAll()));
connect(cancelButton,SIGNAL(pressed()),this,SLOT(c lose()));

QHBoxLayout *hLay1 = new QHBoxLayout;
hLay1->addStretch(1);
hLay1->addWidget(importCurrentButton);
hLay1->addWidget(importAllButton);
hLay1->addWidget(cancelButton);

QVBoxLayout *mainLayout = new QVBoxLayout(this);
mainLayout->addWidget(splitter);
mainLayout->addLayout(hLay1);

setLayout(mainLayout);
setMinimumSize(640,480);

populateContactsList();
}

WABImporter::~WABImporter()
{
cWAB->ClearWABLVContents();
delete cWAB;//This crashes the application
}

void WABImporter::populateContactsList()
{
list<string> contactsList;
if(cWAB->LoadWABContents(contactsList)){
list<string>::iterator listIterator;
for(listIterator = contactsList.begin(); listIterator != contactsList.end(); ++listIterator){
listWidget->addItem(QString::fromStdString(*listIterator));
}
}
}



There is a menu option, clicking on which will open a dialog box and all the windows contacts are listed there. When I close this dialog the application crahes in

qeventdispatcher_win.cpp




Q_CORE_EXPORT bool winPeekMessage(MSG* msg, HWND hWnd, UINT wMsgFilterMin,
UINT wMsgFilterMax, UINT wRemoveMsg)
{
QT_WA({ return PeekMessage(msg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg); } ,
{ return PeekMessageA(msg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg); });//Crashes here
}



Another very strange thing is that it crahses only when I put a break point in the destructor i.e. delete cWAB and try to debug from there.

Otherwise, when I close the dialog, nothing happens but crashes when I close the main application window.

The main application window crahes in qwidget.cpp




void QWidgetPrivate::hide_helper()
{
Q_Q(QWidget);
if ((q->windowType() == Qt::Popup))
qApp->d_func()->closePopup(q);

// Move test modal here. Otherwise, a modal dialog could get
// destroyed and we lose all access to its parent because we haven't
// left modality. (Eg. modal Progress Dialog)
if (q->isModal())
QApplicationPrivate::leaveModal(q);

#if defined(Q_WS_WIN)
if (q->isWindow() && !(q->windowType() == Qt::Popup) && q->parentWidget()
&& !q->parentWidget()->isHidden() && q->isActiveWindow())
q->parentWidget()->activateWindow(); // Activate parent
#endif

q->setAttribute(Qt::WA_Mapped, false);
hide_sys();//CRASHES HERE

bool wasVisible = q->testAttribute(Qt::WA_WState_Visible);

if (wasVisible) {
q->setAttribute(Qt::WA_WState_Visible, false);

}



Please Help!

jacek
7th November 2006, 12:31
delete cWAB;//This crashes the application
So, what do you have there?

munna
7th November 2006, 12:35
Here it is

Header File




class CWAB
{

public:

CWAB(string fileName);
~CWAB();

bool LoadWABContents(list<string> &contactsList);
void ClearWABLVContents();

private:

BOOL m_bInitialized;
HINSTANCE m_hinstWAB;
LPWABOPEN m_lpfnWABOpen;
LPADRBOOK m_lpAdrBook;
LPWABOBJECT m_lpWABObject;

// Cache Proparray of currently selected item in the list view
LPSPropValue m_lpPropArray;
ULONG m_ulcValues;

// Cache entry id of currently selected item in the listview
SBinary m_SB;

map<int,void *> contactsMap;

void FreeProws(LPSRowSet prows);
//HRESULT HrGetWABTemplateID(ULONG ulObjectType, ULONG *lpcbEID, LPENTRYID * lppEID);
};



CPP File



CWAB::CWAB(string fileName)
{
// Here we load the WAB Object and initialize it
m_bInitialized = FALSE;
m_lpPropArray = NULL;
m_ulcValues = 0;
m_SB.cb = 0;
m_SB.lpb = NULL;

{
TCHAR szWABDllPath[MAX_PATH];
DWORD dwType = 0;
ULONG cbData = sizeof(szWABDllPath);
HKEY hKey = NULL;

*szWABDllPath = '\0';

// First we look under the default WAB DLL path location in the
// Registry.
// WAB_DLL_PATH_KEY is defined in wabapi.h
//
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, WAB_DLL_PATH_KEY, 0, KEY_READ, &hKey))
RegQueryValueEx( hKey, L"", NULL, &dwType, (LPBYTE) szWABDllPath, &cbData);

if(hKey) RegCloseKey(hKey);

// if the Registry came up blank, we do a loadlibrary on the wab32.dll
// WAB_DLL_NAME is defined in wabapi.h
//
m_hinstWAB = LoadLibrary( (lstrlen(szWABDllPath)) ? szWABDllPath : WAB_DLL_NAME );
}

if(m_hinstWAB)
{
// if we loaded the dll, get the entry point
//
m_lpfnWABOpen = (LPWABOPEN) GetProcAddress(m_hinstWAB, "WABOpen");

if(m_lpfnWABOpen)
{
HRESULT hr = E_FAIL;
WAB_PARAM wp = {0};
wp.cbSize = sizeof(WAB_PARAM);
wp.szFileName = (LPSTR) (LPCTSTR) fileName.c_str();

// if we choose not to pass in a WAB_PARAM object,
// the default WAB file will be opened up
//
hr = m_lpfnWABOpen(&m_lpAdrBook,&m_lpWABObject,&wp,0);

if(!hr)
m_bInitialized = TRUE;
}
}
}


// Destructor

CWAB::~CWAB()
{
if(m_SB.lpb)
LocalFree(m_SB.lpb);

if(m_bInitialized)
{
if(m_lpPropArray)
m_lpWABObject->FreeBuffer(m_lpPropArray);

if(m_lpAdrBook)
m_lpAdrBook->Release();

if(m_lpWABObject)
m_lpWABObject->Release();

if(m_hinstWAB)
FreeLibrary(m_hinstWAB);
}
}

bool CWAB::LoadWABContents(list<string> &contactsList)
{
ULONG ulObjType = 0;
LPMAPITABLE lpAB = NULL;
//LPTSTR * lppszArray=NULL;
//ULONG cRows = 0;
//LPSRowSet lpRow = NULL;
LPSRowSet lpRowAB = NULL;
LPABCONT lpContainer = NULL;
int cNumRows = 0;
//int nRows=0;

HRESULT hr = E_FAIL;

ULONG lpcbEID;
LPENTRYID lpEID = NULL;

// Get the entryid of the root PAB container
//
hr = m_lpAdrBook->GetPAB( &lpcbEID, &lpEID);

ulObjType = 0;

// Open the root PAB container
// This is where all the WAB contents reside
//
hr = m_lpAdrBook->OpenEntry(lpcbEID,
(LPENTRYID)lpEID,
NULL,
0,
&ulObjType,
(LPUNKNOWN *)&lpContainer);

m_lpWABObject->FreeBuffer(lpEID);

lpEID = NULL;

if(HR_FAILED(hr)){
if ( lpContainer )
lpContainer->Release();
if ( lpAB )
lpAB->Release();

return false;
}

// Get a contents table of all the contents in the
// WABs root container
//
hr = lpContainer->GetContentsTable( 0,&lpAB);

if(HR_FAILED(hr)){
if ( lpContainer )
lpContainer->Release();

if ( lpAB )
lpAB->Release();

return false;
}

// Order the columns in the ContentsTable to conform to the
// ones we want - which are mainly DisplayName, EntryID and
// ObjectType
// The table is guaranteed to set the columns in the order
// requested
//
hr =lpAB->SetColumns( (LPSPropTagArray)&ptaEid, 0 );

if(HR_FAILED(hr)){
if ( lpContainer )
lpContainer->Release();

if ( lpAB )
lpAB->Release();

return false;
}

// Reset to the beginning of the table
//
hr = lpAB->SeekRow( BOOKMARK_BEGINNING, 0, NULL );

if(HR_FAILED(hr)){
if ( lpContainer )
lpContainer->Release();

if ( lpAB )
lpAB->Release();

return false;
}

// Read all the rows of the table one by one
//
int i = 1;
do {
hr = lpAB->QueryRows(1, 0, &lpRowAB);

if(HR_FAILED(hr)){
break;
}

if(lpRowAB) {
cNumRows = lpRowAB->cRows;

if (cNumRows) {
LPSTR lpsz = lpRowAB->aRow[0].lpProps[ieidPR_DISPLAY_NAME].Value.lpszA;
LPENTRYID lpEID = (LPENTRYID) lpRowAB->aRow[0].lpProps[ieidPR_ENTRYID].Value.bin.lpb;
ULONG cbEID = lpRowAB->aRow[0].lpProps[ieidPR_ENTRYID].Value.bin.cb;

// There are 2 kinds of objects - the MAPI_MAILUSER contact object
// and the MAPI_DISTLIST contact object
// We will only consider MAILUSER objects
//
if(lpRowAB->aRow[0].lpProps[ieidPR_OBJECT_TYPE].Value.l == MAPI_MAILUSER) {
// We will now take the entry-id of each object and cache it
// on the listview item representing that object. This enables
// us to uniquely identify the object later if we need to
//
LPSBinary lpSB = NULL;

m_lpWABObject->AllocateBuffer(sizeof(SBinary), (LPVOID *) &lpSB);

if(lpSB) {
m_lpWABObject->AllocateMore(cbEID, lpSB, (LPVOID *) &(lpSB->lpb));

if(!lpSB->lpb) {
m_lpWABObject->FreeBuffer(lpSB);
continue;
}

CopyMemory(lpSB->lpb, lpEID, cbEID);
lpSB->cb = cbEID;


contactsList.push_back(lpsz);
contactsMap.insert(make_pair(i,lpSB));
//LV_ITEM lvi = {0};
//lvi.mask = LVIF_TEXT | LVIF_PARAM;
//lvi.iItem = pListView->GetItemCount();
//lvi.iSubItem = 0;
//lvi.pszText = lpsz;
//lvi.lParam = (LPARAM) lpSB;

// Now add this item to the list view
//pListView->InsertItem(&lvi);
}
}
}
FreeProws(lpRowAB );
}
++i;
}while ( SUCCEEDED(hr) && cNumRows && lpRowAB) ;

return true;
}

void CWAB::FreeProws(LPSRowSet prows)
{
ULONG irow;
if (!prows)
return;

for (irow = 0; irow < prows->cRows; ++irow)
m_lpWABObject->FreeBuffer(prows->aRow[irow].lpProps);

m_lpWABObject->FreeBuffer(prows);
}

void CWAB::ClearWABLVContents()
{
map<int,void *>::iterator mapIterator;
for(mapIterator = contactsMap.begin(); mapIterator != contactsMap.end(); ++ mapIterator){
if((*mapIterator).second){
LPSBinary lpSB = (LPSBinary) (*mapIterator).second;
m_lpWABObject->FreeBuffer(lpSB);
}
}
}



Thanks a lot

jacek
7th November 2006, 18:51
CWAB::~CWAB()
{
if(m_SB.lpb)
LocalFree(m_SB.lpb);

if(m_bInitialized)
{
if(m_lpPropArray)
m_lpWABObject->FreeBuffer(m_lpPropArray);

if(m_lpAdrBook)
m_lpAdrBook->Release();

if(m_lpWABObject)
m_lpWABObject->Release();

if(m_hinstWAB)
FreeLibrary(m_hinstWAB);
}
}
Well... comment out everything except the first statement and see if it crashes. If not, uncomment next one and so on...

Do you create copies of CWAB instances? To be sure add:
private:
CWAB( const CWAB& );
CWAB& operator=( const CWAB& );

munna
8th November 2006, 02:35
This is the culprit




if(m_hinstWAB)
FreeLibrary(m_hinstWAB);



I load the library in the following way and therefore I need to free it.




//This is the variable -->//HINSTANCE m_hinstWAB;
m_hinstWAB = LoadLibrary( (lstrlen(szWABDllPath)) ? szWABDllPath : WAB_DLL_NAME );



Any ideas on how I can solve this?

Thanks a lot !

jacek
8th November 2006, 20:45
What about those copies? Do you create only one object of CWAB class?


This is the culprit
if(m_hinstWAB)
FreeLibrary(m_hinstWAB);
It's more a workaround, than a solution, but maybe you should load it before you create QApplication and free it after QApplication::exec() returns? Or maybe you should try to load it using QLibrary?

munna
9th November 2006, 08:25
What about those copies? Do you create only one object of CWAB class?

Yes I create only one object and its deleted once the window is closed.


maybe you should load it before you create QApplication and free it after QApplication::exec() returns?

But I don't need it through out the application. Only when user needs to access the Windows Address Book, I need to load the library. And once user is done, I free it.


Or maybe you should try to load it using QLibrary?

ok, will try that. But what will happen if I do not call FreeLibrary(m_hinstWAB); ?

jacek
9th November 2006, 20:15
But what will happen if I do not call FreeLibrary(m_hinstWAB); ?
Nothing, if everything is implemented well. In worst case windows will think that this library is used by a non-existent process. Of course if you will create more than one CWAB object, you'll get a resource leak.

Maybe you should try to reproduce that problem using a sample application? That crash might have more than one cause.

munna
9th November 2006, 20:25
Maybe you should try to reproduce that problem using a sample application?
hmm, I am not sure what do you mean by that. I have a windows only code which accesses the windows address book and it works perfectly. I integrated that code with Qt code and it crashes the application


That crash might have more than one cause.

When I comment those two lines, the app works perfectly (no crashes). But when I uncomment those lines, it crashes in the same place.

May be I am missing something.

Thanks a lot!

jacek
9th November 2006, 20:52
hmm, I am not sure what do you mean by that. I have a windows only code which accesses the windows address book and it works perfectly. I integrated that code with Qt code and it crashes the application
So far we know that Qt + FreeLibrary() == crash. The question is: which part of Qt clashes with FreeLibrary().