Information about a DDX routine that you can use to access memo fields (119765)
The information in this article applies to:
- The Microsoft Foundation Classes (MFC), when used with:
- Microsoft Visual C++ for Windows, 16-bit edition 1.5
- Microsoft Visual C++ for Windows, 16-bit edition 1.51
- Microsoft Visual C++ for Windows, 16-bit edition 1.52
- Microsoft Visual C++, 32-bit Editions 2.0
- Microsoft Visual C++, 32-bit Editions 2.1
- Microsoft Visual C++, 32-bit Editions 4.0
- Microsoft Visual C++, 32-bit Editions 4.1
- Microsoft Visual C++, 32-bit Enterprise Edition 4.2
- Microsoft Visual C++, 32-bit Enterprise Edition 5.0
- Microsoft Visual C++, 32-bit Enterprise Edition 6.0
- Microsoft Visual C++, 32-bit Professional Edition 4.2
- Microsoft Visual C++, 32-bit Professional Edition 5.0
- Microsoft Visual C++, 32-bit Professional Edition 6.0
- Microsoft Visual C++, 32-bit Learning Edition 6.0
This article was previously published under Q119765 SUMMARY
An application, using the ODBC database classes of the Microsoft Foundation
Classes, can create a CRecordset derived class object which associates a
CString or a CLongBinary member variable with a memo field within an Access
database.
Technote #45, "MFC/Database Support for Long Varchar/Varbinary," available
in the MFC Tech Notes helpfile in your Visual C++ program group discusses
this.
There are some limitations to using a CString object associated with a memo
field, as opposed to a CLongBinary, though: - In the 16-bit versions of the Microsoft Foundation Classes, a CString
object can only hold up to 32K of data, while a CLongBinary object can
hold much more than 64K if needed.
- The initial size allocation of the CString buffer is determined by the
size of the memo field. Because the memo field isn't a fixed length, the
length may be zero for a new record or may be very small in some cases.
This can cause problems when using AddNew()/Edit() and Update(). As the
user assigns data to the CString, the size of the CString buffer may
change and the buffer for the CString will be re-allocated causing an
assertion.
- CStrings terminate with NULL characters and it is possible that memo
fields may contain any binary data including NULLs.
There is, however, no explicit DDX routine to read the data from a
CLongBinary in a recordset and copy it to an edit control, or to
read the contents of the edit control back into the CLongBinary.
(Or a similar control, as 16-bit edit controls are limited to 64K.)
This article gives one example of such a DDX routine which reads
data from a CLongBinary into an edit control and back. NOTE: A bug exists when using the 16-bit Access ODBC driver which is
included with Visual C++ 1.52 which does not allow mapping of CLongBinary
objects to Memo fields.
For more information, click the following article number to view the article in the Microsoft Knowledge Base:
REFERENCES
MFC Tech Notes (helpfile icon in your Visual C++ program group) - Tech note #26, "DDX and DDV Routines" has additional
information on working with DDX routines.
- Tech note #45, "MFC/Database Support for Long
Varchar/Varbinary" has additional information on working
with large data, CLongBinary, CByteArray, and CString.
Sample Code
/* Compile options needed: Default MFC application project options
*/
void DDX_FieldMemo( CDataExchange * pDX,
int nIDEdit, CLongBinary & lbMemo,
CRecordset * pRecordset )
{
ASSERT_VALID( pRecordset );
UINT nLen;
HGLOBAL hGlob;
LPSTR lpStr;
char * pStrWithNull;
HWND hWndCtrl = pDX->PrepareEditCtrl(nIDEdit);
if ( !hWndCtrl )
{
ASSERT(FALSE);
return;
}
if (pDX->m_bSaveAndValidate)
{
nLen = ::GetWindowTextLength(hWndCtrl);
if ( nLen )
{
hGlob = GlobalAlloc( GPTR | GMEM_SHARE, (DWORD)nLen );
if ( !hGlob )
{
AfxThrowMemoryException();
}
lpStr = (LPSTR)GlobalLock( hGlob );
if ( !lpStr )
{
GlobalFree( hGlob );
AfxThrowMemoryException();
}
// Allocate space for the '\0' string terminator
// Throws exception if needed
pStrWithNull = new char[nLen+1];
::GetWindowText(hWndCtrl, pStrWithNull, nLen+1);
// Cut off the null
#ifndef _WIN32
_fmemcpy( lpStr, pStrWithNull, nLen );
#else
memcpy( lpStr, pStrWithNull, nLen );
#endif
delete [] pStrWithNull;
GlobalUnlock( hGlob ); // Don't leave it locked.
}
else // Empty
{
nLen = 0;
hGlob = NULL;
}
// Free memory we are replacing
GlobalUnlock( lbMemo.m_hData );
GlobalFree( lbMemo.m_hData );
// Put in new data
lbMemo.m_dwDataLength = (DWORD) nLen;
lbMemo.m_hData = hGlob;
if (nLen == 0)
{
if ( pRecordset->IsFieldNullable(&lbMemo) )
pRecordset->SetFieldNull( &lbMemo, TRUE);
}
else
{
// It is required that we explicitly set it Dirty
// and NOT Null
pRecordset->SetFieldNull( &lbMemo, FALSE );
pRecordset->SetFieldDirty( &lbMemo, TRUE );
}
}
else // Reading data from recordset into control
{
nLen = (UINT)lbMemo.m_dwDataLength;
if ( nLen )
{
lpStr = (LPSTR)GlobalLock( lbMemo.m_hData );
// Throws exception if needed
pStrWithNull = new char[nLen+1];
#ifndef _WIN32
_fmemcpy( pStrWithNull, lpStr, nLen );
#else
memcpy( pStrWithNull, lpStr, nLen );
#endif
pStrWithNull[nLen] = 0; // Set '\0' at end of string
SetWindowText( hWndCtrl, pStrWithNull );
delete [] pStrWithNull;
GlobalUnlock( lbMemo.m_hData );
}
else
{
SetWindowText( hWndCtrl, "" );
}
}
}
Modification Type: | Major | Last Reviewed: | 5/26/2005 |
---|
Keywords: | kbtshoot kbDatabase kbinfo KB119765 kbAudDeveloper |
---|
|