October 12, 2004
I am using VC++ 6.0 and have a multi-threaded application (exe & multiple DLLs)
which seem
to be having a
CMemFile object getting clobbered when running in release mode.
It does not happen in debug mode.

When running in the debugger,
the calling thread that builds the memory file reports:
GetPosition = 0
GetLength = 228
ptr to memfile = aa2238

the method GetTextLineNOF is passed a ptr to CMemFile and reports:
GetPosition = 0
GetLength = 228
ptr to memfile = aa2238
Which agrees as expected.

====

However when running in RELEASE mode:
the calling thread that builds the memory file reports:
GetPosition = 0
GetLength = 228
ptr to memfile = 7ccd10

the method GetTextLineNOF is passed a ptr to CMemFile and reports:
GetPosition = 8cf829 WHICH IS WRONG!
GetLength = IT appears to be blowing up on this call to GetLength with access
violation
ptr to memfile = 7ccd10


Here are two code snippets.  Note that each is in its own DLL!

Input file can be any random file even 5 lines long created in notepad.

// ZZZ.cpp : Defines the entry point for the DLL application. //

#include "stdafx.h"
#include "TWC.h"
#include <afxinet.h>
#include "atlbase.h"
#include "generator.h"
#include <wininet.h>



#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif



/***************************************************************/ // Define Constants /***************************************************************/

// Boolean Constants

#define SUCCESS			1			//  Boolean TRUE
#define NOTSUCCESSFUL	0			//  Boolean FALSE

// Registry Constants

#define REGISTRYBASE	HKEY_LOCAL_MACHINE
#define YYYGENPATH		"SYSTEM\\\\CurrentControlSet\\\\Services\\\\xyz"

#define CHECKTIME		60000

#define TEXTLINE_SIZE	256			// For buffers receiving GetTextLineNOF output



/***************************************************************/ // Function prototypes. /***************************************************************/

BOOL SetPageValues(CMemFile* brMemFile);
CString PullField(CString csLine, int nField, char cDelimiter);
CString MakeProperName(CString csOld);
CString GetFullDayName(CString csShortDay);

char * GetTextLine(CMemFile* file, char *pchResult);
char * GetTextLineNOF(CMemFile* file, char *pchResult, long maxlen);

BOOL UnZipFile(LPCTSTR ZipFileName);


/***************************************************************/
//  Global Declarations
/***************************************************************/

// Common Globals

CString Temp = _T("");
CString TemplatePath = _T("");
CString TempPath = _T("");
CString	LogPath = _T("");

// Specific Globals

CString	Logging = _T("");
CString	OutputFileName = _T("");
CString	RunTimes = _T("");
CString	TemplateFileName = _T("");
CString PageDataPath = _T("");
CString City = _T("");
CString csConfigPath = _T("");
int		OutputLocationNumber = 0;
CString	*OutputLocations = NULL;
int		CityLocationNumber = 0;
CString	*CityLocations = NULL;
CTime	LastRun = CTime(0);

ARGLIST Events = {0};
char	ClientName[255] = "";

/***************************************************************/
//  Function Declarations
/***************************************************************/

void DllExport __cdecl PROBLEMThread(ARGLIST &threadParm)
{
CString			csError = _T("");
char			szLine[1024] = "";
CString			ZZZConfigPath = _T("");
BOOL			FTPGrabFile = FALSE;
char			TextLineBuf[TEXTLINE_SIZE] = ""; //placeholder for GetTextLineNOF

//DebugBreak();
try
{
// Get the Computer Name

GetComputerName(ClientName);
MyOutputDebugString(1, "PROBLEM : PROBLEM Thread Starting \n");
Events = threadParm;
MyOutputErrorString(1, "6100,xxx, %s, PROBLEM: Starting PROBLEM Page
Generation\n", ClientName);

char szFilePath[_MAX_PATH] = "";
char * ModuleName = NULL;
HMODULE ModuleHandle = NULL;
ModuleName = "ZZZ.dll";

// Get a handle to the DLL Library.

ModuleHandle = GetModuleHandle(ModuleName);

// Retrieve the path to the DLL.

GetModuleFileName(ModuleHandle, szFilePath, sizeof(szFilePath));

CString csDLLPath = _T("");
csDLLPath = szFilePath;

// Strip the path to the DLL off in order to figure out the path to the config file.

csConfigPath = csDLLPath.Left(csDLLPath.ReverseFind('\\'));

// Build the path to the config file.

ZZZConfigPath.Format("%s\\ZZZ.cfg", csConfigPath);

// Check to see if I should run every CHECKTIME

do
{

FTPGrabFile = FALSE;
MyOutputDebugString(1, "PROBLEM : Checking Page RunTimes for update \n");

MyOutputDebugString(1, "PROBLEM : Opening %s for reading into memory file
\n",ZZZConfigPath);

// Open the ZZZ Configuration file for Reading.

CStdioFile cfInfile(ZZZConfigPath, CFile::modeRead | CFile::typeText |
CFile::shareDenyNone);

// Create a Memory File which will contain the ZZZ config file

CMemFile* brMemFile = new CMemFile;

// Read from the ZZZ Configuration File

while (cfInfile.ReadString(szLine, 1024) != NULL)
{
// Write to the Memory File

brMemFile->Write(szLine, strlen(szLine));
}

// Close the ZZZ Configuration File

cfInfile.Close();

// Seek to the Beginning of the Memory File

brMemFile->SeekToBegin();

//for debugging write out the CMemFile statistics

DWORD dwPos = brMemFile->GetPosition();
MyOutputDebugString(1, "PROBLEM : CMemFile position = %x\n",dwPos);
DWORD dwLen = brMemFile->GetLength();
MyOutputDebugString(1, "PROBLEM : CMemFile length = %x\n",dwLen);
MyOutputDebugString(1, "PROBLEM : ptr to CMemFile  = %x\n", brMemFile);

// Set up the Global Values

MyOutputDebugString(1, "PROBLEM : Making first call to GetTextLineNOF\n");

TemplatePath = GetTextLineNOF(brMemFile, TextLineBuf, sizeof(TextLineBuf));

BLAHBLAHBLAH

----
And here is the method being called:

char * GetTextLineNOF(CMemFile* file, char *pchResult, long maxlen)
{
// PURPOSE: Read a single line of text from the memory file (which usually
contains a
//			*.cfg file).  Store the line into the array pointed to by pchResult.  It is
//			the responsibility of the caller to properly set maxlen to the size of the
//			array pointed to by pchResult so that buffer overflows are prevented.
//			Any comments in the memory file (indicated with a leading ~) will be
ignored
//			and not returned by this method.  Lines in the memory file are terminated
//			with CRLF (ie. Hex 0D0A) but when read in only 0A is returned by
//			file->Read(&iChar, 1);.

// NOTE: There are 6 formats of valid lines in the memory file as follows:
//			1. ~Comment
//			2. leading blanks + ~Comment
//			3. data line starting in column 0
//			4. leading blanks + data line
//			5. leading blanks + data line + ~comment
//			6. data line starting in column 0 + ~Comment
//
// RETURNS: String with leading blanks and trailing comments removed.
//			Lines that only contain CRLF will be ignored.
//			Lines containing only blanks will be ignored.

char	iChar = '\0';
char	skipChar = '\0';// throw away this char because buffer is full
int		iColumn = 0;	// number of chars copied to pchResult
char *pchTemp;	// use this to march across the array 1 char at a time

MyOutputDebugString (1,  "Inside GetTextLineNOF \n");

//for debugging

MyOutputDebugString(1, "PROBLEM : ptr to CMemFile  = %x\n", file);

MyOutputDebugString (1,  "GetTextLineNOF - just after accessing file \n");
DWORD dwPos = file->GetPosition();
MyOutputDebugString (1,  "GetTextLineNOF - just after calling GetPosition \n");
MyOutputDebugString (1,  "GetTextLineNOF: CMemFile pos = %x \n", dwPos);

DWORD dwLen = file->GetLength();
MyOutputDebugString (1,  "GetTextLineNOF - just after calling GetLength \n");

MyOutputDebugString (1,  "GetTextLineNOF: CMemFile len = %x \n", dwLen);

pchTemp = pchResult;
MyOutputDebugString (1,  "after first line GetTextLineNOF \n");

try
{

// loop, until we have something to return (iColumn>0)

while ( TRUE )
{

BOOL IgnoreThisChar = FALSE;
BOOL endOfFile = FALSE;	//whether we have read entire memory file

// Loop until we hit a CR (decimal 10) or the end of the file

if ( file->GetPosition() >= file->GetLength() )
endOfFile = TRUE;

if ( !endOfFile )
{
do
{
file->Read(&iChar, 1);

// Store the character read from memfile UNLESS a comment or leading blank

if ( iChar == '~' )
{
// set to ignore everything after the comment flag

IgnoreThisChar = TRUE;

//if comment is on a data line, then terminate string here

if (iColumn > 0)
{
MyOutputDebugString (1,  "GetTextLineNOF Terminating string");
*(pchTemp+iColumn) = '\0';
iColumn++;
}

}
else if ((iChar == ' ') && (iColumn == 0))
{
continue; //skips over leading blanks
}
else if (!IgnoreThisChar) //valid char to return or CRLF
{
// add the character to the return value if not a comment or leading blank

if ( iChar != 10 )
{
// check for buffer overflow
// the minus 1 is to allow for nul stored at bottom of this method

if (iColumn >= maxlen - 1)
{
// if this will overflow - do not store char AND

*(pchTemp+iColumn) = '\0';
iColumn++;

// - write error msg AND

// - skip over the end of the line AND

do
{
file->Read(&skipChar, 1);
if ( file->GetPosition() >= file->GetLength() )
endOfFile = TRUE;
} while (!endOfFile && skipChar != 10 );

// try to return the next line

}
else // store the char
{
*(pchTemp+iColumn) = iChar;
iColumn++;
//MyOutputDebugString (1,  "GetTextLineNOF Assigning char = %c\n",iChar);
}
}
else // iChar == 10
*(pchTemp+iColumn) = '\0'; // hit LF in mem file so terminate string
} //END else the character was stored for return

if ( file->GetPosition() >= file->GetLength() )
endOfFile = TRUE;

//					MyOutputDebugString(4, "iChar = %c\n", iChar);

} while (!endOfFile && iChar != 10 && skipChar !=10);
} //END if (!endOfFile)

if (endOfFile)
{
*(pchTemp+iColumn) = '\0';
iColumn++;
}

// check the return value, if it is not empty then return everything
// before we hit the comment flag.  Else continue to loop, until we have
// something to return

if (iColumn > 0)
{
break;
//	MyOutputDebugString(4, "IgnoreThisChar = FALSE\n");
}
//else
//	MyOutputDebugString(4, "IgnoreThisChar = TRUE\n");
} //END while TRUE

//MyOutputDebugString(4, "%s\n", szLine);
} //END try block
catch ( CException* e )
{
TCHAR   szCause[255] = _T("");
e->GetErrorMessage(szCause, 255);
//MyOutputDebugString (1, "xxx: %s\n", szCause );
e->Delete();
exit(0);
}

MyOutputDebugString (1,  "GetTextLineNOF Returning string %s \n",pchResult);

return pchResult;
}

=======

Any ideas on how to solve the access violation problem in release mode???

Thanks!

malhenry
November 24, 2004
"malhenry" <malhenry_member@pathlink.com> wrote in message news:ckhdm7$1d8t$1@digitaldaemon.com...
>
> I am using VC++ 6.0

There's the problem! You should be using Digital Mars C++!

<g>