做网站百度还是阿里巴巴好,韩国电商网站排名,网站开发用什么,网站微信支付怎么做在上篇文章开发 windows mobile 上的今日插件时#xff0c;我发现 wince 平台上不支持例如 GetPrivateProfileString 等相关 API 函数。在网络上我并没有找到令我满意的相应代码#xff0c;因此我手工自己写了相应的方法。命名规则是#xff0c;在 PC API 函数的名称前面加上…在上篇文章开发 windows mobile 上的今日插件时我发现 wince 平台上不支持例如 GetPrivateProfileString 等相关 API 函数。在网络上我并没有找到令我满意的相应代码因此我手工自己写了相应的方法。命名规则是在 PC API 函数的名称前面加上 “Ce” 前缀这是为了在 PC 平台上调试和使用时不和系统的 API 函数发生冲突。值得注意的是在写 CeWritePrivateProfileString 方法时如果改写后的 ini 文件应该比改写前的文件小文件尾部将会是一些不确定内容来自于原来文件。在 PC 上我们可以通过 io.h 中的 _chsize 函数重新设置文件大小但是很遗憾的是这些底层的文件操作函数在 wince 平台上依然不被支持但是幸运的是可以使用 coredll.dll 中提供的 SetEndOfFile 函数去完成相同功能感谢88上的 kghost 的提示。 另外我额外提供了一个函数CeGetPrivateProfileKeyNames用于读取某个 section 的所有 key 名称。 当然如果是在 PC 平台我们就没有必要使用这里我所提供的代码因为有系统 API 可以调用。 需要注意的是我提供的代码和 PC 端 API 相比基本功能参数意义完全相同但具有以下一些额外要求 1大小写敏感。当然也可以通过修改代码令其大小写不敏感 2每一行section key value “” 的前后不允许有空格。 3注释行用英文分号“;起始。允许存在空行。 4每一行的字符数不能超过 260 字符取决于代码中的宏定义。 5函数代码同时适用 unicode 和多字节字符串 的环境。 6由于采用标准文件操作函数因此 CeGetPrivateProfileSectionNames 函数并不保证原子性。这一点和 PC API 不同 下面是相关函数代码 (a) IniFile.h /*************************************** * IniFile.h * 说明在WinCe平台读写 INI 文件 * by hoodlum1980 * 2009.08.03 ***************************************/ #ifndef __INIFILE_H_BY_HOODLUM1980 #define __INIFILE_H_BY_HOODLUM1980 //是否在WINCE平台上 #ifndef WINCE #define WINCE #endif #include StdAfx.h #ifndef WINCE #include io.h //for _sopen #include fcntl.h //for _O_RDWT #include share.h // for _SH_DENYRW #endif #ifdef UNICODE // r_winnt #define t_sopen _wsopen //注意WinCe上不支持 #define t_fopen _wfopen #define t_fgets fgetws #define t_fprintf fwprintf //文件格式化写入 #define t_sprintf swprintf //格式化文本 #define t_strcpy wcscpy #define t_strncpy wcsncpy //拷贝指定个数的字符 #define t_strcat wcscat //append a string #define t_strtol wcstol #define t_strlen wcslen #define t_strcmp wcscmp #define t_stricmp _wcsicmp //忽略大小写的字符串比较 #define t_strncmp wcsncmp //比较n个字符 #define t_strchr wcschr //find a character in a string #define t_strrchr wcsrchr //从结尾向前查找字符 #else //ASCII CODE #define t_sopen _sopen //注意WinCe上不支持 #define t_fopen fopen #define t_fgets fgets //读取一行文本 #define t_fprintf fprintf //文件格式化写入 #define t_sprintf sprintf //格式化文本 #define t_strcpy strcpy #define t_strncpy strncpy //拷贝指定个数的字符 #define t_strcat strcat //append a string #define t_strtol strtol //把字符串转换成longint32 #define t_strlen strlen #define t_strcmp strcmp //比较字符串 #define t_stricmp _stricmp //忽略大小写的字符串比较 #define t_strncmp strncmp //比较n个字符 #define t_strchr strchr //查找字符 #define t_strrchr strrchr //从结尾向前查找字符 #endif //CeWritePrivateProfileString 方法用到的辅助标记 #define MODE_DELETE_SECTION 11 #define MODE_OVERWRITE_SECTION 12 #define MODE_APPEND_SECTION 13 #define MODE_DELETE_KEY 21 #define MODE_OVERWRITE_KEY 22 #define MODE_APPEND_KEY 23 #define LINESIZE 260 //行缓冲区大小 DWORD CeGetPrivateProfileString( LPCTSTR lpAppName, //section name: [lpAppName] LPCTSTR lpKeyName, //lpKeyNamelpReturnedString LPCTSTR lpDefault, //未找到时的默认值 LPTSTR lpReturnedString, //[out] 查找到的结果 DWORD nSize, //[in]lpReturnedString的字符数,注意单位不是字节 LPCTSTR lpFileName ); UINT CeGetPrivateProfileInt( LPCTSTR lpAppName, LPCTSTR lpKeyName, int nDefault, LPCTSTR lpFileName ); DWORD CeGetPrivateProfileSection( LPCTSTR lpAppName, LPTSTR lpReturnedString, DWORD nSize, LPCTSTR lpFileName ); DWORD CeGetPrivateProfileSectionNames( LPTSTR lpszReturnBuffer, DWORD nSize, LPCTSTR lpFileName ); //在PC平台上可以调用_chsize函数调整文件大小但是在WINCE平台上 //由于不支持所以必须注意当文件尺寸应该缩小时文件尾部内容不确定 BOOL CeWritePrivateProfileString( LPCTSTR lpAppName, LPCTSTR lpKeyName, //要修改的KEY如果为NULL会删除整个Section LPCTSTR lpString, //要写入的值如果为NULL则会删除这个KEY LPCTSTR lpFileName ); //重写某个Section注意和 PC API 的区别是这里不保证原子性操作 BOOL CeWritePrivateProfileSection( LPCTSTR lpAppName, //section name LPCTSTR lpString, //key1val1 \0 key2val2 \0\0 LPCTSTR lpFileName ); // // 以下是我增加的函数在API中没有 // DWORD CeGetPrivateProfileKeyNames( LPCTSTR lpAppName, LPTSTR lpReturnedString, DWORD nSize, //缓冲区的字符数 LPCTSTR lpFileName ); #endif(b) IniFile.cpp //适用于 char* 和 UNICODE //所有字符串必须使用 TEXT(aa) 或者 _T(aa) 的格式自动适应 char* 或 UNICODE //所有相关函数加t_前缀 //IniFile: 读取INI FILE的简单解析!所谓简单也就是解析代码简单但对文件格式要求更高 //[1]任何字符串前后不要有空格使解析代码可以不考虑前后的trim // 例如允许Key1Val, 而不允许 Key1 Val //[2]允许有注释第一个字符必须是英文分号; // #include StdAfx.h #include IniFile.h //从appnamesection中读取string类型key DWORD CeGetPrivateProfileString( LPCTSTR lpAppName, //section name: [lpAppName] LPCTSTR lpKeyName, //lpKeyNamelpReturnedString LPCTSTR lpDefault, //未找到时的默认值 LPTSTR lpReturnedString, //[out] 查找到的结果 DWORD nSize, //[in]lpReturnedString的字符数,注意单位不是字节 LPCTSTR lpFileName ) { DWORD ret 0; FILE *stream; bool bFindVal false; bool bFindSection false; TCHAR line[ LINESIZE ]; size_t sectionLength, keyLength, lineLength; stream t_fopen(lpFileName, _T(r)); if(stream NULL) { //设置默认值 t_strcpy(lpReturnedString, lpDefault); ret t_strlen(lpReturnedString); return ret; } sectionLength t_strlen(lpAppName); while(t_fgets(line, LINESIZE, stream) ! NULL) { //忽略注释行和空行 if(line[0] 0 || line[0] ;) continue; lineLength t_strlen(line); //注意把LF0xa字符替换成0这在UNICODE环境下可能出现结尾是LF if(line[ lineLength - 1 ] 0x0a) { line[ lineLength - 1 ] 0; lineLength--; //注意此时可能会成为空字符串 if(lineLength 0) continue; } //尝试寻找到 section if(!bFindSection) { if(line[0] ! [) continue; //本行是否是 [section] //这里是我们想要的Section吗 //检查这一行的宽度是否正好是section长度加2 [lpAppName] if(line[sectionLength 1] ! ]) continue; if(t_strncmp(line1, lpAppName, sectionLength) ! 0) continue; //Now Section will appear on next line //读取section前求出 Key 的长度 keyLength t_strlen(lpKeyName); bFindSection true; continue; } //查找Key, Section End? if(line[0][) break; //遇到了下一个 if(lineLength keyLength1 || line[keyLength] ! ) continue; //KeyName if(t_strncmp(line, lpKeyName, keyLength)!0) continue; //Now We Get the Key! t_strcpy(lpReturnedString, line keyLength 1); //Now Its done. bFindVal true; break; } fclose(stream); if(!bFindVal) { //设置默认值 t_strcpy(lpReturnedString, lpDefault); } ret t_strlen(lpReturnedString); return ret; } //读取一个int值 UINT CeGetPrivateProfileInt( LPCTSTR lpAppName, LPCTSTR lpKeyName, int nDefault, LPCTSTR lpFileName ) { long ret nDefault; //返回值 FILE *stream; bool bFindVal false; bool bFindSection false; TCHAR line[ LINESIZE ]; size_t sectionLength, keyLength, lineLength; stream t_fopen(lpFileName, _T(r)); if(stream NULL) { //设置默认值 return nDefault; } sectionLength t_strlen(lpAppName); while(t_fgets(line, LINESIZE, stream) ! NULL) { //忽略注释行和空行 if(line[0] 0 || line[0] ;) continue; lineLength t_strlen(line); //注意把LF0xa字符替换成0这在UNICODE环境下可能出现结尾是LF if(line[ lineLength - 1 ] 0x0a) { line[ lineLength - 1 ] 0; lineLength--; //注意此时可能会成为空字符串 if(lineLength 0) continue; } //尝试寻找到 section if(!bFindSection) { if(line[0] ! [) continue; //本行是否是 [section] //这里是我们想要的Section吗 //检查这一行的宽度是否正好是section长度加2 [lpAppName] if(line[sectionLength 1] ! ]) continue; if(t_strncmp(line1, lpAppName, sectionLength) ! 0) continue; //Now Section will appear on next line //读取section前求出 Key 的长度 keyLength t_strlen(lpKeyName); bFindSection true; continue; } //查找Key, Section End? if(line[0][) break; //遇到了下一个 if(lineLength keyLength1 || line[keyLength] ! ) continue; //KeyName if(t_strncmp(line, lpKeyName, keyLength)!0) continue; //Now We Get the Key! TCHAR *pStopChar NULL; ret t_strtol(line keyLength 1, pStopChar, 10); //默认为10进制 //Now Its done. bFindVal true; break; } fclose(stream); return ret; } //获取某个Section下面的所有“keyvalue”形式的字符串集合以0字符分割 //结尾使用两个0字符 //缓冲区写入key1value1 \0 key2value2 \0 \0 //返回值表示写入缓冲区的字符数, 不包括结尾的0字符。 //如果缓冲区不够容纳所有的键值对则返回值 (nSize-2) DWORD CeGetPrivateProfileSection( LPCTSTR lpAppName, LPTSTR lpReturnedString, DWORD nSize, //缓冲区的字符数 LPCTSTR lpFileName ) { DWORD ret 0; //返回值拷贝的字符数量 DWORD remainSize nSize - 2; //缓冲区当前所能能够接纳的字符数量 DWORD copySize; //本次循环中需要拷贝的字符数量 FILE *stream; bool bFindSection false; //是否已经找到Section TCHAR line[ LINESIZE ]; //行缓冲区 LPTSTR pItem; //指向当前键值对的写入地址 size_t sectionLength, lineLength; pItem lpReturnedString; //指向缓冲区起始地址 stream t_fopen(lpFileName, _T(r)); if(stream NULL) { return ret; } sectionLength t_strlen(lpAppName); while(t_fgets(line, LINESIZE, stream) ! NULL) { //缓冲区是否还有剩余空间 if(remainSize 0) break; //忽略注释行和空行 if(line[0] 0 || line[0] ;) continue; lineLength t_strlen(line); //注意把LF0xa字符替换成0这在UNICODE环境下可能出现结尾是LF if(line[ lineLength - 1 ] 0x0a) { line[ lineLength - 1 ] 0; lineLength--; //注意此时可能会成为空字符串 if(lineLength 0) continue; } //尝试寻找到 section if(!bFindSection) { if(line[0] ! [) continue; //本行是否是 [section] //这里是我们想要的Section吗 //检查这一行的宽度是否正好是section长度加2 [lpAppName] if(line[sectionLength 1] ! ]) continue; if(t_strncmp(line1, lpAppName, sectionLength) ! 0) continue; //Now Section will appear on next line bFindSection true; continue; } //查找Key, Section End? if(line[0][) break; //遇到了下一个 //copy the line to buffer, 注意ncpy不会复制结尾的0字符 copySize min( remainSize, lineLength ); t_strncpy(pItem, line, copySize); //追加一个0字符 pItem[copySize] 0; //缩小缓冲区剩余字符数量remainSize和当前写入位置pItem ret (copySize 1); //加1是为了统计结尾的0字符 remainSize - (copySize 1); pItem (copySize 1); } fclose(stream); if(bFindSection) { //再次对缓冲区追加一个0 字符 *pItem 0; } return ret; } //获取一个ini文件中所有section的name拷贝到缓冲区 //注意和系统API的区别是系统API的读取是原子性的即读取时不允许修改ini文件的内容 //而我们的函数未必保证这一点 DWORD CeGetPrivateProfileSectionNames( LPTSTR lpszReturnBuffer, DWORD nSize, LPCTSTR lpFileName ) { DWORD ret 0; //返回值拷贝的字符数量 DWORD remainSize nSize - 2; //缓冲区当前所能能够接纳的字符数量 DWORD copySize; //本次循环中需要拷贝的字符数量 TCHAR line[ LINESIZE ]; //行缓冲区 TCHAR *pSectionEndChar; //]字符指针 LPTSTR pItem; //指向当前键值对的写入地址 FILE *stream; //流指针 size_t lineLength; //行字符长度 pItem lpszReturnBuffer; //指向缓冲区起始地址 stream t_fopen(lpFileName, _T(r)); if(stream NULL) { return ret; } while(t_fgets(line, LINESIZE, stream) ! NULL) { //缓冲区是否还有剩余空间 if(remainSize 0) break; //忽略注释行和空行 if(line[0] 0 || line[0] ;) continue; lineLength t_strlen(line); //注意把LF0xa字符替换成0这在 UNICODE 环境下可能出现结尾是LF if(line[ lineLength - 1 ] 0x0a) { line[ lineLength - 1 ] 0; lineLength--; //注意此时可能会成为空字符串 if(lineLength 0) continue; } if(line[0] ! [) continue; //本行是否是 [section] //找到了一个Section开始拷贝 //copy the section name to buffer, 注意ncpy不会复制结尾的0字符 //LINE: [sectionName] // | | // line pSectionEndChar //找出‘’字符的位置 pSectionEndChar t_strchr(line, ]); if(pSectionEndChar ! NULL) { //找到了‘’字符pEqualChar - line是key的长度 copySize min( remainSize, pSectionEndChar - line - 1 ); } else { //本行中不存在‘]’字符对于合法文件来说不会出现此种情况 copySize min( remainSize, lineLength - 1 ); } t_strncpy(pItem, line1, copySize); //追加一个0字符 pItem[copySize] 0; //缩小缓冲区剩余字符数量remainSize和当前写入位置pItem ret (copySize 1); //加1是为了统计结尾的0字符 remainSize - (copySize 1); pItem (copySize 1); } fclose(stream); //再次对缓冲区追加一个0 字符 *pItem 0; return ret; } // BOOL CeWritePrivateProfileString( LPCTSTR lpAppName, LPCTSTR lpKeyName, //要修改的KEY如果为NULL会删除整个Section LPCTSTR lpString, //要写入的值如果为NULL则会删除这个KEY LPCTSTR lpFileName ) { FILE *stream; void *pVoid NULL; //文件的后半部分 bool bFindKey false; bool bFindSection false; TCHAR line[ LINESIZE ]; size_t sectionLength, keyLength, lineLength, nBytesRead 0; LONG nInsertPos -1, nCopyPos -1, nFileEndPos, nPos; //文件指针位置 LONG nSectionBegin -1, nKeyBegin -1, nNextKey -1, nNextSection -1; BYTE mode 0; //如果 sectionName 为NULL返回成功 if(lpAppName NULL) return true; //r: Opens for both reading and writing. (The file must exist.) stream t_fopen(lpFileName, _T(r)); if(stream NULL) { return false; } //先取一次mode的默认值 if(lpKeyName NULL) mode MODE_DELETE_SECTION; else if(lpString NULL) mode MODE_DELETE_KEY; else mode MODE_OVERWRITE_KEY; sectionLength t_strlen(lpAppName); //每次读行前保存文件指针位置 while(nPos ftell(stream), t_fgets(line, LINESIZE, stream) ! NULL) { //忽略注释行和空行 if(line[0] 0 || line[0] ;) continue; lineLength t_strlen(line); //注意把LF0xa字符替换成0这在UNICODE环境下可能出现结尾是LF if(line[ lineLength - 1 ] 0x0a) { line[ lineLength - 1 ] 0; lineLength--; //注意此时可能会成为空字符串 if(lineLength 0) continue; } //尝试寻找到 section if(!bFindSection) { if(line[0] ! [) continue; //本行是否是 [section] //这里是我们想要的Section吗 //检查这一行的宽度是否正好是section长度加2 [lpAppName] if(line[sectionLength 1] ! ]) continue; if(t_strncmp(line1, lpAppName, sectionLength) ! 0) continue; //Now Section will appear on next line //读取section前求出 Key 的长度 if(lpKeyName ! NULL) keyLength t_strlen(lpKeyName); nSectionBegin nPos; bFindSection true; continue; } //Section找到了 //Section End ? if(line[0][) { nNextSection nPos; break; //遇到了下一个 } //是否需要查找KEY if(lpKeyName ! NULL) { if(lineLength keyLength1 || line[keyLength] ! ) continue; //KeyName if(t_strncmp(line, lpKeyName, keyLength) ! 0) continue; //Now We Get the Key! nKeyBegin nPos; nNextKey ftell(stream); //要拷贝的起始位置 //Now Its done. bFindKey true; break; } } //如果已经到达文件尾部则追加换行 if(feof(stream)) t_fprintf(stream, _T(\r\n)); if(nNextSection 0) nNextSection ftell(stream); if(nNextKey 0) nNextKey ftell(stream); //遍历后再次更新mode值 if(mode MODE_DELETE_SECTION) { if(!bFindSection) { fclose(stream); return true; } else { nInsertPos nSectionBegin; nCopyPos nNextSection; } } if(mode MODE_DELETE_KEY) { if(!bFindKey) { fclose(stream); return true; } else { nInsertPos nKeyBegin; nCopyPos nNextKey; } } if(mode MODE_OVERWRITE_KEY) { if(!bFindSection) { mode MODE_APPEND_SECTION; } else { if(bFindKey) { nInsertPos nKeyBegin; nCopyPos nNextKey; } else { mode MODE_APPEND_KEY; nInsertPos nNextSection; nCopyPos nNextSection; } } } //追加一个新的Section if(mode MODE_APPEND_SECTION) { t_fprintf(stream, _T(\r\n[%s]\r\n%s%s\r\n), lpAppName, lpKeyName, lpString); fclose(stream); return true; } //先把文件的后半部分拷贝到内存 fseek(stream, 0, SEEK_END); nFileEndPos ftell(stream); if(nCopyPos 0 nCopyPos nFileEndPos) { //分配内存作为缓冲区 pVoid malloc(nFileEndPos - nCopyPos 1); if(pVoid NULL) { fclose(stream); return false; //堆内存不足 } fseek(stream, nCopyPos, SEEK_SET); nBytesRead fread(pVoid, 1, nFileEndPos - nCopyPos 1, stream); } //写入新的value值 fseek(stream, nInsertPos, SEEK_SET); if(lpKeyName ! NULL lpString ! NULL) t_fprintf(stream, _T(%s%s\r\n), lpKeyName, lpString); //现在把文件的后半部分写回文件中 if(pVoid ! NULL nBytesRead 0) { fwrite(pVoid, 1, nBytesRead, stream); free(pVoid); } //此时结尾可能还有一些内容属于原来的ini文件 //我们把它写成注释 nPos ftell(stream); fclose(stream); //如果文件变小了那么我们需要更改文件大小 if(nPos nFileEndPos) { #ifdef WINCE //WINCE平台 HANDLE handle CreateFile( lpFileName, //LPCTSTR lpFileName GENERIC_WRITE, //DOWRD dwDesiredAccess, 0, //DWORD dwShareMode, 非共享模式 NULL, //LPSECURITY_ATTRIBUTES lpSecurityAttributes, ignored OPEN_EXISTING, //DWORD dwCreationDispostion, FILE_ATTRIBUTE_NORMAL, //DWORD dwFlagsAndAttributes, NULL//HANDLE hTemplateFile, ignored ); if(handle ! NULL) { //移动文件指针 SetFilePointer(handle, nPos, NULL, FILE_BEGIN); //设置EOF SetEndOfFile(handle); //关闭 CloseHandle(handle); } #else //PC 平台 int handle t_sopen(lpFileName, _O_RDWR, _SH_DENYRW); if(handle 0) { //修改文件大小 _chsize(handle, nPos); //关闭文件 _close(handle); } #endif // } return TRUE; } //重写某个Section注意和 PC API 的区别是这里不保证原子性操作 BOOL CeWritePrivateProfileSection( LPCTSTR lpAppName, //section name LPCTSTR lpString, //key1val1 \0 key2val2 \0\0 LPCTSTR lpFileName ) { FILE *stream; void *pVoid NULL; //文件的后半部分 bool bFindSection false; TCHAR line[ LINESIZE ]; //行缓冲区 LPCTSTR pItem lpString; size_t sectionLength, lineLength, nBytesRead 0; LONG nFileEndPos, nPos; //文件指针位置 LONG nSectionBegin -1, nNextSection -1; //如果 sectionName 为NULL返回失败 if(lpAppName NULL || lpString NULL) return false; //r: Opens for both reading and writing. (The file must exist.) stream t_fopen(lpFileName, _T(r)); if(stream NULL) { return false; } sectionLength t_strlen(lpAppName); //每次读行前保存文件指针位置 while(nPos ftell(stream), t_fgets(line, LINESIZE, stream) ! NULL) { //忽略注释行和空行 if(line[0] 0 || line[0] ;) continue; lineLength t_strlen(line); //注意把LF0xa字符替换成0这在UNICODE环境下可能出现结尾是LF if(line[ lineLength - 1 ] 0x0a) { line[ lineLength - 1 ] 0; lineLength--; //注意此时可能会成为空字符串 if(lineLength 0) continue; } //尝试寻找到 section if(!bFindSection) { if(line[0] ! [) continue; //本行是否是 [section] //这里是我们想要的Section吗 //检查这一行的宽度是否正好是section长度加2 [lpAppName] if(line[sectionLength 1] ! ]) continue; if(t_strncmp(line1, lpAppName, sectionLength) ! 0) continue; //Now Section will appear on next line nSectionBegin nPos; bFindSection true; continue; } //Section找到了 //Section End ? if(line[0][) { nNextSection nPos; break; //遇到了下一个 } } //如果已经到达文件尾部则追加换行 if(nNextSection 0) nNextSection ftell(stream); //追加一个新的Section if(!bFindSection) { nSectionBegin ftell(stream); } //覆写Section //先把文件的后半部分拷贝到内存 fseek(stream, 0, SEEK_END); nFileEndPos ftell(stream); if(nNextSection 0 nNextSection nFileEndPos) { //分配内存作为缓冲区 pVoid malloc(nFileEndPos - nNextSection 1); if(pVoid NULL) { fclose(stream); return false; //堆内存不足 } fseek(stream, nNextSection, SEEK_SET); nBytesRead fread(pVoid, 1, nFileEndPos - nNextSection 1, stream); } //逐行写入key val fseek(stream, nSectionBegin, SEEK_SET); //再次写入[section]如果不存在就会追加 t_fprintf(stream, _T([%s]\r\n), lpAppName); while(*pItem) { t_fprintf(stream, _T(%s\r\n), pItem); pItem t_strlen(pItem) 1; //移动到下一行 } //现在把文件的后半部分写回文件中 if(pVoid ! NULL) { fwrite(pVoid, 1, nBytesRead, stream); free(pVoid); } //此时结尾可能还有一些内容属于原来的ini文件 //我们把它写成注释 nPos ftell(stream); //当前文件位置 fclose(stream); //如果文件变小了那么我们需要更改文件大小 if(nPos nFileEndPos) { #ifdef WINCE //WINCE平台 HANDLE handle CreateFile( lpFileName, //LPCTSTR lpFileName GENERIC_WRITE, //DOWRD dwDesiredAccess, 0, //DWORD dwShareMode, 非共享模式 NULL, //LPSECURITY_ATTRIBUTES lpSecurityAttributes, ignored OPEN_EXISTING, //DWORD dwCreationDispostion, FILE_ATTRIBUTE_NORMAL, //DWORD dwFlagsAndAttributes, NULL//HANDLE hTemplateFile, ignored ); if(handle ! NULL) { //移动文件指针 SetFilePointer(handle, nPos, NULL, FILE_BEGIN); //设置EOF SetEndOfFile(handle); //关闭 CloseHandle(handle); } #else //PC 平台 int handle t_sopen(lpFileName, _O_RDWR, _SH_DENYRW); if(handle 0) { //修改文件大小 _chsize(handle, nPos); //关闭文件 _close(handle); } #endif // } return TRUE; } // // 以下是我增加的函数API中没有 // // //获取某个section下的所有的Key名 //获取某个Section下面的所有“key形式的字符串集合以0字符分割 //结尾使用两个0字符 //缓冲区写入key1 \0 key2 \0 \0 //返回值表示写入缓冲区的字符数, 不包括结尾的0字符。 //如果缓冲区不够容纳所有的键值对则返回值 (nSize-2) //注意此函数是在桌面 API 中也没有的。而是我单独添加的 // DWORD CeGetPrivateProfileKeyNames( LPCTSTR lpAppName, LPTSTR lpReturnedString, DWORD nSize, //缓冲区的字符数 LPCTSTR lpFileName ) { DWORD ret 0; //返回值拷贝的字符数量 DWORD remainSize nSize - 2; //缓冲区当前所能能够接纳的字符数量 DWORD copySize; //本次循环中需要拷贝的字符数量 bool bFindSection false; //是否已经找到Section TCHAR line[ LINESIZE ]; //行缓冲区 LPTSTR pItem; //指向当前键值对的写入地址 TCHAR *pEqualChar; //等号字符的在行中的位置 FILE *stream; //流指针 size_t sectionLength, lineLength; pItem lpReturnedString; //指向缓冲区起始地址 stream t_fopen(lpFileName, _T(r)); if(stream NULL) { return ret; } sectionLength t_strlen(lpAppName); while(t_fgets(line, LINESIZE, stream) ! NULL) { //缓冲区是否还有剩余空间 if(remainSize 0) break; //忽略注释行和空行 if(line[0] 0 || line[0] ;) continue; lineLength t_strlen(line); //注意把LF0xa字符替换成0这在UNICODE环境下可能出现结尾是LF if(line[ lineLength - 1 ] 0x0a) { line[ lineLength - 1 ] 0; lineLength--; //注意此时可能会成为空字符串 if(lineLength 0) continue; } //尝试寻找到 section if(!bFindSection) { if(line[0] ! [) continue; //本行是否是 [section] //这里是我们想要的Section吗 //检查这一行的宽度是否正好是section长度加2 [lpAppName] if(line[sectionLength 1] ! ]) continue; if(t_strncmp(line1, lpAppName, sectionLength) ! 0) continue; //Now Section will appear on next line bFindSection true; continue; } //查找Key, Section End? if(line[0][) break; //遇到了下一个 //copy the keyname to buffer, 注意ncpy不会复制结尾的0字符 //LINE: keyName // | | // line pEqualChar //找出‘’字符的位置 pEqualChar t_strchr(line, ); if(pEqualChar ! NULL) { //找到了‘’字符pEqualChar - line是key的长度 copySize min( remainSize, pEqualChar - line ); } else { //本行中不存在‘’字符对于合法文件来说不会出现此种情况 copySize min( remainSize, lineLength ); } t_strncpy(pItem, line, copySize); //最佳一个0字符 pItem[copySize] 0; //缩小缓冲区剩余字符数量remainSize和当前写入位置pItem ret (copySize 1); //加1是为了统计结尾的0字符 remainSize - (copySize 1); pItem (copySize 1); } fclose(stream); if(bFindSection) { //再次对缓冲区追加一个0 字符 *pItem 0; } return ret; }在 CeWritePrivateProfileString 函数中用到的几个文件指针的含义是假设我们要查找的 Section 是“section2”Key 是“key2” ... nSectionBegin - [section2] ... nKeyBegin - key2value2 nNextKey - ... ... nNextSection - [otherSection] ... 其他文件指针的含义是nInsertPos - 新的KEYValue开始写入位置 nCopyPos - 文件的后半部分在原始文件中的位置整体不需要改写但可能需要前移或后移从这里到文件结尾的内容会在改写ini文件之前拷贝到内存改写KEY后再写回文件并附加到文件尾部。 上面的代码中包含 StdAfx.h 通常是因为默认设定如果取消预编译头的选项则可以不包含它。 然后我们可以很方便对上面的代码进行测试 #include stdio.h #include IniFile.h int _tmain(int argc, _TCHAR* argv[]) { TCHAR buffer[128]; int age; CeGetPrivateProfileString(_T(section2), _T(name), _T(defaultValue), buffer, t_strlen(buffer), _T(c:\\test.ini)); age CeGetPrivateProfileInt(_T(section2), _T(age), -1, _T(c:\\test.ini)); //get section //CeGetPrivateProfileSection(_T(section2), buffer, 128, _T(c:\\test.ini)); //key names CeGetPrivateProfileKeyNames(_T(section2), buffer, 128, _T(c:\\test.ini)); //section names GetPrivateProfileSectionNames(buffer, 128, _T(c:\\test.ini)); CeWritePrivateProfileString(_T(section2), _T(key2), _T(testValue), _T(c:\\test.ini)); wprintf(buffer); getchar(); return 0; } //假设 C:\\test.ini 的内容是 //;testing ini file //[section1] //key1aa //[section2] //namemyname //age20 //[section3] //key1bb