Microsoft KB Archive/119765

= Information about a DDX routine that you can use to access memo fields =

Article ID: 119765

Article Last Modified on 11/21/2006

-

APPLIES TO

 Microsoft Foundation Class Library 4.2, when used with:  Microsoft Visual C++ 1.5 Professional Edition

 Microsoft Visual C++ 1.51

 Microsoft Visual C++ 1.52 Professional Edition

 Microsoft Visual C++ 2.0 Professional Edition</li></ul>

 Microsoft Visual C++ 2.1</li></ul>

 Microsoft Visual C++ 4.0 Standard Edition</li></ul>

 Microsoft Visual C++ 4.1 Subscription</li></ul>

 Microsoft Visual C++ 4.2 Enterprise Edition</li></ul>

 Microsoft Visual C++ 5.0 Enterprise Edition</li></ul>

 Microsoft Visual C++ 6.0 Enterprise Edition</li></ul>

 Microsoft Visual C++ 4.2 Professional Edition</li></ul>

 Microsoft Visual C++ 5.0 Professional Edition</li></ul>

<ul> <li>Microsoft Visual C++ 6.0 Professional Edition</li></ul>

<ul> <li>Microsoft Visual C++ 6.0 Standard Edition</li></ul> </li></ul>

-

<div class="notice_section">

This article was previously published under Q119765

<div class="summary_section">

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:


 * 1) 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.
 * 2) 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.
 * 3) 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:

BUG: Program crashes when memo field mapped to CLongBinary

<div class="moreinformation_section">

MORE INFORMATION
NOTE: The sample code below must explicitly call SetFieldNull and SetFieldDirty to set the field as NOT Null and as dirty when reading data from the control. Without both of these calls, the field will not be updated in the database.

The DDX routine shown, will need to be explicitly called in your CFormView or CRecordView derived class's DoDataExchange member function outside of the AFX_DATA_MAP section. For example the following code associates a CRecordset member variable CLongBinary m_lbMemo with an edit control with the ID IDC_EDIT_MEMO: void CSampView::DoDataExchange(CDataExchange* pDX) {     CRecordView::DoDataExchange(pDX); //AFX_DATA_MAP

DDX_FieldMemo( pDX, IDC_EDIT_MEMO, m_pSet->m_lbMemo, m_pSet ); }

<div class="references_section">

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];

// 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, "" ); }      }   }

Additional query words: SQL_LONGVARCHAR SQL_LONGVARBINARY MfcDatabase kbMFC kbVC150 kbVC151 kbVC152 kbVC200 kbVC210 kbVC400 kbVC410 kbVC420 kbVC500 kbVC600 kbVC600

Keywords: kbtshoot kbdatabase kbinfo KB119765

-

[mailto:TECHNET@MICROSOFT.COM Send feedback to Microsoft]

© Microsoft Corporation. All rights reserved.