Today, I turned around in the VC version of the BBS. I saw this question by a buddy: saying that he had an error when writing MFC's database programs (ODBC), and then insert Update when it is called Update. Because of the BBS, I exchanged with him, found that he called Format between AddNew and Update. Intuition tells me that the question is here. So I analyzed it. This is my post on BBS.
I took a closer look at this question, and the problem is inside the MFC: only the MFC4.2 of VC6 belts will be described below.
When we use the ODBC to insert the database, we are such a process: addNew () // give member assignment update () and in the MFC source file dbcore.cpp 1040 row, there is a row of comments: // Buffer Address MUST NOT CHANGE - ODBC'S SQLBINDCOL Depends Upon This is used by the CString binding string type because the MFC is bound by the default data source, and CString uses dynamic memory management mode, so this buffer address is actually changed. So, the 1041 line of dbcore.cpp starts this a few words:
Void * pvbind; pvbind = value.getBuffer (0); value.releaseBuffer (); if (pvbind! = pinfo-> m_pvbindaddress) {trace1 ("Error: cstring buffer (column% u) Address Has Changed! / n", Nfield); assert (false);
So if you move the cstring buffer between the cash and update, you must receive an Assert. (Nickshen seems to be the problem here)
This is clear that you can't move the buffer between AddNew and Update. However, according to the results of my and Nickshen privately discussed, he just calls CString member format, wants to convert a floating point number into a string, if you do this, there will be problems, but directly assign a value, is it Format Move CSTRING buffer?
So I followed the CString's format function, found that the process of the Formatv function called by the Format function is like this: first calculate the string of the string after the format string, the string is spent, and then see whether to assign new. Buffer, then sprintf. This learning data structure can be understood. It's very simple, but there is such a problem: in the formatv function, there is such a paragraph (strex.cpp, 659 row) Case 'F': va_arg (arglist, double_ARG); NITEMLEN = 128; // width isn't truncated // 312 == Strlen ("- 1 (309 zeroes).") // 309 Zeroes == Max Precision of a double nitemlen = max (Nitemlen, 312 nPRecision; Break; this is format to formatting % F treatment is in a Switch block. After Switch, // adjust nmaxlen for output Nitemlen Nmaxlen = Nitemlen; ... getBuffer (NMAXLEN);? If you use% f, MFC will conserve your% F will take up the location of 312 characters (it is indeed conservative, as for why 312, the comment is very clear), so use this huge number call GetBuffer. Then CString's Operator = (LPCTSTR), this is more simple, do not have a conservative calculation, how many characters are allocated to all bytes, and through GetBuffer.
In the implementation of GetBuffer, it is simple to see that the original length is not enough, not reassigned enough, then MEMCPY, then, the buffer moves.
Slow! If the length is not enough, you will move the buffer, and both operations will move the buffer, then why only format is wrong, the value is not?
Who said no? You try to give you a string for a length of more than 256, and it is definitely wrong, I have tried it. So, where is this 256? You must use a Recordset first step. It must be Open. Tracking discovery, one step in Open is BindfieldTocolumns (DBCore.cpp 3854), after a series of distributions, the program has been DBRFX.CPP 777: Case CfieldTocolumn :: BindfieldTocolumn: ... // constrain to user specified max length, Subject To 256 byte minif (cbColumn> (UINT) nMaxLength || cbColumn <256) cbColumn = nMaxLength; // Set up binding addresvoid * pvData; value.GetBufferSetLength (cbColumn 1); pvData = value.LockBuffer (); // will be Overwritten if unicode, how much this nmaxlength is this NMAXLENGTH? This look at the declaration of RFX_Text in Afxdb.h, 255! understood?
This is clear, all everything is caused by the inside of the MFC, because we will not insert a string that exceeds 255 in the database (in fact access and SQL Server support " 255 characters), therefore do not have problems, but the engineers of the MFC are conserved when doing the format function, so as long as you use% F format, there is no problem. I know the reason, the solution is very simple: 1. If you can change the database, change the String (varchar) type of field to Double. 2, if you don't have this permission, or too much data can no longer change, then you only have to return, first define a buffer, sprintf, and assign the value to cstring.
It is really troublesome.
The same procedure, then the VC7 is debugged without problems, and if you have time to track it. The mfc7.1 CString has been completely rewritten ...