徐州浦发银行5点后上班:WinCE下常用但缺少的功能函数(UuidCreate、ini文件操作)

来源:百度文库 编辑:偶看新闻 时间:2024/04/29 08:22:22
http://hrybird.bokee.com/viewdiary.16230696.html 2007.7.1 18:12 作者:peng 

最近两周,在做一个项目的移植,大部分时间是比较幸运的,大部分的API都被支持,多是一些VS2005语法要求更为严格后的一些常见错误,另外就是CE对完成例程的不支持,改为Select模型也就可以了,再就是ARM CPU平台下常见的内存对齐问题和据说也是常见的模板的兼容性问题。总的来说还是比较幸运的。
 
在此中间有两个小的问题,一个是WinCE下没有Ini文件的操作API,再就是没有UuidCreate函数创建通用的GUID。这两个问题都是比较普通常见的操作,于是开始我没有太重视,以为随便一搜索网上就会有一堆的现成代码可用,因为太普通了。但事实证明我是错误的,至少ini操作比较完善的工具函数我就没有找到合适的,GUID的创建倒是有个C#的版本,但C版本也没有见到,后来想,可能是目前做手机开发的资源和人还是较少吧。
 
后来就不得不放弃自己懒惰的想法了,没办法,既然没有就自己实现了。实际上我还是倾向于使用现成代码的,因为代码虽然简单不多,但自己写的话测试和调试还是有些费事,要保证可靠性还可能要考虑到一些自己可能会有些地方考虑不到,综合别人的代码可以弥补这些不足。现在我花了些时间实现,并基本详细测试过了,所以也就拿出来共享一下,以让后面用到的人能够比我现在能省事些,毕竟一直以来大都是从互联网拿,自己给予的太少,如果都和我这样,估计就比较可怕了,也该拿出些东西来了,否则心里老是不安。
 
首先是创建GUID,这个主要的一点是尽可能和WinAPI的特性保持一致,否则可能会有重复的风险,这是一个难点,所以主要是要参考Rfc和MSDN,代码如下:
 
//------------------------------------------------------------------------------
//  Win CE下生成Guid的文件:由于Win CE下不支持UuidCreate函数,因此创建Uuid需要
//  自己实现,仅仅用随机数的方式不能保证同其它系统(PC)下的兼容性。从MSDN上找到
//  了Guid的实现算法,据文档中描述,算法保持了同PC下的基本一致性。    
//  
//  参考:http://msdn2.microsoft.com/en-us/library/aa446557.aspx
// 
//------------------------------------------------------------------------------
#pragma once
#include
class PocketGuid
{
private:
    // One to three bits of the clock sequence section are used to define the variant, or layout,
    // of the GUID. Windows and the PocketGuid class generate variant type 2 GUIDs.
    enum GuidVariant
    {
        ReservedNCS = 0x00,
        Standard = 0x02,
        ReservedMicrosoft = 0x06,
        ReservedFuture = 0x07
    };
    // The upper four bits of the timestamp section contain the GUID's version that specifies the content of
    // each section. Before Windows 2000, the CoCreateGuid function generated version 1 GUIDs. With Windows 2000,
    // Microsoft switched to version 4 GUIDs, since embedding the MAC address was viewed as a security risk.
    // The PocketGuid class also generates version 4 GUIDs.
    enum GuidVersion
    {
        TimeBased = 0x01,
        Reserved = 0x02,
        NameBased = 0x03,
        Random = 0x04
    };
    class Const
    {
        // number of bytes in guid
    public:
        static const int ByteArraySize = 16;
 
  // multiplex variant info
  static const int VariantByte = 8;
  static const int VariantByteMask = 0x3f;
  static const int VariantByteShift = 6;
  // multiplex version info
  static const int VersionByte = 7;
  static const int VersionByteMask = 0x0f;
  static const int VersionByteShift = 4;
    };
public:
    static HRESULT CreateGuid (GUID & guid)
    {
        HCRYPTPROV hCryptProv = NULL;
        HRESULT hr = S_OK;
 
        // holds random bits for guid
        BYTE  * bits = new BYTE[Const::ByteArraySize];
        if (bits == NULL)
        {
            hr = E_OUTOFMEMORY;
            goto ExitHere;
        }
        // get crypto provider handle
        if (!CryptAcquireContext (&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
        {
            hr = HRESULT_FROM_WIN32 (GetLastError ());
            goto ExitHere;
        }
        // generate a 128 bit (16 byte) cryptographically random number
        if (!CryptGenRandom (hCryptProv, Const::ByteArraySize, bits))
        {
            hr = HRESULT_FROM_WIN32 (GetLastError ());
            goto ExitHere;
        }
        // set the variant
        bits[Const::VariantByte] &= Const::VariantByteMask;
        bits[Const::VariantByte] |= ((int)Standard << Const::VariantByteShift);
        // set the version
        bits[Const::VersionByte] &= Const::VersionByteMask;
        bits[Const::VersionByte] |= ((int)Random << Const::VersionByteShift);       
       
        memcpy (&guid, bits, sizeof (GUID));
  
    ExitHere:
        if (hCryptProv != NULL)
            CryptReleaseContext (hCryptProv, 0);
        if (bits != NULL)
            delete [] bits;
  return hr;
    };
};

 

ini文件操作相关函数,根据我的需要,只实现了4个,代码如下:

 

#ifdef UNDER_CE

//=======================================================================================================
//
//   WinCE下不支持ini文件操作的API,根据MSDN的帮助和Win32下测试的API的特性,模拟实现。测试发现API在不同
//   系统下的特性不完全一致,但区别不大,这里实现的是大部分XP系统下的特性
//  
//=======================================================================================================

#define GetPrivateProfileSectionNames   GetMyProfileSectionNames
#define GetPrivateProfileSection GetMyProfileSection
#define WritePrivateProfileString WriteMyProfileString
#define GetPrivateProfileString GetMyProfileString

BOOL WriteMyProfileString (LPCTSTR section, LPCTSTR keyName, LPCTSTR value, LPCTSTR filePath)
{
    CIniFile iniFile;
    CString str = _T ("");

    CString strSection = section;
    CString strKeyName = keyName;
    CString strValue = value;

    if (!iniFile.Open (filePath, CFile::modeRead | CFile::modeCreate | CFile::modeNoTruncate))
        return FALSE;

    CStringArray strArray;
    while (iniFile.ReadLine (str))
    {
        strArray.Add (str);
    }
    iniFile.Close ();

    BOOL foundKey = FALSE;
    BOOL addValue = FALSE;
    for (int i = 0; i < strArray.GetSize (); i++)
    {
        str = strArray[i];
        str = str.TrimLeft ().TrimRight ();
        if (str.GetAt (0) == ',' || str.GetAt (0) == '#')
            continue;

        if (!foundKey)
        {
            if (str.GetAt (0) == '[' && str.Right (str.GetLength () - 1).TrimLeft ().Find (strSection) == 0)
            {
                foundKey = TRUE;
                if (keyName == NULL)
                {
                    strArray.RemoveAt (i);
                    i --;
                }
            }
        }
        else
        {
            // enter new key's area
            if (str.GetAt (0) == '[')
            {
                if (keyName != NULL)
                {
                    strArray.InsertAt (i, strKeyName + _T ("=") + strValue + _T ("\r"));
                    addValue = TRUE;
                }
                break;
            }
            else if (keyName == NULL)
            {
                strArray.RemoveAt (i);
                i --;
            }
            else if (str.Find (strKeyName) == 0)
            {
                CString rightValue = str.Right (str.GetLength () - strKeyName.GetLength ()).TrimLeft ();
                if (rightValue.Find (_T ("=")) == 0)
                {
                    if (value != NULL)
                    {
                        strArray[i] = strKeyName + _T ("=") + strValue + _T ("\r");
                        addValue = TRUE;
                    }
                    else
                    {
                        strArray.RemoveAt (i);
                    }
                    break;
                }
            }
        }
    }
   
    if (!addValue && keyName != NULL && value != NULL)
    {
        if (!foundKey)
            strArray.Add (_T ("[") + strSection + _T ("]") + _T ("\r"));
        strArray.Add (strKeyName + _T ("=") + strValue + _T ("\r"));
    }

    if (!iniFile.Open (filePath, CFile::modeCreate | CFile::modeWrite))
        return FALSE;

    for (int i = 0; i < strArray.GetSize (); i++)
    {
        iniFile.WriteString (strArray[i]);
    }
    iniFile.Close ();
 
    return TRUE;
}

void GetMyProfileString (LPCTSTR  section, LPCTSTR keyName, LPCTSTR defaultStr, CString & returnedStr, LPCTSTR fileName)
{
    CString strSection = section;
    CString strKeyName = keyName;
    returnedStr = defaultStr;
   
    if (strSection == _T ("") || strKeyName == _T (""))
        return;

    CIniFile iniFile;
    CString str = _T ("");

    if (!iniFile.Open (fileName, CFile::modeRead))
        return;

    BOOL foundKey = FALSE;
    while (iniFile.ReadLine (str))
    {
        str = str.Trim ();
        if (str.GetAt (0) == ',' || str.GetAt (0) == '#')
            continue;

        if (!foundKey)
        {
            if (str.GetAt (0) == '[' && str.Right (str.GetLength () - 1).TrimLeft ().Find (strSection) == 0)
                foundKey = TRUE;
        }
        else
        {
            // enter new key's area
            if (str.GetAt (0) == '[')
            {
                foundKey = FALSE;
                break;
            }           
            else if (str.Find (strKeyName) == 0)
            {
                CString rightValue = str.Right (str.GetLength () - strKeyName.GetLength ()).TrimLeft ();
                if (rightValue.Find (_T ("=")) == 0)
                {
                    returnedStr = rightValue.Right (rightValue.GetLength () - 1).Trim ();
                    break;
                }
            }
        }
    }
    iniFile.Close ();
}


DWORD GetMyProfileString (LPCTSTR  section, LPCTSTR keyName, LPCTSTR defaultStr, LPTSTR returnedString, DWORD size, LPCTSTR filePath)
{
    if (returnedString == NULL || size == 0)
        return 0;

    if (size == 1)
    {
        returnedString[0] = '\0';
        return 0;
    }

    CString str = _T ("");
    GetMyProfileString (section, keyName, defaultStr, str, filePath);

    DWORD available = size - 1;

    if (available < (DWORD)str.GetLength ())
        str = str.Left (available);

    wcscpy_s (returnedString, size, str.GetBuffer ());
    int allocSize = str.GetLength (); 

    returnedString[allocSize + 1] = '\0';
    return allocSize;
}

DWORD GetMyProfileSectionNames (LPTSTR returnBuffer, DWORD size,  LPCTSTR fileName)
{   
    if (returnBuffer == NULL || size == 0)
        return 0;
    if (size <= 2)
    {
        returnBuffer[0] = '\0';
        return 0;
    }

    CIniFile iniFile;
    if (!iniFile.Open (fileName, CFile::modeRead))
    {
        returnBuffer[0] = '\0';
        return 0;
    }

    CString str = _T ("");
    DWORD allocSize = 0;
    DWORD available = size - 1;
    while (iniFile.ReadLine (str) && available > 1)
    {
        str = str.Trim ();
        if (str.GetAt (0) == ',' || str.GetAt (0) == '#')
            continue;

        if (str.GetAt (0) == '[')
        {
            CString section = str.Right (str.GetLength () - 1).Trim ();
            int pos = section.Find (_T ("]"));
            if (pos >= 0)
                section = section.Left (pos).Trim ();

            if (available < (DWORD)section.GetLength ())
                section = section.Left (available - 1);

            wcscpy_s (returnBuffer + allocSize, size - allocSize, section.GetBuffer ());
            int curAlloc = section.GetLength () + 1; 
            allocSize += curAlloc; 
            ASSERT (available >= (DWORD)curAlloc);
            available -= curAlloc;
        }
    }             
    returnBuffer[allocSize] = '\0';
    return allocSize > 1 ? allocSize -1 : 0;
}

DWORD GetMyProfileSection (LPCTSTR section, LPTSTR returnedString, DWORD size, LPCTSTR fileName)
{
    if (returnedString == NULL || size == 0 || section == NULL)
        return 0;

    if (size <= 2)
    {
        returnedString[0] = '\0';
        return 0;
    }

    CIniFile iniFile;
    if (!iniFile.Open (fileName, CFile::modeRead))
    {
        returnedString[0] = '\0';
        return 0;
    }
    CString strSection = section;

    CString str = _T ("");
    DWORD allocSize = 0;
    DWORD available = size - 1;
    BOOL  foundKey = FALSE;
    while (iniFile.ReadLine (str) && available > 1)
    {
        str = str.Trim ();
        if (str.GetAt (0) == ',' || str.GetAt (0) == '#')
            continue;

        if (!foundKey)
        {
            if (str.GetAt (0) == '[' && str.Right (str.GetLength () - 1).TrimLeft ().Find (strSection) == 0)
                foundKey = TRUE;
        }
        else
        {
            // enter new key's area
            if (str.GetAt (0) == '[')
            {
                foundKey = FALSE;
                break;
            }    

            CString entry = _T ("");
            int pos = str.Find (_T ("="));
            if (pos >= 0)
            {
                CString left = str.Left (pos).Trim ();
                CString right = str.Right (str.GetLength () - pos - 1).Trim ();
                entry = left + _T ("=") + right;
            }
            else
            {
                entry = str;
            }

            if (available < (DWORD)entry.GetLength ())
                entry = entry.Left (available - 1);

            wcscpy_s (returnedString + allocSize, size - allocSize, entry.GetBuffer ());
            int curAlloc = entry.GetLength () + 1; 
            allocSize += curAlloc; 
            ASSERT (available >= (DWORD)curAlloc);
            available -= curAlloc;
        }
    }             
    returnedString[allocSize] = '\0';
    return allocSize > 1 ? allocSize -1 : 0;
}

//=======================================================================================================
#endif   //UNDER_CE

 

 

这里用到了读文件的函数,每次读一行,开始使用了CStdioFile的ReadString,PC下已经测试通过了,但真正到了手机上发现受骗了,呵呵,手机上的ReadString的特性变了,具体可以查看MFC中的源码,粗略读了一下它的代码,似乎CE下ReadString的特性是:如果文件大小不足128,则全部读出,否则只读一行;也就是可能超过一行,所以不符合需求了。于是简单的自己写了一个能支持真正读一行的类:

 

 


#ifdef UNDER_CE
class CIniFile : public CStdioFile
{
public:
    CIniFile() {}
    ~CIniFile() {}

    BOOL ReadLine (CString& rString)
    {
        ASSERT_VALID(this);

        ULONGLONG nStartPosition = CFile::GetPosition();
        bool fEndOfFile = false;

        rString = _T("");    // empty string without deallocating
        const int nMaxSize = 128;
        LPTSTR lpsz = rString.GetBuffer(nMaxSize);
        int nLen = 0;
        for (;;)
        {
            // Reading is not buffered, just let the internal OS buffer handle it.
            UINT nRead = CFile::Read(
             reinterpret_cast(lpsz),
             (nMaxSize)*sizeof(*lpsz) // convert from characters to bytes
             );

            nRead /= sizeof(*lpsz); // convert from bytes to characters

            if(nRead != nMaxSize)
            {
                // reached end of file, terminate the string here.
                fEndOfFile = true;
                //nLen = nRead;
                //break;
            }

            // check for end of line character
            for(nLen = 0 ; nLen < static_cast(nRead) && lpsz[nLen] != '\n' ; ++nLen)
                ;

            if(lpsz[nLen]=='\n')
            {
                // nLen is correct location of end of line, which should be replaced with a null terminator
                fEndOfFile = false;
                break;
            }

            if (fEndOfFile)
            {
                nLen = nRead;
                break;
            }

            rString.ReleaseBuffer();

            nLen = rString.GetLength();
            lpsz = rString.GetBuffer(nMaxSize + nLen) + nLen;
        }

        lpsz[nLen] = '\0';
        rString.ReleaseBuffer();

        nLen = rString.GetLength();

        // Reset the file pointer to the position immediately after the end of line character
        if(!fEndOfFile)
        {
            CFile::Seek(nStartPosition + (nLen + 1) * sizeof(TCHAR), begin);
        }
        return nLen != 0;
    }
};
#endif

 

你可以通过这个链接引用该篇文章:http://hrybird.bokee.com/viewdiary.16230696.html

 (#)