徐州浦发银行5点后上班:WinCE下常用但缺少的功能函数(UuidCreate、ini文件操作)
来源:百度文库 编辑:偶看新闻 时间:2024/04/29 08:22:22
最近两周,在做一个项目的移植,大部分时间是比较幸运的,大部分的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
(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
;
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
(#)