用记录集填充树视图
Populate treeview with recordset
我有一个对话框,作为主 window 的子项。对话框有树视图控件。它们是使用资源编辑器和 WinAPI 创建的。
我正在使用 ADO 和 C++ 用数据库中的一些数据填充树视图。不幸的是,我没有得到预期的结果。
为了理解我的问题,我将提供数据库中列的描述 table 我从以下位置获取数据:
- ID -> 自动编号
- BrojUgovora -> 字符串 // ContractNumber
- 许多其他领域...
以上是table的相关值:
ID | BrojUgovora
-----------------
1 | qwert
2 | prvi ugovor
3 | drugi ugovor
在我 运行 我的代码之后,我希望得到以下结果:
德鲁吉乌戈沃尔
前辈
qwert
但我明白了:
drugi ugovor
prvi ugovor
ID -------> why column name instead of column value???
当我通过 lParam 注释掉我将 ID 存储到 treeview 节点的部分时,我得到了正确的结果。
我需要将 ID 存储到 lParam 中,因此不能删除我的那部分代码。
这是我在WM_INITDIALOG
中调用的函数:
/*********** REMARKS ***************
/**** Fills treeview control with the contract number
/**** In treeview node's LPARAM is stored the value of the primary key
/**** Returns the number of failed attempts to load string/autonumber field
/***********************************/
int InitTreeView(HWND hDlg)
{
// error result
int iNumberOfFailedLoads = 0;
//connect to database
ADODB::_ConnectionPtr pConn("ADODB.Connection");
try
{
HRESULT hr = pConn->Open(bstrConnect, username, password,
ADODB::adConnectUnspecified);
if (!SUCCEEDED(hr))
throw _com_error(hr);
ADODB::_CommandPtr pCmd("ADODB.Command");
pCmd->ActiveConnection = pConn;
pCmd->CommandType = ADODB::adCmdText;
pCmd->CommandText = L" select ID, BrojUgovora from UGOVORI;";
ADODB::_RecordsetPtr pRS = pCmd->Execute(NULL, NULL, ADODB::adCmdText);
ADODB::Fields* pFields = NULL;
hr = pRS->get_Fields(&pFields);
if (!SUCCEEDED(hr))
throw _com_error(hr);
if (pFields && pFields->GetCount() > 0)
{
while (!pRS->AdoNSEOF)
{
// load contract values into treeview
TVINSERTSTRUCT tvis = { 0 };
tvis.item.mask = TVIF_TEXT | TVIF_PARAM;
tvis.hInsertAfter = TVI_FIRST;
tvis.item.pszText = // this is string field
pRS->Fields->GetItem(L"BrojUgovora")->Value.bstrVal;
tvis.item.lParam = // this is autonumber field
(LPARAM)(pRS->Fields->GetItem(L"ID")->Value.lVal);
HTREEITEM hti = TreeView_InsertItem(GetDlgItem(hDlg, IDC_TREE1),
&tvis);
if (NULL == hti)
iNumberOfFailedLoads++;
pRS->MoveNext();
}
pRS->Close();
}
pConn->Close();
}
catch (_com_error &e)
{
if (pConn->State == ADODB::adStateOpen)
pConn->Close();
iNumberOfFailedLoads = -1;
}
return iNumberOfFailedLoads;
}
这里是 WM_INITDIALOG
处理程序:
case WM_INITDIALOG:
{
// needed for visual styles, long story
EnableThemeDialogTexture(hDlg, ETDT_ENABLETAB);
InitTreeView(hDlg);
}
return (INT_PTR)FALSE;
调试结果:
这是我从调试器得到的:
/*********** REMARKS ***************
/**** Fills treeview control with the contract number
/**** In treeview node's LPARAM is stored the value of the primary key
/**** Returns the number of failed attempts to load string/autonumber field
/***********************************/
int InitTreeView(HWND hDlg)
{
// error result
int iNumberOfFailedLoads = 0;
//connect to database
ADODB::_ConnectionPtr pConn("ADODB.Connection");
try
{
HRESULT hr = pConn->Open(bstrConnect, username, password,
ADODB::adConnectUnspecified);
if (!SUCCEEDED(hr))
throw _com_error(hr);
ADODB::_CommandPtr pCmd("ADODB.Command");
pCmd->ActiveConnection = pConn;
pCmd->CommandType = ADODB::adCmdText;
pCmd->CommandText = L" select ID, BrojUgovora from UGOVORI;";
ADODB::_RecordsetPtr pRS = pCmd->Execute(NULL, NULL, ADODB::adCmdText);
ADODB::Fields* pFields = NULL;
hr = pRS->get_Fields(&pFields);
if (!SUCCEEDED(hr))
throw _com_error(hr);
if (pFields && pFields->GetCount() > 0)
{
while (!pRS->AdoNSEOF)
{
// load contract values into treeview
TVINSERTSTRUCT tvis = { 0 };
tvis.item.mask = TVIF_TEXT | TVIF_PARAM;
tvis.hInsertAfter = TVI_FIRST;
tvis.item.pszText =
pRS->Fields->GetItem(L"BrojUgovora")->Value.bstrVal;
tvis.item.lParam = // here is first breakpoint
(LPARAM)(pRS->Fields->GetItem(L"ID")->Value.lVal);
// MessageBeep(0) added just so I can put breakpoint there
MessageBeep(0); // here is second breakpoint
HTREEITEM hti = TreeView_InsertItem(GetDlgItem(hDlg, IDC_TREE1),
&tvis);
if (NULL == hti)
iNumberOfFailedLoads++;
pRS->MoveNext();
}
pRS->Close();
}
pConn->Close();
}
catch (_com_error &e)
{
if (pConn->State == ADODB::adStateOpen)
pConn->Close();
iNumberOfFailedLoads = -1;
}
return iNumberOfFailedLoads;
}
当我到达第一个断点时,从数据库中正确读取了字符串。
在第二个断点上,它 "magically" 变为 ID
。
我为解决这个问题所做的努力:
像下面这样更改 while
循环中的代码后,一切正常:
while (!pRS->AdoNSEOF)
{
wchar_t txt[50];
memset(txt, L'[=15=]', sizeof(txt));
swprintf_s(txt, 50, L"%s",
pRS->Fields->GetItem(L"BrojUgovora")->Value.bstrVal);
//...
tvis.item.pszText = txt;
// the rest of the code is the same
我曾尝试使用动态字符串来存储数据库中的字符串,但失败了。我收到调试断言错误。当我尝试使用 wstring
.
时也会发生同样的情况
问题:
我应该如何重写我的 InitTreeView
函数以避免我上面描述的错误?
我怀疑 GetItem
方法正在返回一个临时值,一旦函数 returns;所以 pszText
最终指向的字符串是 freed/overwritten.
尝试以下方法,看看是否有所不同:
// load contract values into treeview
_variant_t varText = pRS->Fields->GetItem(L"BrojUgovora")->Value;
_variant_t varID = pRS->Fields->GetItem(L"ID")->Value;
TVINSERTSTRUCT tvis = { 0 };
tvis.item.mask = TVIF_TEXT | TVIF_PARAM;
tvis.hInsertAfter = TVI_FIRST;
tvis.item.pszText = varText.bstrVal;
tvis.item.lParam = varID.lVal;
我有一个对话框,作为主 window 的子项。对话框有树视图控件。它们是使用资源编辑器和 WinAPI 创建的。
我正在使用 ADO 和 C++ 用数据库中的一些数据填充树视图。不幸的是,我没有得到预期的结果。
为了理解我的问题,我将提供数据库中列的描述 table 我从以下位置获取数据:
- ID -> 自动编号
- BrojUgovora -> 字符串 // ContractNumber
- 许多其他领域...
以上是table的相关值:
ID | BrojUgovora
-----------------
1 | qwert
2 | prvi ugovor
3 | drugi ugovor
在我 运行 我的代码之后,我希望得到以下结果: 德鲁吉乌戈沃尔 前辈 qwert
但我明白了:
drugi ugovor
prvi ugovor
ID -------> why column name instead of column value???
当我通过 lParam 注释掉我将 ID 存储到 treeview 节点的部分时,我得到了正确的结果。
我需要将 ID 存储到 lParam 中,因此不能删除我的那部分代码。
这是我在WM_INITDIALOG
中调用的函数:
/*********** REMARKS ***************
/**** Fills treeview control with the contract number
/**** In treeview node's LPARAM is stored the value of the primary key
/**** Returns the number of failed attempts to load string/autonumber field
/***********************************/
int InitTreeView(HWND hDlg)
{
// error result
int iNumberOfFailedLoads = 0;
//connect to database
ADODB::_ConnectionPtr pConn("ADODB.Connection");
try
{
HRESULT hr = pConn->Open(bstrConnect, username, password,
ADODB::adConnectUnspecified);
if (!SUCCEEDED(hr))
throw _com_error(hr);
ADODB::_CommandPtr pCmd("ADODB.Command");
pCmd->ActiveConnection = pConn;
pCmd->CommandType = ADODB::adCmdText;
pCmd->CommandText = L" select ID, BrojUgovora from UGOVORI;";
ADODB::_RecordsetPtr pRS = pCmd->Execute(NULL, NULL, ADODB::adCmdText);
ADODB::Fields* pFields = NULL;
hr = pRS->get_Fields(&pFields);
if (!SUCCEEDED(hr))
throw _com_error(hr);
if (pFields && pFields->GetCount() > 0)
{
while (!pRS->AdoNSEOF)
{
// load contract values into treeview
TVINSERTSTRUCT tvis = { 0 };
tvis.item.mask = TVIF_TEXT | TVIF_PARAM;
tvis.hInsertAfter = TVI_FIRST;
tvis.item.pszText = // this is string field
pRS->Fields->GetItem(L"BrojUgovora")->Value.bstrVal;
tvis.item.lParam = // this is autonumber field
(LPARAM)(pRS->Fields->GetItem(L"ID")->Value.lVal);
HTREEITEM hti = TreeView_InsertItem(GetDlgItem(hDlg, IDC_TREE1),
&tvis);
if (NULL == hti)
iNumberOfFailedLoads++;
pRS->MoveNext();
}
pRS->Close();
}
pConn->Close();
}
catch (_com_error &e)
{
if (pConn->State == ADODB::adStateOpen)
pConn->Close();
iNumberOfFailedLoads = -1;
}
return iNumberOfFailedLoads;
}
这里是 WM_INITDIALOG
处理程序:
case WM_INITDIALOG:
{
// needed for visual styles, long story
EnableThemeDialogTexture(hDlg, ETDT_ENABLETAB);
InitTreeView(hDlg);
}
return (INT_PTR)FALSE;
调试结果:
这是我从调试器得到的:
/*********** REMARKS ***************
/**** Fills treeview control with the contract number
/**** In treeview node's LPARAM is stored the value of the primary key
/**** Returns the number of failed attempts to load string/autonumber field
/***********************************/
int InitTreeView(HWND hDlg)
{
// error result
int iNumberOfFailedLoads = 0;
//connect to database
ADODB::_ConnectionPtr pConn("ADODB.Connection");
try
{
HRESULT hr = pConn->Open(bstrConnect, username, password,
ADODB::adConnectUnspecified);
if (!SUCCEEDED(hr))
throw _com_error(hr);
ADODB::_CommandPtr pCmd("ADODB.Command");
pCmd->ActiveConnection = pConn;
pCmd->CommandType = ADODB::adCmdText;
pCmd->CommandText = L" select ID, BrojUgovora from UGOVORI;";
ADODB::_RecordsetPtr pRS = pCmd->Execute(NULL, NULL, ADODB::adCmdText);
ADODB::Fields* pFields = NULL;
hr = pRS->get_Fields(&pFields);
if (!SUCCEEDED(hr))
throw _com_error(hr);
if (pFields && pFields->GetCount() > 0)
{
while (!pRS->AdoNSEOF)
{
// load contract values into treeview
TVINSERTSTRUCT tvis = { 0 };
tvis.item.mask = TVIF_TEXT | TVIF_PARAM;
tvis.hInsertAfter = TVI_FIRST;
tvis.item.pszText =
pRS->Fields->GetItem(L"BrojUgovora")->Value.bstrVal;
tvis.item.lParam = // here is first breakpoint
(LPARAM)(pRS->Fields->GetItem(L"ID")->Value.lVal);
// MessageBeep(0) added just so I can put breakpoint there
MessageBeep(0); // here is second breakpoint
HTREEITEM hti = TreeView_InsertItem(GetDlgItem(hDlg, IDC_TREE1),
&tvis);
if (NULL == hti)
iNumberOfFailedLoads++;
pRS->MoveNext();
}
pRS->Close();
}
pConn->Close();
}
catch (_com_error &e)
{
if (pConn->State == ADODB::adStateOpen)
pConn->Close();
iNumberOfFailedLoads = -1;
}
return iNumberOfFailedLoads;
}
当我到达第一个断点时,从数据库中正确读取了字符串。
在第二个断点上,它 "magically" 变为 ID
。
我为解决这个问题所做的努力:
像下面这样更改 while
循环中的代码后,一切正常:
while (!pRS->AdoNSEOF)
{
wchar_t txt[50];
memset(txt, L'[=15=]', sizeof(txt));
swprintf_s(txt, 50, L"%s",
pRS->Fields->GetItem(L"BrojUgovora")->Value.bstrVal);
//...
tvis.item.pszText = txt;
// the rest of the code is the same
我曾尝试使用动态字符串来存储数据库中的字符串,但失败了。我收到调试断言错误。当我尝试使用 wstring
.
问题:
我应该如何重写我的 InitTreeView
函数以避免我上面描述的错误?
我怀疑 GetItem
方法正在返回一个临时值,一旦函数 returns;所以 pszText
最终指向的字符串是 freed/overwritten.
尝试以下方法,看看是否有所不同:
// load contract values into treeview
_variant_t varText = pRS->Fields->GetItem(L"BrojUgovora")->Value;
_variant_t varID = pRS->Fields->GetItem(L"ID")->Value;
TVINSERTSTRUCT tvis = { 0 };
tvis.item.mask = TVIF_TEXT | TVIF_PARAM;
tvis.hInsertAfter = TVI_FIRST;
tvis.item.pszText = varText.bstrVal;
tvis.item.lParam = varID.lVal;