superkind
5/16/2019 - 6:45 AM

CString::Format 대체

https://groups.google.com/d/msg/microsoft.public.pocketpc.developer/oaAgvrjgl8k/Q0rlSzU4wL4J

	nor...@googlegroups.com	
12/27/05

Hi.
I have "ported" an app from eVC4 to VS2005, and everything compiles and works somewhat OK. But there seems to be some changes in the CString::Format method.

1. It is limited to 1025 characters. Any longer, and it truncates. If I just add several strings to eachother using '+', the resulting string can be far larger than 1025, so it must be the Format function itself. This is a major problem, is there a fix?

2. Some Format statements that worked in eVC4 no longer works. I have a statement with 13 %'s and the first 10 are inserted OK, but number 11 is just wrong, and 12 and 13 seems offset by one.

Does anyone know about this? I guess I have to make my own CString-based class and override the Format function if there is no way to fix this.

Best regards,
Ole-Johan Ellingsen

Click here to Reply

buzz	
12/28/05
We just got done fighting the problem with Format in our port from eVC4 
to WM5.  It appears that MFC8 is using the "safe" versions of sprintf, 
and there is no apparent way of disabling this (compiler switches).
Here is the class that I wrote to get around the problem.  (BTW....I 
haven't noticed your item #2...yet).

HERE IS THE HEADER FILE
//------------------------------------------------------------------------------
#pragma once
#include "strsafe.h"

class CPCString
{
public:
        CPCString(void);
        virtual ~CPCString(void);

        bool Format(const TCHAR* format, ...);
        TCHAR* GetBuffer() { return _buf; }

private:
        TCHAR* _buf;

        int getBufferSize(const TCHAR* format, va_list args);
};


HERE IS THE CPP FILE
//------------------------------------------------------------------------------
#include "StdAfx.h"
#include "PCString.h"

//------------------------------------------------------------------------------
//
// Constructor
//
//------------------------------------------------------------------------------
CPCString::CPCString(void): _buf(NULL)
{
}

//------------------------------------------------------------------------------
//
// Destructor
// Destroy the internal string buffer as we go out of scope
//
//------------------------------------------------------------------------------
CPCString::~CPCString(void)
{
        if(_buf)
        {
                delete _buf;
                _buf = NULL;
        }
}

//------------------------------------------------------------------------------
//
//
//------------------------------------------------------------------------------
bool CPCString::Format(const TCHAR* format, ...)
{
        bool res = true;
        
        size_t bufLength = 0;
        LPTSTR pEnd = NULL;
        size_t chRemaining = 0;
        DWORD flags = STRSAFE_NULL_ON_FAILURE | STRSAFE_IGNORE_NULLS;
        HRESULT hr = S_OK;

        // Create the variable arguement list and initialize
        va_list args;
        va_start(args, format);

        // Calculate how much buffer we will need based on the length of the
        // format string and the size of the arguements
        bufLength = getBufferSize(format, args);

        // Reset the arguement pointer back to the beginning
        va_start(args, format);

        // Create a buffer large enough to hold our formatted string
        _buf = new TCHAR[bufLength];
        if(_buf == NULL)
        {
                // Something bad happened....bail
                return false;
        }

        // Clear the buffer
        memset((void*)_buf, 0, bufLength);

        // Call the safe sprintf for format the string into the given buffer
        hr = StringCchVPrintfEx(_buf, bufLength, &pEnd, &chRemaining, flags, 
format, args);

        // Make sure everything is ok
        if(FAILED(hr))
        {
                res = false;
        }

        return res;
}

//------------------------------------------------------------------------------
//
// Calculates the size of the buffer (in TCHAR) that is needed to hold the
// formatted string based on arguement types (lengths).
//
//------------------------------------------------------------------------------
int CPCString::getBufferSize(const TCHAR* format, va_list args)
{
        const int NON_STRING_LENGTH = 32;
        const int ROUNDING_LENGTH = 256;

        TCHAR ch;

        // Initialize the length to the length of the format string. We know we 
will
        // need at least that much buffer.
        int length = _tcslen(format);

        // Set pointers to the beginning and end of the format string
        TCHAR* p = (TCHAR*)format;
        TCHAR* pEnd = p + length;

        // Loop thru the format string
        while(p < pEnd)
        {
                // If we find a formatter...
                if(*p == _T('%'))
                {
                        // Get the format type
                        ch = *(p + 1);

                        // Make sure the user is not just printer a percent ('%%')
                        if(ch != _T('%'))
                        {
                                // Check for string format types
                                if((ch == _T('s')) || (ch == _T('S')))
                                {
                                        // We found a string type, so get the string length of the
                                        // corresponding arguement and add it to the overall length
                                        length += _tcslen(va_arg(args, TCHAR*));
                                }
                                else if((ch == _T('e')) || (ch == _T('E')) || (ch == _T('f')) ||
                                            (ch == _T('g')) || (ch == _T('G')))
                                {
                                        // We found a real type, so grab its arguement and throw it away.
                                        // Add a fixed amount for this type to the overall length
                                        va_arg(args, double);
                                        length += NON_STRING_LENGTH;
                                }
                                else
                                {
                                        // We found an integer type, so grab its arguement and throw it away.
                                        // Add a fixed amount for this type to the overall length
                                        va_arg(args, int);
                                        length += NON_STRING_LENGTH;
                                }
                        }

                        // Skip of the format type
                        p++;
                }

                // Examine the next character in the format string
                p++;
        }

        // Make the overall length a nice multiple of ROUNDING_LENGTH
        length = length + (ROUNDING_LENGTH - (length % ROUNDING_LENGTH));

        return length;
}

USE WITH CAUTION....

- show quoted text -