1 #include "stdafx.h"
2 #include "Common.h"
3 #include "resource.h"
4 #include "FilePathHelper.h"
5 #include <random>
6 #include <strsafe.h>
7 // #include <pathcch.h>
8
CCommon()9 CCommon::CCommon()
10 {
11 }
12
13
~CCommon()14 CCommon::~CCommon()
15 {
16 }
17
18
19 //void CCommon::GetAllFormatFiles(wstring path, vector<wstring>& files, const vector<wstring>& format, size_t max_file)
20 //{
21 // //文件句柄
22 // int hFile = 0;
23 // //文件信息(用Unicode保存使用_wfinddata_t,多字节字符集使用_finddata_t)
24 // _wfinddata_t fileinfo;
25 // wstring file_path;
26 // for (auto a_format : format)
27 // {
28 // if ((hFile = _wfindfirst(file_path.assign(path).append(L"\\*.").append(a_format).c_str(), &fileinfo)) != -1)
29 // {
30 // do
31 // {
32 // if (files.size() >= max_file) break;
33 // files.push_back(file_path.assign(fileinfo.name)); //将文件名保存
34 // } while (_wfindnext(hFile, &fileinfo) == 0);
35 // }
36 // _findclose(hFile);
37 // }
38 // std::sort(files.begin(), files.end()); //对容器里的文件按名称排序
39 //}
40
FileExist(const wstring & file,bool is_case_sensitive)41 bool CCommon::FileExist(const wstring& file, bool is_case_sensitive)
42 {
43 WIN32_FIND_DATA findFileData;
44 HANDLE hFind = FindFirstFileW(file.c_str(), &findFileData);
45 if (hFind == INVALID_HANDLE_VALUE) // 没有找到说明不区分大小写也没有匹配文件
46 return false;
47 FindClose(hFind);
48 if (is_case_sensitive) // 如果需要区分大小写那么重新严格比较
49 return CFilePathHelper(file).GetFileName() == findFileData.cFileName;
50 return true;
51 }
52
FolderExist(const wstring & file)53 bool CCommon::FolderExist(const wstring& file)
54 {
55 DWORD dwAttrib = GetFileAttributes(file.c_str());
56 return INVALID_FILE_ATTRIBUTES != dwAttrib && 0 != (dwAttrib & FILE_ATTRIBUTE_DIRECTORY);
57 }
58
IsFolder(const wstring & path)59 bool CCommon::IsFolder(const wstring& path)
60 {
61 DWORD dwAttrib = GetFileAttributes(path.c_str());
62 return (dwAttrib & FILE_ATTRIBUTE_DIRECTORY) != 0;
63 }
64
CheckAndFixFile(wstring & file)65 bool CCommon::CheckAndFixFile(wstring& file)
66 {
67 WIN32_FIND_DATA findFileData;
68 HANDLE hFind = FindFirstFileW(file.c_str(), &findFileData);
69 if (hFind == INVALID_HANDLE_VALUE)
70 return false;
71 FindClose(hFind);
72 CFilePathHelper file_path(file);
73 file = file_path.GetDir() + findFileData.cFileName; // 修正file的文件名大小写到与文件一致
74 return true;
75 }
76
GetFileLastModified(const wstring & file_path,unsigned __int64 & modified_time)77 bool CCommon::GetFileLastModified(const wstring& file_path, unsigned __int64& modified_time)
78 {
79 // 使用GetFileAttributesEx,耗时大约为FindFirstFile的2/3
80 WIN32_FILE_ATTRIBUTE_DATA file_attributes;
81 if (GetFileAttributesEx(file_path.c_str(), GetFileExInfoStandard, &file_attributes))
82 {
83 ULARGE_INTEGER last_modified_time{};
84 last_modified_time.HighPart = file_attributes.ftLastWriteTime.dwHighDateTime;
85 last_modified_time.LowPart = file_attributes.ftLastWriteTime.dwLowDateTime;
86 modified_time = last_modified_time.QuadPart;
87 return true;
88 }
89 return false;
90 }
91
GetFileCreateTime(const wstring & file_path,unsigned __int64 & create_time)92 bool CCommon::GetFileCreateTime(const wstring& file_path, unsigned __int64& create_time)
93 {
94 // 使用GetFileAttributesEx,耗时大约为FindFirstFile的2/3
95 WIN32_FILE_ATTRIBUTE_DATA file_attributes;
96 if (GetFileAttributesEx(file_path.c_str(), GetFileExInfoStandard, &file_attributes))
97 {
98 ULARGE_INTEGER time{};
99 time.HighPart = file_attributes.ftCreationTime.dwHighDateTime;
100 time.LowPart = file_attributes.ftCreationTime.dwLowDateTime;
101 create_time = time.QuadPart;
102 return true;
103 }
104 return false;
105 }
106
FileTimeToTimeT(unsigned __int64 file_time)107 time_t CCommon::FileTimeToTimeT(unsigned __int64 file_time)
108 {
109 if (file_time == 0)
110 return 0;
111 // 1601年到1970年之间的时间间隔,以100纳秒为单位
112 const ULONGLONG epochDelta = 116444736000000000ULL;
113
114 // 将 FILETIME 转换为自1970年1月1日以来的100纳秒间隔数
115 ULONGLONG ull = file_time - epochDelta;
116
117 // 将100纳秒转换为秒
118 time_t t = ull / 10000000ULL;
119
120 return t;
121 }
122
IsFileHidden(const wstring & file_path)123 bool CCommon::IsFileHidden(const wstring& file_path)
124 {
125 DWORD attirbute = GetFileAttributes(file_path.c_str());
126 return (attirbute & FILE_ATTRIBUTE_HIDDEN) != 0;
127 }
128
SetFileHidden(const wstring & file_path,bool hidden)129 void CCommon::SetFileHidden(const wstring& file_path, bool hidden)
130 {
131 DWORD attirbute = GetFileAttributes(file_path.c_str());
132 if (hidden)
133 attirbute |= FILE_ATTRIBUTE_HIDDEN;
134 else
135 attirbute &= ~FILE_ATTRIBUTE_HIDDEN;
136 SetFileAttributes(file_path.c_str(), attirbute);
137 }
138
DeleteStringBom(string & str)139 void CCommon::DeleteStringBom(string& str)
140 {
141 //去掉utf8的BOM
142 if (str.size() >= 3 && str.substr(0, 3) == string{ '\xef', '\xbb', '\xbf' })
143 str = str.substr(3);
144 //去掉utf16的BOM
145 if (str.size() >= 2 && str.substr(0, 2) == string{ '\xff', '\xfe' })
146 str = str.substr(2);
147 }
148
StringCsvNormalize(CString & str)149 bool CCommon::StringCsvNormalize(CString& str)
150 {
151 bool rtn{ false };
152 //如果字符串中有双引号,则将其替换为两个双引号
153 if (str.Replace(L"\"", L"\"\""))
154 rtn = true;
155
156 //如果字符串中包含换行符、双引号和/或逗号,则将其用双引号包裹
157 const LPCTSTR spec_str = L"\r\",/";
158 if (str.FindOneOf(spec_str) >= 0)
159 {
160 str = L'\"' + str;
161 str.AppendChar(L'\"');
162 rtn = true;
163 }
164 return rtn;
165 }
166
167 //bool CCommon::FileIsMidi(const wstring & file_name)
168 //{
169 // wstring type;
170 // type = file_name.substr(file_name.size() - 4, 4); //获取扩展名
171 // std::transform(type.begin(), type.end(), type.begin(), tolower); //将扩展名转换成小写
172 // return (type == L".mid");
173 //}
174
StringCopy(char * dest,int size,string source)175 void CCommon::StringCopy(char* dest, int size, string source)
176 {
177 int source_size = source.size();
178 for (int i{}; i < size && i < source_size; i++)
179 {
180 dest[i] = source[i];
181 }
182 }
183
184 //bool CCommon::StringCompareNoCase(const wstring & str1, const wstring & str2)
185 //{
186 // wstring _str1{ str1 }, _str2{ str2 };
187 // StringTransform(_str1, false);
188 // StringTransform(_str2, false);
189 // return (_str1 == _str2);
190 //}
191
192 //size_t CCommon::StringFindNoCase(const wstring & str, const wstring & find_str)
193 //{
194 // wstring _str{ str }, _find_str{ find_str };
195 // StringTransform(_str, false);
196 // StringTransform(_find_str, false);
197 // return _str.find(_find_str);
198 //}
199
IsDivideChar(wchar_t ch)200 bool CCommon::IsDivideChar(wchar_t ch)
201 {
202 if ((ch >= L'0' && ch <= L'9') || (ch >= L'a' && ch <= L'z') || (ch >= L'A' && ch <= L'Z') || ch > 255)
203 return false;
204 else
205 return true;
206 }
207
StrIsNumber(const wstring & str)208 bool CCommon::StrIsNumber(const wstring& str)
209 {
210 if (str.empty())
211 return false;
212 for (const auto& ch : str)
213 {
214 if (ch < L'0' || ch > L'9')
215 return false;
216 }
217 return true;
218 }
219
CharIsNumber(wchar_t ch)220 bool CCommon::CharIsNumber(wchar_t ch)
221 {
222 return (ch >= L'0' && ch <= L'9');
223 }
224
StringToInt(const wstring & str)225 int CCommon::StringToInt(const wstring& str)
226 {
227 size_t start{ std::wstring::npos };
228 size_t end{ std::wstring::npos };
229 for (size_t i{}; i < str.size(); i++)
230 {
231 //标记第一个数字的位置
232 if (CharIsNumber(str[i]) && start == std::wstring::npos)
233 start = i;
234 //标记找到第一个数字后第一个不是数字的位置
235 if (start != std::wstring::npos && !CharIsNumber(str[i]))
236 {
237 end = i;
238 break;
239 }
240 }
241 if (start < str.size() && end > start)
242 {
243 wstring num_str = str.substr(start, end - start);
244 return _wtoi(num_str.c_str());
245 }
246 return 0;
247 }
248
StringSplitLine(const wstring & source_str,vector<wstring> & results,bool skip_empty,bool trim)249 void CCommon::StringSplitLine(const wstring& source_str, vector<wstring>& results, bool skip_empty, bool trim)
250 {
251 results.clear();
252 if (source_str.empty())
253 return;
254
255 auto push_back_str = [&](const wchar_t* start, const wchar_t* end)
256 {
257 wstring tmp(start, end);
258 if (trim)
259 StringNormalize(tmp);
260 if (!skip_empty || !tmp.empty())
261 results.push_back(std::move(tmp));
262 };
263
264 const wchar_t* line_start_pos = source_str.data();
265 const wchar_t* cur_pos = line_start_pos;
266 const wchar_t* end_pos = line_start_pos + source_str.size();
267 while (cur_pos < end_pos)
268 {
269 if (*cur_pos == L'\r' || *cur_pos == L'\n')
270 {
271 push_back_str(line_start_pos, cur_pos);
272 ++cur_pos; // 指针移动到下一个字符
273 if (*cur_pos == L'\n' && *(cur_pos - 1) == L'\r') // 如果下一个字符是LF且位于CR后面那么跳过
274 ++cur_pos;
275 line_start_pos = cur_pos;
276 }
277 else
278 ++cur_pos;
279 }
280 push_back_str(line_start_pos, cur_pos);
281 }
282
283 template<class T>
_StringSplit(const T & str,wchar_t div_ch,vector<T> & results,bool skip_empty,bool trim)284 static void _StringSplit(const T& str, wchar_t div_ch, vector<T>& results, bool skip_empty, bool trim)
285 {
286 results.clear();
287 size_t split_index = -1;
288 size_t last_split_index = -1;
289 while (true)
290 {
291 split_index = str.find(div_ch, split_index + 1);
292 T split_str = str.substr(last_split_index + 1, split_index - last_split_index - 1);
293 if (trim)
294 CCommon::StringNormalize(split_str);
295 if (!split_str.empty() || !skip_empty)
296 results.push_back(split_str);
297 if (split_index == wstring::npos)
298 break;
299 last_split_index = split_index;
300 }
301 }
302
303 template<class T>
_StringSplit(const T & str,const T & div_str,vector<T> & results,bool skip_empty,bool trim)304 void _StringSplit(const T& str, const T& div_str, vector<T>& results, bool skip_empty /*= true*/, bool trim)
305 {
306 results.clear();
307 size_t split_index = 0 - div_str.size();
308 size_t last_split_index = 0 - div_str.size();
309 while (true)
310 {
311 split_index = str.find(div_str, split_index + div_str.size());
312 T split_str = str.substr(last_split_index + div_str.size(), split_index - last_split_index - div_str.size());
313 if (trim)
314 CCommon::StringNormalize(split_str);
315 if (!split_str.empty() || !skip_empty)
316 results.push_back(split_str);
317 if (split_index == wstring::npos)
318 break;
319 last_split_index = split_index;
320 }
321 }
322
StringSplit(const wstring & str,wchar_t div_ch,vector<wstring> & results,bool skip_empty,bool trim)323 void CCommon::StringSplit(const wstring& str, wchar_t div_ch, vector<wstring>& results, bool skip_empty, bool trim)
324 {
325 _StringSplit<std::wstring>(str, div_ch, results, skip_empty, trim);
326 }
327
StringSplit(const wstring & str,const wstring & div_str,vector<wstring> & results,bool skip_empty,bool trim)328 void CCommon::StringSplit(const wstring& str, const wstring& div_str, vector<wstring>& results, bool skip_empty /*= true*/, bool trim)
329 {
330 _StringSplit<std::wstring>(str, div_str, results, skip_empty, trim);
331 }
332
StringSplit(const string & str,char div_ch,vector<string> & result,bool skip_empty,bool trim)333 void CCommon::StringSplit(const string& str, char div_ch, vector<string>& result, bool skip_empty, bool trim)
334 {
335 _StringSplit<std::string>(str, div_ch, result, skip_empty, trim);
336 }
337
StringSplit(const string & str,const string & div_str,vector<string> & results,bool skip_empty,bool trim)338 void CCommon::StringSplit(const string& str, const string& div_str, vector<string>& results, bool skip_empty, bool trim)
339 {
340 _StringSplit<std::string>(str, div_str, results, skip_empty, trim);
341 }
342
StringSplitWithMulitChars(const wstring & str,const wstring & div_ch,vector<wstring> & results,bool skip_empty)343 void CCommon::StringSplitWithMulitChars(const wstring& str, const wstring& div_ch, vector<wstring>& results, bool skip_empty /*= true*/)
344 {
345 results.clear();
346 size_t split_index = -1;
347 size_t last_split_index = -1;
348 while (true)
349 {
350 split_index = str.find_first_of(div_ch, split_index + 1);
351 wstring split_str = str.substr(last_split_index + 1, split_index - last_split_index - 1);
352 StringNormalize(split_str);
353 if (!split_str.empty() || !skip_empty)
354 results.push_back(split_str);
355 if (split_index == wstring::npos)
356 break;
357 last_split_index = split_index;
358 }
359 }
360
StringSplitWithSeparators(const wstring & str,const vector<wstring> & separators,vector<wstring> & results,bool skip_empty)361 void CCommon::StringSplitWithSeparators(const wstring& str, const vector<wstring>& separators, vector<wstring>& results, bool skip_empty /*= true*/)
362 {
363 results.clear();
364 size_t split_index = 0;
365 size_t last_split_index = 0;
366
367 wstring split_str;
368 size_t i{};
369 for (; i < separators.size(); i++)
370 {
371 if (i == 0)
372 split_index = str.find(separators[i]);
373 else
374 split_index = str.find(separators[i], split_index + separators[i - 1].size());
375
376 if (split_index == wstring::npos)
377 break;
378
379 if (i == 0)
380 split_str = str.substr(0, split_index);
381 else
382 split_str = str.substr(last_split_index + separators[i - 1].size(), split_index - last_split_index - separators[i - 1].size());
383 if (!split_str.empty() || !skip_empty)
384 results.push_back(split_str);
385
386 last_split_index = split_index;
387 }
388
389 if (i - 1 >= 0 && i - 1 < separators.size())
390 {
391 size_t index = last_split_index + separators[i - 1].size();
392 if (index < str.size())
393 split_str = str.substr(last_split_index + separators[i - 1].size());
394 if (!split_str.empty() || !skip_empty)
395 results.push_back(split_str);
396 }
397 }
398
StringMerge(const vector<wstring> & strings,wchar_t div_ch)399 wstring CCommon::StringMerge(const vector<wstring>& strings, wchar_t div_ch)
400 {
401 wstring result;
402 for (const auto& str : strings)
403 {
404 result.append(str).push_back(div_ch);
405 }
406 if (!strings.empty())
407 result.pop_back();
408 return result;
409 }
410
MergeStringList(const vector<wstring> & values)411 wstring CCommon::MergeStringList(const vector<wstring>& values)
412 {
413 wstring str_merge;
414 int index = 0;
415 // 在每个字符串前后加上引号,再将它们用逗号连接起来
416 for (wstring str : values)
417 {
418 StringNormalize(str);
419 if (str.empty()) continue;
420 if (index > 0)
421 str_merge.push_back(L',');
422 str_merge.push_back(L'\"');
423 str_merge += str;
424 str_merge.push_back(L'\"');
425 index++;
426 }
427 return str_merge;
428 }
429
SplitStringList(vector<wstring> & values,const wstring & str_value)430 void CCommon::SplitStringList(vector<wstring>& values, const wstring& str_value)
431 {
432 CCommon::StringSplit(str_value, L"\",\"", values);
433 if (!values.empty())
434 {
435 // 结果中第一项前面和最后一项的后面各还有一个引号,将它们删除
436 values.front() = values.front().substr(1);
437 values.back().pop_back();
438 }
439 }
440
TranslateToSimplifiedChinese(const wstring & str)441 wstring CCommon::TranslateToSimplifiedChinese(const wstring& str)
442 {
443 wstring result;
444 size_t size{ str.size() };
445 if (size == 0) return wstring();
446 wchar_t* out_buff = new wchar_t[size + 1];
447 WORD wLanguageID = MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED);
448 LCID Locale = MAKELCID(wLanguageID, SORT_CHINESE_PRCP);
449 int rtn = LCMapString(Locale, LCMAP_SIMPLIFIED_CHINESE, str.c_str(), -1, out_buff, size * sizeof(wchar_t));
450 result.assign(out_buff);
451 delete[] out_buff;
452 return result;
453 }
454
TranslateToTranditionalChinese(const wstring & str)455 wstring CCommon::TranslateToTranditionalChinese(const wstring& str)
456 {
457 wstring result;
458 size_t size{ str.size() };
459 if (size == 0) return wstring();
460 wchar_t* out_buff = new wchar_t[size + 1];
461 WORD wLanguageID = MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED);
462 LCID Locale = MAKELCID(wLanguageID, SORT_CHINESE_PRCP);
463 int rtn = LCMapString(Locale, LCMAP_TRADITIONAL_CHINESE, str.c_str(), -1, out_buff, size * sizeof(wchar_t));
464 result.assign(out_buff);
465 delete[] out_buff;
466 return result;
467 }
468
FileNameNormalize(wstring & file_name)469 void CCommon::FileNameNormalize(wstring& file_name)
470 {
471 //查找字符串中的无效字符,并将其替换成‘_’
472 const wstring invalid_chars{ L"\\\"/:*?<>|\a\b\f\n\r\t\v" };
473 int index{ -1 };
474 while (true)
475 {
476 index = file_name.find_first_of(invalid_chars, index + 1);
477 if (index == wstring::npos)
478 {
479 return;
480 }
481 else
482 {
483 if (file_name[index] == L'<')
484 file_name[index] = L'(';
485 else if (file_name[index] == L'>')
486 file_name[index] = L')';
487 else
488 file_name[index] = L'_';
489 }
490 }
491 }
492
IsFileNameValid(const wstring & file_name)493 bool CCommon::IsFileNameValid(const wstring& file_name)
494 {
495 const wstring invalid_chars{ L"\\\"/:*?<>|\a\b\f\n\r\t\v" };
496 return (file_name.find_first_of(invalid_chars) == wstring::npos);
497 }
498
GetFileSize(const wstring & file_name)499 size_t CCommon::GetFileSize(const wstring& file_name)
500 {
501 std::streampos l, m;
502 ifstream file(file_name, std::ios::in | std::ios::binary);
503 l = file.tellg();
504 file.seekg(0, std::ios::end);
505 m = file.tellg();
506 file.close();
507 return static_cast<size_t>(m - l);
508 }
509
StrToUnicode(const string & str,CodeType code_type,bool auto_utf8)510 wstring CCommon::StrToUnicode(const string& str, CodeType code_type, bool auto_utf8)
511 {
512 // 当使用ANSI,UTF8,UTF8_NO_BOM,UTF16LE,UTF16BE时不检测直接转换
513 // 使用默认值CodeType::AUTO时先检测BOM,如果没有BOM则按ANSI转换
514 // 将auto_utf8置true使AUTO检测没有BOM的字串是否为UTF8序列,如果符合则按UTF8_NO_BOM转换
515 // auto_utf8有可能将过短的ANSI误认为是UTF8导致乱码
516 if (str.empty()) return wstring();
517 // code_type为AUTO时从这里开始
518 if (code_type == CodeType::AUTO) // 先根据BOM判断编码类型
519 {
520 code_type = JudgeCodeType(str, CodeType::ANSI, auto_utf8);
521 }
522 bool result_ready = false;
523 int size;
524 wstring result;
525 // 如果编码类型此时已经可以确定并转换好不必回落到ANSI则置位result_ready
526 if (code_type == CodeType::UTF8 || code_type == CodeType::UTF8_NO_BOM)
527 {
528 string temp;
529 //如果前面有BOM,则去掉BOM
530 if (str.size() >= 3 && str[0] == -17 && str[1] == -69 && str[2] == -65)
531 temp = str.substr(3);
532 else
533 temp = str;
534 size = MultiByteToWideChar(CP_UTF8, 0, temp.c_str(), -1, NULL, 0);
535 if (size <= 0) return wstring();
536 wchar_t* str_unicode = new wchar_t[size + 1];
537 MultiByteToWideChar(CP_UTF8, 0, temp.c_str(), -1, str_unicode, size);
538 result.assign(str_unicode);
539 delete[] str_unicode;
540 result_ready = true;
541 }
542 else if (code_type == CodeType::UTF16LE)
543 {
544 string temp;
545 //如果前面有BOM,则去掉BOM
546 if (str.size() >= 2 && str[0] == -1 && str[1] == -2)
547 temp = str.substr(2);
548 else
549 temp = str;
550 if (temp.size() % 2 == 1)
551 temp.pop_back();
552 temp.push_back('\0');
553 result = (const wchar_t*)temp.c_str();
554 result_ready = true;
555 }
556 else if (code_type == CodeType::UTF16BE)
557 {
558 string temp;
559 //如果前面有BOM,则去掉BOM
560 if (str.size() >= 2 && str[0] == -2 && str[1] == -1)
561 temp = str.substr(2);
562 else
563 temp = str;
564 if (temp.size() % 2 == 1)
565 temp.pop_back();
566 temp.push_back('\0');
567 wchar_t* p = (wchar_t*)temp.c_str();
568 convertBE_LE(p, temp.size() >> 1);
569 result = p;
570 result_ready = true;
571 }
572
573 // 如果以上均未执行那么按系统ANSI编码处理
574 if (!result_ready)
575 {
576 size = MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, NULL, 0);
577 if (size <= 0) return wstring();
578 wchar_t* str_unicode = new wchar_t[size + 1];
579 MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, str_unicode, size);
580 result.assign(str_unicode);
581 delete[] str_unicode;
582 }
583 return result;
584 }
585
UnicodeToStr(const wstring & wstr,CodeType code_type,bool * char_cannot_convert)586 string CCommon::UnicodeToStr(const wstring& wstr, CodeType code_type, bool* char_cannot_convert)
587 {
588 if (wstr.empty()) return string();
589 if (char_cannot_convert != nullptr)
590 *char_cannot_convert = false;
591 BOOL UsedDefaultChar{ FALSE };
592 string result;
593 int size{ 0 };
594 if (code_type == CodeType::ANSI)
595 {
596 size = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, NULL, 0, NULL, NULL);
597 if (size <= 0) return string();
598 char* str = new char[size + 1];
599 WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, str, size, NULL, &UsedDefaultChar);
600 result.assign(str);
601 delete[] str;
602 }
603 else if (code_type == CodeType::UTF8 || code_type == CodeType::UTF8_NO_BOM)
604 {
605 result.clear();
606 if (code_type == CodeType::UTF8)
607 {
608 result.push_back(-17);
609 result.push_back(-69);
610 result.push_back(-65);
611 }
612 size = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, NULL, 0, NULL, NULL);
613 if (size <= 0) return string();
614 char* str = new char[size + 1];
615 WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, str, size, NULL, NULL);
616 result.append(str);
617 delete[] str;
618 }
619 else if (code_type == CodeType::UTF16LE)
620 {
621 result.clear();
622 result.push_back(-1); //在前面加上UTF16LE的BOM
623 result.push_back(-2);
624 result.append((const char*)wstr.c_str(), (const char*)wstr.c_str() + wstr.size() * 2);
625 result.push_back('\0');
626 }
627 else if (code_type == CodeType::UTF16BE)
628 {
629 result.clear();
630 result.push_back(-2); //在前面加上UTF16BE的BOM
631 result.push_back(-1);
632 wchar_t* p = (wchar_t*)wstr.c_str();
633 convertBE_LE(p, wstr.size());
634 wstring temp{ p };
635 result.append((const char*)temp.c_str(), (const char*)temp.c_str() + temp.size() * 2);
636 result.push_back('\0');
637 }
638 if (char_cannot_convert != nullptr)
639 *char_cannot_convert = (UsedDefaultChar != FALSE);
640 return result;
641 }
642
ASCIIToUnicode(const string & ascii)643 wstring CCommon::ASCIIToUnicode(const string& ascii)
644 {
645 wstring result;
646 for (const char& ch : ascii)
647 {
648 result.push_back(ch);
649 }
650 return result;
651 }
652
IsUTF8Bytes(const char * data)653 bool CCommon::IsUTF8Bytes(const char* data)
654 {
655 int charByteCounter = 1; //计算当前正分析的字符应还有的字节数
656 unsigned char curByte; //当前分析的字节.
657 bool ascii = true;
658 int length = strlen(data);
659 for (int i = 0; i < length; i++)
660 {
661 curByte = static_cast<unsigned char>(data[i]);
662 if (charByteCounter == 1)
663 {
664 if (curByte >= 0x80)
665 {
666 ascii = false;
667 //判断当前
668 while (((curByte <<= 1) & 0x80) != 0)
669 {
670 charByteCounter++;
671 }
672 //标记位首位若为非0 则至少以2个1开始 如:110XXXXX...........1111110X
673 if (charByteCounter == 1 || charByteCounter > 6)
674 {
675 return false;
676 }
677 }
678 }
679 else
680 {
681 //若是UTF-8 此时第一位必须为1
682 if ((curByte & 0xC0) != 0x80)
683 {
684 return false;
685 }
686 charByteCounter--;
687 }
688 }
689 if (ascii) return false; //如果全是ASCII字符,返回false
690 else return true;
691 }
692
JudgeCodeType(const string & str,CodeType default_code,bool auto_utf8)693 CodeType CCommon::JudgeCodeType(const string& str, CodeType default_code, bool auto_utf8)
694 {
695 CodeType code_type{ default_code };
696 if (!str.empty())
697 {
698 // 如果前面有UTF8的BOM,则编码类型为UTF8
699 if (str.size() >= 3 && str[0] == -17 && str[1] == -69 && str[2] == -65)
700 code_type = CodeType::UTF8;
701 // 如果前面有UTF16LE的BOM,则编码类型为UTF16LE
702 else if (str.size() >= 2 && str[0] == -1 && str[1] == -2)
703 code_type = CodeType::UTF16LE;
704 // 如果前面有UTF16BE的BOM,则编码类型为UTF16BE
705 else if (str.size() >= 2 && str[0] == -2 && str[1] == -1)
706 code_type = CodeType::UTF16BE;
707 // AUTO时是否将符合UTF8格式的str作为UTF8_NO_BOM处理
708 else if (auto_utf8 && IsUTF8Bytes(str.c_str()))
709 code_type = CodeType::UTF8_NO_BOM;
710 }
711 return code_type;
712 }
713
IsURL(const wstring & str)714 bool CCommon::IsURL(const wstring& str)
715 {
716 return (str.substr(0, 7) == L"http://" || str.substr(0, 8) == L"https://" || str.substr(0, 6) == L"ftp://" || str.substr(0, 6) == L"mms://");
717 }
718
IsWindowsPath(const wstring & str)719 bool CCommon::IsWindowsPath(const wstring& str)
720 {
721 return (str.size() >= 3 // windows 路径至少3个字符
722 && ((str[0] >= L'A' && str[0] <= L'Z') || (str[0] >= L'a' && str[0] <= L'z')) // 第1个字符必须为字母
723 && str[1] == L':' // 第2个字符必须为冒号
724 && (str[2] == L'/' || str[2] == L'\\') // 第3个字符必须为斜杠
725 );
726 }
727
IsPath(const wstring & str)728 bool CCommon::IsPath(const wstring& str)
729 {
730 if (str.size() < 3)
731 return false;
732
733 bool is_windows_path{ IsWindowsPath(str) };
734 bool is_UNC_path{ str[0] == L'\\' && str[1] == L'\\' };
735
736 if (!is_windows_path && !is_UNC_path)
737 return false;
738
739 const wstring invalid_chars{ L":*?\"<>|" };
740 if (str.find_first_of(invalid_chars, is_windows_path ? 2 : 0) != wstring::npos)
741 return false;
742
743 return true;
744 }
745
StringCharacterReplace(wstring & str,wchar_t ch,wchar_t ch_replaced)746 bool CCommon::StringCharacterReplace(wstring& str, wchar_t ch, wchar_t ch_replaced)
747 {
748 bool replaced = false;
749 for (size_t i = 0; i < str.size(); i++)
750 {
751 if (str[i] == ch)
752 {
753 str[i] = ch_replaced;
754 replaced = true;
755 }
756 }
757 return replaced;
758 }
759
StringReplace(wstring & str,const wstring & str_old,const wstring & str_new)760 bool CCommon::StringReplace(wstring& str, const wstring& str_old, const wstring& str_new)
761 {
762 if (str.empty())
763 return false;
764 bool replaced{ false };
765 size_t pos = 0;
766 while ((pos = str.find(str_old, pos)) != std::wstring::npos)
767 {
768 str.replace(pos, str_old.length(), str_new);
769 replaced = true;
770 pos += str_new.length(); // 前进到替换后的字符串末尾
771 }
772 return replaced;
773 }
774
DataSizeToString(size_t data_size)775 CString CCommon::DataSizeToString(size_t data_size)
776 {
777 CString size_info;
778 if (data_size < 1024)
779 size_info.Format(_T("%u B"), data_size);
780 else if (data_size < 1024 * 1024)
781 size_info.Format(_T("%.2f KB"), data_size / 1024.0f);
782 else if (data_size < 1024 * 1024 * 1024)
783 size_info.Format(_T("%.2f MB"), data_size / 1024.0f / 1024.0f);
784 else
785 size_info.Format(_T("%.2f GB"), data_size / 1024.0f / 1024.0f / 1024.0f);
786 return size_info;
787 }
788
GetExePath()789 wstring CCommon::GetExePath()
790 {
791 wchar_t path[MAX_PATH];
792 GetModuleFileNameW(NULL, path, MAX_PATH);
793 size_t index;
794 wstring current_path{ path };
795 index = current_path.find_last_of(L'\\');
796 current_path = current_path.substr(0, index + 1);
797 return current_path;
798 }
799
GetDesktopPath()800 wstring CCommon::GetDesktopPath()
801 {
802 LPITEMIDLIST ppidl;
803 TCHAR pszDesktopPath[MAX_PATH];
804 if (SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &ppidl) == S_OK)
805 {
806 SHGetPathFromIDList(ppidl, pszDesktopPath);
807 CoTaskMemFree(ppidl);
808 }
809 return wstring(pszDesktopPath);
810 }
811
GetTemplatePath()812 wstring CCommon::GetTemplatePath()
813 {
814 wstring result;
815 wchar_t buff[MAX_PATH];
816 GetTempPath(MAX_PATH, buff); //获取临时文件夹的路径
817 result = buff;
818 if (!result.empty() && result.back() != L'\\' && result.back() != L'/') //确保路径后面有斜杠
819 result.push_back(L'\\');
820 return result;
821 }
822
823
GetAppDataConfigDir()824 wstring CCommon::GetAppDataConfigDir()
825 {
826 LPITEMIDLIST ppidl;
827 TCHAR pszAppDataPath[MAX_PATH];
828 if (SHGetSpecialFolderLocation(NULL, CSIDL_APPDATA, &ppidl) == S_OK)
829 {
830 SHGetPathFromIDList(ppidl, pszAppDataPath);
831 CoTaskMemFree(ppidl);
832 }
833 wstring app_data_path{ pszAppDataPath }; //获取到C:/User/用户名/AppData/Roaming路径
834 CreateDirectory(app_data_path.c_str(), NULL); //如果Roaming不存在,则创建它
835 app_data_path += L'\\';
836 app_data_path += APP_NAME;
837 #ifdef _DEBUG
838 app_data_path += L" (Debug)";
839 #endif
840 app_data_path += L'\\';
841 CreateDirectory(app_data_path.c_str(), NULL); //如果C:/User/用户名/AppData/Roaming/MusicPlayer2不存在,则创建它
842
843 return app_data_path;
844 }
845
GetSpecialDir(int csidl)846 wstring CCommon::GetSpecialDir(int csidl)
847 {
848 bool rtn{};
849 LPITEMIDLIST ppidl;
850 wchar_t folder_dir[MAX_PATH];
851 if (SHGetSpecialFolderLocation(NULL, csidl, &ppidl) == S_OK)
852 {
853 rtn = SHGetPathFromIDListW(ppidl, folder_dir);
854 CoTaskMemFree(ppidl);
855 }
856 ASSERT(rtn);
857 if (rtn)
858 return wstring(folder_dir);
859 return wstring();
860 }
861
CreateDir(const _tstring & path)862 bool CCommon::CreateDir(const _tstring& path)
863 {
864 if (!FolderExist(path))
865 {
866 if (CreateDirectory(path.c_str(), NULL))
867 {
868 return true;
869 }
870 }
871 return false;
872 }
873
FileRename(const _tstring & file_path,const _tstring & new_file_name)874 _tstring CCommon::FileRename(const _tstring& file_path, const _tstring& new_file_name)
875 {
876 if (!FileExist(file_path))
877 return _tstring();
878
879 _tstring dir;
880 size_t index = file_path.find_last_of(_T("/\\"));
881 if (index == _tstring::npos)
882 return _tstring();
883 dir = file_path.substr(0, index + 1);
884
885 _tstring extension;
886 size_t index_ext = file_path.rfind(_T('.'));
887 if (index_ext < file_path.size() - 1 && index_ext > index)
888 extension = file_path.substr(index_ext);
889
890 _tstring new_file_path = dir + new_file_name + extension;
891 try
892 {
893 CFile::Rename(file_path.c_str(), new_file_path.c_str());
894 }
895 catch (CFileException* pEx)
896 {
897 new_file_path.clear();
898 pEx->Delete();
899 }
900 return new_file_path;
901 }
902
RelativePathToAbsolutePath(const _tstring & relative_path,const _tstring & cur_dir)903 _tstring CCommon::RelativePathToAbsolutePath(const _tstring& relative_path, const _tstring& cur_dir)
904 {
905 // relative_path如果是盘符开头的绝对路径那么返回此绝对路径
906 // 否则将relative_path视为相对路径或斜杠开头的绝对路径并与cur_dir拼接
907 _tstring result = relative_path;
908 _tstring dir = cur_dir;
909 if (!IsPath(result) && !dir.empty())
910 {
911 // https://docs.microsoft.com/en-us/windows/win32/api/shlwapi/
912 // PathCombine拼接简化两个合法路径,当result为斜杠开头的绝对路径时将其只与dir的盘符拼接
913 // PathCchCombine 是处理了缓冲区溢出的安全版本,Windows 8开始支持,位于pathcch.h
914 TCHAR lpBuffer[MAX_PATH]{};
915 PathCombine(lpBuffer, dir.c_str(), result.c_str());
916 // PathCchCombine(lpBuffer, MAX_PATH, dir.c_str(), result.c_str());
917 result = lpBuffer;
918 }
919 return result;
920 }
921
CopyStringToClipboard(const wstring & str)922 bool CCommon::CopyStringToClipboard(const wstring& str)
923 {
924 if (OpenClipboard(NULL))
925 {
926 HGLOBAL clipbuffer;
927 EmptyClipboard();
928 size_t size = (str.size() + 1) * 2;
929 clipbuffer = GlobalAlloc(GMEM_DDESHARE, size);
930 memcpy_s(GlobalLock(clipbuffer), size, str.c_str(), size);
931 GlobalUnlock(clipbuffer);
932 if (SetClipboardData(CF_UNICODETEXT, clipbuffer) == NULL)
933 return false;
934 CloseClipboard();
935 return true;
936 }
937 else return false;
938 }
939
GetStringFromClipboard()940 wstring CCommon::GetStringFromClipboard()
941 {
942 if (OpenClipboard(NULL))
943 {
944 if (IsClipboardFormatAvailable(CF_TEXT))
945 {
946 HANDLE hClip;
947 wchar_t* pBuf;
948 hClip = GetClipboardData(CF_UNICODETEXT); //获取剪贴板数据
949 if (hClip == NULL)
950 return wstring();
951 pBuf = (wchar_t*)GlobalLock(hClip);
952 if (pBuf == nullptr)
953 return wstring();
954 CloseClipboard();
955 return wstring(pBuf);
956 }
957 }
958 return wstring();
959 }
960
WriteLog(const wchar_t * path,const wstring & content)961 void CCommon::WriteLog(const wchar_t* path, const wstring& content)
962 {
963 SYSTEMTIME cur_time;
964 GetLocalTime(&cur_time);
965 char buff[32];
966 sprintf_s(buff, "%d/%.2d/%.2d %.2d:%.2d:%.2d.%.3d ", cur_time.wYear, cur_time.wMonth, cur_time.wDay,
967 cur_time.wHour, cur_time.wMinute, cur_time.wSecond, cur_time.wMilliseconds);
968 ofstream out_put{ path, std::ios::app };
969 out_put << buff << CCommon::UnicodeToStr(content, CodeType::UTF8_NO_BOM) << std::endl;
970 out_put.close(); // 这里需要显式关闭以避免被不同线程连续调用时丢失内容(不过还是不能承受并发,多线程并发时请自行加锁
971 }
972
DisposeCmdLineFiles(const wstring & cmd_line,vector<wstring> & files)973 void CCommon::DisposeCmdLineFiles(const wstring& cmd_line, vector<wstring>& files)
974 {
975 // 解析命令行参数中的文件/文件夹路径放入files
976 // files 中能够接受音频文件路径/播放列表文件路径/文件夹路径随意乱序出现
977 // files 中无法被识别为“播放列表文件路径”“文件夹路径”的项目会被直接加入默认播放列表
978 // TODO: 这里可能需要添加以下功能,我没有其他windows版本的经验,不确定这里怎样改
979 // 文件/文件夹存在判断;路径通配符展开;相对路径转换绝对路径;支持不在同一文件夹下的多个文件路径
980 files.clear();
981 if (cmd_line.empty()) return;
982 wstring path;
983 //先找出字符串中的文件夹路径,从命令行参数传递过来的文件肯定都是同一个文件夹下的
984 if (cmd_line[0] == L'\"') //如果第一个文件用双引号包含起来
985 {
986 int index1 = cmd_line.find(L'\"', 1); //查找和第1个双引号匹配的双引号
987 int index2 = cmd_line.rfind(L'\\', index1); //往前查找反斜杠
988 path = cmd_line.substr(1, index2); //获取文件夹路径(包含最后一个反斜杠)
989 files.push_back(cmd_line.substr(1, index1 - 1));
990 }
991 else //如果第一个文件没有用双引号包含起来,则说明路径中不包含空格,
992 {
993 int index1 = cmd_line.find(L' '); //查找和第1空格
994 int index2 = cmd_line.rfind(L'\\', index1); //往前查找反斜杠
995 path = cmd_line.substr(0, index2 + 1); //获取文件夹路径(包含最后一个反斜杠)
996 files.push_back(cmd_line.substr(0, index1));
997 }
998 int path_size = path.size();
999 if (path_size < 2) return;
1000 int index{};
1001 while (true)
1002 {
1003 index = cmd_line.find(path, index + path_size); //从第2个开始查找路径出现的位置
1004 if (index == string::npos) break;
1005 if (index > 0 && cmd_line[index - 1] == L'\"') //如果路径前面一个字符是双引号
1006 {
1007 int index1 = cmd_line.find(L'\"', index);
1008 files.push_back(cmd_line.substr(index, index1 - index));
1009 }
1010 else
1011 {
1012 int index1 = cmd_line.find(L' ', index);
1013 files.push_back(cmd_line.substr(index, index1 - index));
1014 }
1015 }
1016 return;
1017 //CString out_info;
1018 //out_info += _T("命令行参数:");
1019 //out_info += cmd_line.c_str();
1020 //out_info += _T("\r\n");
1021 //out_info += _T("路径:");
1022 //out_info += path.c_str();
1023 //out_info += _T("\r\n");
1024 //CCommon::WriteLog(L".\\command.log", wstring{ out_info });
1025 }
1026
GetCmdLineCommand(const wstring & cmd_line,int & command)1027 bool CCommon::GetCmdLineCommand(const wstring& cmd_line, int& command)
1028 {
1029 if (CCommon::StringNatchWholeWord(cmd_line, wstring(L"-play_pause")) != string::npos || CCommon::StringNatchWholeWord(cmd_line, wstring(L"-p")) != string::npos)
1030 command |= ControlCmd::PLAY_PAUSE;
1031 if (CCommon::StringNatchWholeWord(cmd_line, wstring(L"-previous")) != string::npos || CCommon::StringNatchWholeWord(cmd_line, wstring(L"-pre")) != string::npos)
1032 command |= ControlCmd::_PREVIOUS;
1033 if (CCommon::StringNatchWholeWord(cmd_line, wstring(L"-next")) != string::npos || CCommon::StringNatchWholeWord(cmd_line, wstring(L"-n")) != string::npos)
1034 command |= ControlCmd::_NEXT;
1035 if (CCommon::StringNatchWholeWord(cmd_line, wstring(L"-stop")) != string::npos || CCommon::StringNatchWholeWord(cmd_line, wstring(L"-s")) != string::npos)
1036 command |= ControlCmd::STOP;
1037 if (CCommon::StringNatchWholeWord(cmd_line, wstring(L"-ff")) != string::npos)
1038 command |= ControlCmd::FF;
1039 if (CCommon::StringNatchWholeWord(cmd_line, wstring(L"-rew")) != string::npos)
1040 command |= ControlCmd::REW;
1041 if (CCommon::StringNatchWholeWord(cmd_line, wstring(L"-vol_up")) != string::npos)
1042 command |= ControlCmd::VOLUME_UP;
1043 if (CCommon::StringNatchWholeWord(cmd_line, wstring(L"-vol_down")) != string::npos)
1044 command |= ControlCmd::VOLUME_DOWM;
1045 if (CCommon::StringNatchWholeWord(cmd_line, wstring(L"-mini")) != string::npos)
1046 command |= ControlCmd::MINI_MODE;
1047 return command != ControlCmd::NONE;
1048 }
1049
CreateFileShortcut(LPCTSTR lpszLnkFileDir,LPCTSTR lpszFileName,LPCTSTR lpszLnkFileName,LPCTSTR lpszWorkDir,WORD wHotkey,LPCTSTR lpszDescription,int iShowCmd,LPCTSTR lpszArguments,int nIconOffset)1050 bool CCommon::CreateFileShortcut(LPCTSTR lpszLnkFileDir, LPCTSTR lpszFileName, LPCTSTR lpszLnkFileName, LPCTSTR lpszWorkDir, WORD wHotkey, LPCTSTR lpszDescription, int iShowCmd, LPCTSTR lpszArguments, int nIconOffset)
1051 {
1052 if (lpszLnkFileDir == NULL)
1053 return false;
1054
1055 HRESULT hr;
1056 IShellLink* pLink; //IShellLink对象指针
1057 IPersistFile* ppf; //IPersisFil对象指针
1058
1059 //创建IShellLink对象
1060 hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void**)&pLink);
1061 if (FAILED(hr))
1062 return false;
1063
1064 //从IShellLink对象中获取IPersistFile接口
1065 hr = pLink->QueryInterface(IID_IPersistFile, (void**)&ppf);
1066 if (FAILED(hr))
1067 {
1068 pLink->Release();
1069 return false;
1070 }
1071
1072 TCHAR file_path[MAX_PATH]; //当前进程exe文件路径
1073 GetModuleFileName(NULL, file_path, MAX_PATH);
1074 LPCTSTR pFilePath; //快捷方式目标
1075
1076 //目标
1077 if (lpszFileName == NULL)
1078 pFilePath = file_path;
1079 else
1080 pFilePath = lpszFileName;
1081 pLink->SetPath(pFilePath);
1082
1083 //工作目录
1084 if (lpszWorkDir != NULL)
1085 {
1086 pLink->SetWorkingDirectory(lpszWorkDir);
1087 }
1088 else
1089 {
1090 //设置工作目录为快捷方式目标所在位置
1091 _tstring workDir = pFilePath;
1092 int index = workDir.find_last_of(_T("\\/"));
1093 if (index != workDir.npos)
1094 workDir = workDir.substr(0, index);
1095 pLink->SetWorkingDirectory(workDir.c_str());
1096 }
1097
1098 //快捷键
1099 if (wHotkey != 0)
1100 pLink->SetHotkey(wHotkey);
1101
1102 //备注
1103 if (lpszDescription != NULL)
1104 pLink->SetDescription(lpszDescription);
1105
1106 //显示方式
1107 pLink->SetShowCmd(iShowCmd);
1108
1109 //参数
1110 if (lpszArguments != NULL)
1111 pLink->SetArguments(lpszArguments);
1112
1113 //图标
1114 if (nIconOffset > 0)
1115 pLink->SetIconLocation(pFilePath, nIconOffset);
1116
1117 //快捷方式的路径 + 名称
1118 _tstring shortcutName;
1119 shortcutName = lpszLnkFileDir;
1120 if (!shortcutName.empty() && shortcutName.back() != _T('\\') && shortcutName.back() != _T('/'))
1121 shortcutName.push_back(_T('\\'));
1122
1123 if (lpszLnkFileName != NULL) //指定了快捷方式的名称
1124 {
1125 shortcutName += lpszLnkFileName;
1126 }
1127 else
1128 {
1129 //没有指定名称,就从取指定文件的文件名作为快捷方式名称。
1130 _tstring fileName = pFilePath;
1131
1132 int index1, index2;
1133 index1 = fileName.find_last_of(_T("\\/"));
1134 index2 = fileName.rfind(_T('.'));
1135
1136 if (index1 == _tstring::npos || index2 == _tstring::npos || index1 >= index2)
1137 {
1138 ppf->Release();
1139 pLink->Release();
1140 return false;
1141 }
1142 fileName = fileName.substr(index1 + 1, index2 - index1 - 1);
1143 fileName += _T(".lnk");
1144 shortcutName += fileName;
1145 }
1146
1147 //保存快捷方式到指定目录下
1148 hr = ppf->Save(shortcutName.c_str(), TRUE);
1149
1150 ppf->Release();
1151 pLink->Release();
1152 return SUCCEEDED(hr);
1153 }
1154
GetFiles(wstring file_name,vector<wstring> & files,std::function<bool (const wstring &)> fun_is_valid)1155 void CCommon::GetFiles(wstring file_name, vector<wstring>& files, std::function<bool(const wstring&)> fun_is_valid)
1156 {
1157 files.clear();
1158 //文件句柄
1159 intptr_t hFile = 0;
1160 //文件信息(用Unicode保存使用_wfinddata_t,多字节字符集使用_finddata_t)
1161 _wfinddata_t fileinfo;
1162 if ((hFile = _wfindfirst(file_name.c_str(), &fileinfo)) != -1)
1163 {
1164 do
1165 {
1166 if (fun_is_valid(fileinfo.name))
1167 files.push_back(fileinfo.name);
1168 } while (_wfindnext(hFile, &fileinfo) == 0);
1169 }
1170 _findclose(hFile);
1171 }
1172
GetImageFiles(wstring file_name,vector<wstring> & files)1173 void CCommon::GetImageFiles(wstring file_name, vector<wstring>& files)
1174 {
1175 files.clear();
1176 //文件句柄
1177 intptr_t hFile = 0;
1178 //文件信息(用Unicode保存使用_wfinddata_t,多字节字符集使用_finddata_t)
1179 _wfinddata_t fileinfo;
1180 if ((hFile = _wfindfirst(file_name.c_str(), &fileinfo)) != -1)
1181 {
1182 do
1183 {
1184 if (FileIsImage(fileinfo.name))
1185 files.push_back(fileinfo.name);
1186 } while (_wfindnext(hFile, &fileinfo) == 0);
1187 }
1188 _findclose(hFile);
1189 }
1190
IsFolderMatchKeyWord(wstring dir,const wstring & key_word)1191 bool CCommon::IsFolderMatchKeyWord(wstring dir, const wstring& key_word)
1192 {
1193 //文件句柄
1194 intptr_t hFile = 0;
1195 //文件信息
1196 _wfinddata_t fileinfo;
1197 if (dir.back() != '\\' && dir.back() != '/')
1198 dir.push_back('\\');
1199
1200 wstring folder_name;
1201 size_t index = dir.rfind(L'\\', dir.size() - 2);
1202 folder_name = dir.substr(index + 1, dir.size() - index - 2);
1203
1204 if ((hFile = _wfindfirst((dir + L"*").c_str(), &fileinfo)) != -1)
1205 {
1206 do
1207 {
1208 wstring file_name = fileinfo.name;
1209 if (file_name == L"." || file_name == L"..")
1210 continue;
1211
1212 if (CCommon::IsFolder(dir + file_name)) //当前是文件夹,则递归调用
1213 {
1214 if (IsFolderMatchKeyWord(dir + file_name, key_word))
1215 {
1216 _findclose(hFile);
1217 return true;
1218 }
1219 }
1220 //else
1221 //{
1222 // if (StringFindNoCase(file_name, key_word) != wstring::npos)
1223 // return true;
1224 //}
1225 } while (_wfindnext(hFile, &fileinfo) == 0);
1226
1227 if (StringFindNoCase(folder_name, key_word) != wstring::npos)
1228 {
1229 _findclose(hFile);
1230 return true;
1231 }
1232 }
1233 _findclose(hFile);
1234 return false;
1235 }
1236
FileIsImage(const wstring & file_name)1237 bool CCommon::FileIsImage(const wstring& file_name)
1238 {
1239 size_t index;
1240 index = file_name.find_last_of(L'.');
1241 wstring type;
1242 if (index != string::npos)
1243 type = file_name.substr(index); //获取扩展名
1244 std::transform(type.begin(), type.end(), type.begin(), tolower); //将扩展名转换成小写
1245 return (type == L".jpg" || type == L".jpeg" || type == L".png" || type == L".gif" || type == L".bmp");
1246 }
1247
GetRandomString(int length)1248 wstring CCommon::GetRandomString(int length)
1249 {
1250 wstring result;
1251 SYSTEMTIME current_time;
1252 GetLocalTime(¤t_time); //获取当前时间
1253 srand(current_time.wMilliseconds); //用当前时间的毫秒数设置产生随机数的种子
1254 int char_type; //当前要生成的字符类型 0:数字;1:小写字母;2:大写字母
1255 for (int i{}; i < length; i++)
1256 {
1257 char_type = rand() % 3; //随机确定要生成的字符类型
1258 wchar_t current_char;
1259 switch (char_type)
1260 {
1261 case 0:
1262 current_char = L'0' + (rand() % 10);
1263 break;
1264 case 1:
1265 current_char = L'a' + (rand() % 26);
1266 break;
1267 case 2:
1268 current_char = L'A' + (rand() % 26);
1269 break;
1270 }
1271 result.push_back(current_char);
1272 }
1273 return result;
1274 }
1275
IsFileNameNumbered(const wstring & file_name,int & number,size_t & index)1276 bool CCommon::IsFileNameNumbered(const wstring& file_name, int& number, size_t& index)
1277 {
1278 if (file_name.empty())
1279 return false;
1280 if (file_name.back() != L')')
1281 return false;
1282 size_t size{ file_name.size() };
1283 //size_t index;
1284 index = file_name.rfind(L'('); //往前查找右括号
1285 if (index == wstring::npos || index == 0) //左括号不能在字符串开头
1286 return false;
1287 wstring number_str{ file_name.substr(index + 1, size - index - 2) }; //获取两个括号之间的文本
1288 if (StrIsNumber(number_str)) //判断文本是否是数字
1289 {
1290 number = _wtoi(number_str.c_str());
1291 return true;
1292 }
1293 else
1294 {
1295 return false;
1296 }
1297 }
1298
SizeZoom(CSize & size,int side)1299 void CCommon::SizeZoom(CSize& size, int side)
1300 {
1301 float width_height_ratio{ static_cast<float>(size.cx) / size.cy }; //长宽比
1302 if (width_height_ratio > 1) //长宽比大于1:1
1303 {
1304 size.cx = side;
1305 size.cy = static_cast<int>(side / width_height_ratio);
1306 }
1307 else if (width_height_ratio < 1)
1308 {
1309 size.cy = side;
1310 size.cx = static_cast<int>(side * width_height_ratio);
1311 }
1312 else
1313 {
1314 size.cx = size.cy = side;
1315 }
1316 }
1317
GetWindowsThemeColor()1318 COLORREF CCommon::GetWindowsThemeColor()
1319 {
1320 #ifdef COMPILE_IN_WIN_XP
1321 return RGB(0, 120, 215);
1322 #else
1323 DWORD crColorization;
1324 BOOL fOpaqueBlend;
1325 COLORREF theme_color{};
1326 HRESULT result = DwmGetColorizationColor(&crColorization, &fOpaqueBlend);
1327 if (result == S_OK)
1328 {
1329 BYTE r, g, b;
1330 r = (crColorization >> 16) % 256;
1331 g = (crColorization >> 8) % 256;
1332 b = crColorization % 256;
1333 theme_color = RGB(r, g, b);
1334 }
1335 return theme_color;
1336 #endif
1337 }
1338
1339
AppendMenuOp(HMENU hDst,HMENU hSrc)1340 int CCommon::AppendMenuOp(HMENU hDst, HMENU hSrc)
1341 {
1342 int iCnt = 0;
1343 ASSERT(hDst && hSrc);
1344
1345 for (int iSrc = 0, iDst = GetMenuItemCount(hDst); iSrc < GetMenuItemCount(hSrc); iSrc++)
1346 {
1347 TCHAR szMenuStr[256] = { 0 };
1348 MENUITEMINFO mInfo = { 0 };
1349 mInfo.cbSize = sizeof(mInfo);
1350 mInfo.fMask = 0
1351 | MIIM_CHECKMARKS //Retrieves or sets the hbmpChecked and hbmpUnchecked members.
1352 | MIIM_DATA //Retrieves or sets the dwItemData member.
1353 | MIIM_ID //Retrieves or sets the wID member.
1354 | MIIM_STATE //Retrieves or sets the fState member.
1355 | MIIM_SUBMENU //Retrieves or sets the hSubMenu member.
1356 | MIIM_FTYPE //Retrieves or sets the fType and dwTypeData members.
1357 //这里如果不添加MIIM_STRING和MIIM_BITMAP,会导致有图标的菜单项文本不显示
1358 | MIIM_STRING
1359 | MIIM_BITMAP
1360 | 0;
1361 mInfo.dwTypeData = szMenuStr;
1362 mInfo.cch = _countof(szMenuStr);
1363
1364 VERIFY(GetMenuItemInfo(hSrc, iSrc, TRUE, &mInfo));
1365
1366 if (mInfo.hSubMenu)
1367 {
1368 HMENU hSub = CreatePopupMenu();
1369 AppendMenuOp(hSub, mInfo.hSubMenu);
1370 mInfo.hSubMenu = hSub;
1371 }
1372
1373 InsertMenuItem(hDst, iDst++, TRUE, &mInfo);
1374 iCnt++;
1375 }
1376
1377 return iCnt;
1378 }
1379
IsMenuItemInMenu(CMenu * pMenu,UINT id)1380 bool CCommon::IsMenuItemInMenu(CMenu* pMenu, UINT id)
1381 {
1382 if (pMenu == nullptr)
1383 return false;
1384
1385 int item_count = pMenu->GetMenuItemCount();
1386 for (int i = 0; i < item_count; i++)
1387 {
1388 if (pMenu->GetMenuItemID(i) == id)
1389 return true;
1390 CMenu* pSubMenu = pMenu->GetSubMenu(i);
1391 if (IsMenuItemInMenu(pSubMenu, id))
1392 return true;
1393 }
1394 return false;
1395 }
1396
GetMenuItemPosition(CMenu * pMenu,UINT id)1397 int CCommon::GetMenuItemPosition(CMenu* pMenu, UINT id)
1398 {
1399 int pos = -1;
1400 int item_count = pMenu->GetMenuItemCount();
1401 for (int i = 0; i < item_count; i++)
1402 {
1403 if (pMenu->GetMenuItemID(i) == id)
1404 {
1405 pos = i;
1406 break;
1407 }
1408 }
1409 return pos;
1410 }
1411
IterateMenuItem(CMenu * pMenu,std::function<void (CMenu *,UINT)> func)1412 void CCommon::IterateMenuItem(CMenu* pMenu, std::function<void(CMenu*, UINT)> func)
1413 {
1414 if (pMenu != nullptr)
1415 {
1416 int item_count = pMenu->GetMenuItemCount();
1417 for (int i = 0; i < item_count; i++)
1418 {
1419 CMenu* pSubMenu = pMenu->GetSubMenu(i);
1420 if (pSubMenu != nullptr)
1421 IterateMenuItem(pSubMenu, func);
1422 UINT id = pMenu->GetMenuItemID(i);
1423 if (id > 0)
1424 func(pMenu, id);
1425 }
1426 }
1427 }
1428
StringLeftMatch(const std::wstring & str,const std::wstring & matched_str)1429 bool CCommon::StringLeftMatch(const std::wstring& str, const std::wstring& matched_str)
1430 {
1431 if (str.size() < matched_str.size())
1432 return false;
1433 return str.substr(0, matched_str.size()) == matched_str;
1434 }
1435
GetThreadLanguageList(vector<wstring> & language_tag)1436 bool CCommon::GetThreadLanguageList(vector<wstring>& language_tag)
1437 {
1438 language_tag.clear();
1439 ULONG num{};
1440 vector<wchar_t> buffer(LOCALE_NAME_MAX_LENGTH, L'\0');
1441 ULONG buffer_size{ static_cast<ULONG>(buffer.size()) };
1442 bool rtn = GetThreadPreferredUILanguages(MUI_LANGUAGE_NAME, &num, buffer.data(), &buffer_size); // >=Windows Vista
1443 if (!rtn) return false;
1444 ASSERT(buffer_size <= LOCALE_NAME_MAX_LENGTH);
1445 size_t pos{};
1446 for (size_t i{}; i < buffer_size; ++i)
1447 {
1448 if (buffer[i] != L'\0' || pos == i)
1449 continue;
1450 wstring tmp(buffer.begin() + pos, buffer.begin() + i);
1451 language_tag.push_back(tmp);
1452 pos = i + 1;
1453 }
1454 ASSERT(language_tag.size() == num);
1455 return true;
1456 }
1457
SetThreadLanguageList(const vector<wstring> & language_tag)1458 bool CCommon::SetThreadLanguageList(const vector<wstring>& language_tag)
1459 {
1460 vector<wchar_t> buffer;
1461 size_t buffer_size{ 1 };
1462 for (const wstring& tag : language_tag)
1463 {
1464 if (tag.empty()) continue;
1465 buffer_size += tag.size() + 1;
1466 if (buffer_size > LOCALE_NAME_MAX_LENGTH)
1467 break;
1468 buffer.insert(buffer.end(), tag.begin(), tag.end());
1469 buffer.push_back(L'\0');
1470 }
1471 if (buffer.empty()) // buffer为空时多插入一个\0确保双\0结尾(空buffer会重置之前设置的线程首选UI语言列表)
1472 buffer.push_back(L'\0');
1473 buffer.push_back(L'\0');
1474 bool rtn = SetThreadPreferredUILanguages(MUI_LANGUAGE_NAME, buffer.data(), nullptr); // >=Windows Vista
1475 return rtn;
1476 }
1477
GetSystemDefaultUIFont()1478 wstring CCommon::GetSystemDefaultUIFont()
1479 {
1480 NONCLIENTMETRICS metrics;
1481 metrics.cbSize = sizeof(NONCLIENTMETRICS);
1482 SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &metrics, 0);
1483 wstring font_name = metrics.lfMessageFont.lfFaceName;
1484 return font_name;
1485 }
1486
WStringCopy(wchar_t * str_dest,int dest_size,const wchar_t * str_source,int source_size)1487 void CCommon::WStringCopy(wchar_t* str_dest, int dest_size, const wchar_t* str_source, int source_size)
1488 {
1489 if (dest_size <= 0)
1490 return;
1491 if (source_size <= 0 || str_source == nullptr)
1492 {
1493 str_dest[0] = L'\0';
1494 return;
1495 }
1496 int i;
1497 for (i = 0; i < dest_size && i < source_size && str_source[i] != L'\0'; i++)
1498 str_dest[i] = str_source[i];
1499 //确保目标字符串末尾有一个\0
1500 int copy_cnt = i;
1501 if (copy_cnt < dest_size)
1502 str_dest[copy_cnt] = L'\0';
1503 else
1504 str_dest[dest_size - 1] = L'\0';
1505 }
1506
NormalizeFont(LOGFONT & font)1507 void CCommon::NormalizeFont(LOGFONT& font)
1508 {
1509 wstring name;
1510 wstring style;
1511 name = font.lfFaceName;
1512 if (name.empty())
1513 return;
1514 if (name.back() == L' ')
1515 name.pop_back();
1516 size_t index = name.rfind(L' ');
1517 if (index == wstring::npos)
1518 return;
1519 style = name.substr(index + 1);
1520 bool style_acquired = false;
1521 if (style == L"Light")
1522 {
1523 font.lfWeight = FW_LIGHT;
1524 style_acquired = true;
1525 }
1526 else if (style == L"Semilight")
1527 {
1528 font.lfWeight = 350;
1529 style_acquired = true;
1530 }
1531 else if (style == L"ExtraLight")
1532 {
1533 font.lfWeight = FW_EXTRALIGHT;
1534 style_acquired = true;
1535 }
1536 else if (style == L"Semibold")
1537 {
1538 font.lfWeight = FW_SEMIBOLD;
1539 style_acquired = true;
1540 }
1541 else if (style == L"Bold")
1542 {
1543 font.lfWeight = FW_BOLD;
1544 style_acquired = true;
1545 }
1546 else if (style == L"ExtraBold")
1547 {
1548 font.lfWeight = FW_EXTRABOLD;
1549 style_acquired = true;
1550 }
1551 else if (style == L"Black" || style == L"Heavy")
1552 {
1553 font.lfWeight = FW_BLACK;
1554 style_acquired = true;
1555 }
1556 else if (style == L"Normal" || style == L"Regular")
1557 {
1558 font.lfWeight = FW_NORMAL;
1559 style_acquired = true;
1560 }
1561
1562 if (style_acquired)
1563 {
1564 name = name.substr(0, index);
1565 }
1566 //wcsncpy_s(font.lfFaceName, name.c_str(), 32);
1567 WStringCopy(font.lfFaceName, 32, name.c_str(), name.size());
1568 }
1569
GetMenuBarHeight(HWND hWnd)1570 int CCommon::GetMenuBarHeight(HWND hWnd)
1571 {
1572 MENUBARINFO menuInfo{};
1573 menuInfo.cbSize = sizeof(MENUBARINFO);
1574 int rtn = GetMenuBarInfo(hWnd, OBJID_MENU, 0, &menuInfo);
1575
1576 int menu_bar_height = 0;
1577 if (rtn != 0)
1578 menu_bar_height = menuInfo.rcBar.bottom - menuInfo.rcBar.top;
1579
1580 return menu_bar_height;
1581 }
1582
DoubleRound(double dVal,int format)1583 double CCommon::DoubleRound(double dVal, int format)
1584 {
1585 auto ipow = std::pow(10, format);
1586 return std::floor(dVal * ipow + 0.5) / ipow;
1587 }
1588
IconSizeNormalize(int size)1589 int CCommon::IconSizeNormalize(int size)
1590 {
1591 //查找标准图标大小列表中和指定大小最接近的一个,然后将其返回
1592
1593 const vector<int> standard_size{ 16, 20, 24, 28, 32, 48, 64, 128, 256, 512 };
1594 int min_diff = MAXINT;
1595 int index = 0;
1596 for (size_t i = 0; i < standard_size.size(); i++)
1597 {
1598 int diff = std::abs(size - standard_size[i]);
1599 if (diff == min_diff && diff > 2)
1600 return size;
1601
1602 if (diff < min_diff)
1603 {
1604 min_diff = diff;
1605 index = i;
1606 }
1607 }
1608 return standard_size[index];
1609 }
1610
SetWindowOpacity(HWND hWnd,int opacity)1611 void CCommon::SetWindowOpacity(HWND hWnd, int opacity)
1612 {
1613 SetWindowLong(hWnd, GWL_EXSTYLE, GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_LAYERED);
1614 ::SetLayeredWindowAttributes(hWnd, 0, opacity * 255 / 100, LWA_ALPHA); //透明度取值范围为0~255
1615 }
1616
StringIsVersion(LPCTSTR str)1617 bool CCommon::StringIsVersion(LPCTSTR str)
1618 {
1619 CString version_str{ str };
1620 return (version_str.GetLength() == 4 || version_str.GetLength() == 5) && version_str[1] == _T('.') && CharIsNumber(version_str[0]) && CharIsNumber(version_str[2]) && CharIsNumber(version_str[3]);
1621 }
1622
GetFileContent(const wchar_t * file_path,string & contents_buff,size_t max_size)1623 bool CCommon::GetFileContent(const wchar_t* file_path, string& contents_buff, size_t max_size)
1624 {
1625 std::ifstream file{ file_path, std::ios::binary | std::ios::in };
1626 if (file.fail())
1627 return false;
1628 //获取文件长度
1629 file.seekg(0, file.end);
1630 unsigned int length{ static_cast<unsigned int>(file.tellg()) };
1631 file.seekg(0, file.beg);
1632
1633 char* buff = new char[length];
1634 file.read(buff, length);
1635 file.close();
1636
1637 contents_buff.assign(buff, length);
1638 delete[] buff;
1639
1640 return true;
1641 }
1642
GetFileContent(const wchar_t * file_path,size_t & length)1643 const char* CCommon::GetFileContent(const wchar_t* file_path, size_t& length)
1644 {
1645 std::ifstream file{ file_path, std::ios::binary };
1646 length = 0;
1647 if (file.fail())
1648 return nullptr;
1649 //获取文件长度
1650 file.seekg(0, file.end);
1651 length = static_cast<size_t>(file.tellg());
1652 file.seekg(0, file.beg);
1653
1654 char* buff = new char[length];
1655 file.read(buff, length);
1656 file.close();
1657
1658 return buff;
1659 }
1660
SaveDataToFile(const string & data,const wstring & file_path)1661 bool CCommon::SaveDataToFile(const string& data, const wstring& file_path)
1662 {
1663 ofstream out_put{ file_path, std::ios::binary };
1664 if (!out_put.is_open())
1665 return false;
1666 if (!data.empty())
1667 out_put << data;
1668 out_put.close();
1669 return true;
1670 }
1671
DoOpenFileDlg(const wstring & filter,vector<wstring> & path_list,CWnd * pParent)1672 void CCommon::DoOpenFileDlg(const wstring& filter, vector<wstring>& path_list, CWnd* pParent)
1673 {
1674 path_list.clear();
1675 //构造打开文件对话框
1676 CFileDialog fileDlg(TRUE, NULL, NULL, OFN_ALLOWMULTISELECT, filter.c_str(), pParent);
1677 //设置保存文件名的字符缓冲的大小为128kB(如果以平均一个文件名长度为32字节计算,最多可以打开大约4096个文件)
1678 fileDlg.m_ofn.nMaxFile = 128 * 1024;
1679 LPTSTR ch = new TCHAR[fileDlg.m_ofn.nMaxFile];
1680 fileDlg.m_ofn.lpstrFile = ch;
1681 //对内存块清零
1682 ZeroMemory(fileDlg.m_ofn.lpstrFile, sizeof(TCHAR) * fileDlg.m_ofn.nMaxFile);
1683 //显示打开文件对话框
1684 if (IDOK == fileDlg.DoModal())
1685 {
1686 POSITION posFile = fileDlg.GetStartPosition();
1687 while (posFile != NULL)
1688 {
1689 path_list.push_back(fileDlg.GetNextPathName(posFile).GetString());
1690 }
1691 }
1692 delete[] ch;
1693
1694 }
1695
SetDialogFont(CWnd * pDlg,CFont * pFont)1696 void CCommon::SetDialogFont(CWnd* pDlg, CFont* pFont)
1697 {
1698 if (pDlg->GetSafeHwnd() != NULL)
1699 {
1700 CWnd* pWndChild;
1701 pWndChild = pDlg->GetWindow(GW_CHILD);
1702 while (pWndChild)
1703 {
1704 pWndChild->SetFont(pFont);
1705 pWndChild = pWndChild->GetWindow(GW_HWNDNEXT);
1706 }
1707 }
1708 }
1709
FileAutoRename(wstring & file_path)1710 void CCommon::FileAutoRename(wstring& file_path)
1711 {
1712 while (CCommon::FileExist(file_path))
1713 {
1714 //判断文件名的末尾是否符合“(数字)”的形式
1715 wstring file_name; //文件名(不含扩展名)
1716 CFilePathHelper c_file_path(file_path);
1717 file_name = c_file_path.GetFileNameWithoutExtension();
1718 wstring ext{ c_file_path.GetFileExtension() };
1719 int num;
1720 size_t index;
1721 bool is_numbered{ CCommon::IsFileNameNumbered(file_name, num, index) }; //文件名的末尾是否符合“(数字)”的形式
1722 if (!is_numbered) //如果文件名末尾没有“(数字)”,则在末尾添加“ (1)”
1723 {
1724 file_name += L" (1)";
1725 }
1726 else //否则,将原来的数字加1
1727 {
1728 file_name = file_name.substr(0, index);
1729 CString num_str;
1730 num_str.Format(_T("(%d)"), num + 1);
1731 file_name += num_str;
1732 }
1733 file_path = c_file_path.GetDir() + file_name + L'.' + ext;
1734 }
1735
1736 }
1737
StringCompareInLocalLanguage(const wstring & str1,const wstring & str2,bool no_case)1738 int CCommon::StringCompareInLocalLanguage(const wstring& str1, const wstring& str2, bool no_case)
1739 {
1740 #ifndef COMPILE_IN_WIN_XP
1741 int rtn = CompareStringEx(LOCALE_NAME_USER_DEFAULT, (no_case ? NORM_IGNORECASE : 0) | SORT_DIGITSASNUMBERS, str1.c_str(), str1.size(), str2.c_str(), str2.size(), NULL, NULL, 0);
1742 #else
1743 int rtn = CompareString(LOCALE_NAME_USER_DEFAULT, (no_case ? NORM_IGNORECASE : 0), str1.c_str(), str1.size(), str2.c_str(), str2.size());
1744 #endif
1745 if (rtn == CSTR_EQUAL)
1746 return 0;
1747 else if (rtn == CSTR_GREATER_THAN)
1748 return 1;
1749 else
1750 return -1;
1751 }
1752
SetNumberBit(unsigned short & num,int bit,bool value)1753 void CCommon::SetNumberBit(unsigned short& num, int bit, bool value)
1754 {
1755 if (value)
1756 {
1757 num |= (1 << bit);
1758 }
1759 else
1760 {
1761 num &= ~(1 << bit);
1762 }
1763 }
1764
GetNumberBit(unsigned short num,int bit)1765 bool CCommon::GetNumberBit(unsigned short num, int bit)
1766 {
1767 return (num & (1 << bit)) != 0;
1768 }
1769
GetTextResourceRawData(UINT id)1770 std::string CCommon::GetTextResourceRawData(UINT id)
1771 {
1772 std::string res_data;
1773 HINSTANCE hInstance = AfxGetResourceHandle();
1774 HRSRC hRsrc = FindResource(NULL, MAKEINTRESOURCE(id), _T("TEXT"));
1775 if (hRsrc != NULL)
1776 {
1777 HGLOBAL hGlobal = LoadResource(NULL, hRsrc);
1778 if (hGlobal != NULL)
1779 {
1780 const char* pResource = static_cast<const char*>(LockResource(hGlobal));
1781 if (pResource != NULL)
1782 {
1783 // 获取资源大小
1784 DWORD dwSize = SizeofResource(hInstance, hRsrc);
1785 // 将资源数据存储到std::string
1786 return std::string(pResource, dwSize);
1787 }
1788 UnlockResource(hGlobal);
1789 }
1790 }
1791 return res_data;
1792 }
1793
GetTextResource(UINT id,CodeType code_type)1794 wstring CCommon::GetTextResource(UINT id, CodeType code_type)
1795 {
1796 string res_data = GetTextResourceRawData(id);
1797 wstring res_str = CCommon::StrToUnicode(res_data, code_type);
1798 return res_str;
1799 }
1800
GetPngImageResource(UINT id)1801 Gdiplus::Image* CCommon::GetPngImageResource(UINT id)
1802 {
1803 Gdiplus::Image* pImage = nullptr;
1804 HINSTANCE hInst = AfxGetResourceHandle();
1805 if (HRSRC hRes = ::FindResource(hInst, MAKEINTRESOURCE(id), _T("PNG")))
1806 {
1807 DWORD imageSize = ::SizeofResource(hInst, hRes);
1808 if (HGLOBAL hResData = ::LoadResource(hInst, hRes))
1809 {
1810 LPVOID pResourceData = ::LockResource(hResData);
1811 #ifdef COMPILE_IN_WIN_XP
1812 if (HGLOBAL hBuffer = ::GlobalAlloc(GMEM_FIXED, imageSize))
1813 {
1814 ::CopyMemory(hBuffer, pResourceData, imageSize);
1815 IStream* pStream = nullptr;
1816 if (SUCCEEDED(::CreateStreamOnHGlobal(hBuffer, TRUE, &pStream)))
1817 {
1818 pImage = Gdiplus::Image::FromStream(pStream);
1819 pStream->Release();
1820 }
1821 ::GlobalFree(hBuffer); // 释放内存句柄
1822 }
1823 #else // 在缓冲区上创建内存流
1824 if (IStream* pStream = SHCreateMemStream(static_cast<const BYTE*>(pResourceData), imageSize))
1825 {
1826 pImage = Gdiplus::Image::FromStream(pStream);
1827 pStream->Release();
1828 }
1829 #endif // COMPILE_IN_WIN_XP
1830 ::FreeResource(hResData);
1831 }
1832 }
1833 return pImage;
1834 }
1835
1836
GetPngImageResourceData(UINT id)1837 string CCommon::GetPngImageResourceData(UINT id)
1838 {
1839 string data;
1840 HINSTANCE hInst = AfxGetResourceHandle();
1841 if (HRSRC hRes = ::FindResource(hInst, MAKEINTRESOURCE(id), _T("PNG")))
1842 {
1843 DWORD imageSize = ::SizeofResource(hInst, hRes);
1844 if (HGLOBAL hResData = ::LoadResource(hInst, hRes))
1845 {
1846 LPVOID pResourceData = ::LockResource(hResData);
1847 data = string(static_cast<const char*>(pResourceData), imageSize);
1848 ::FreeResource(hResData);
1849 }
1850 }
1851 return data;
1852 }
1853
Random(int min,int max)1854 int CCommon::Random(int min, int max)
1855 {
1856 std::random_device rd;
1857 std::mt19937 engine(rd());
1858 std::uniform_int_distribution<int> dis(min, max - 1);
1859 int dis_{ dis(engine) };
1860 return dis_;
1861 }
1862
GetDesktopBackgroundPath()1863 CString CCommon::GetDesktopBackgroundPath()
1864 {
1865 CString path;
1866 CRegKey key;
1867 if (key.Open(HKEY_CURRENT_USER, _T("Control Panel\\Desktop\\")) == ERROR_SUCCESS)
1868 {
1869 TCHAR buff[MAX_PATH]{};
1870 ULONG size{ MAX_PATH };
1871 key.QueryStringValue(_T("WallPaper"), buff, &size);
1872 path = buff;
1873 }
1874 return path;
1875 }
1876
CalculateWindowMoveOffset(CRect & check_rect,vector<CRect> & screen_rects)1877 POINT CCommon::CalculateWindowMoveOffset(CRect& check_rect, vector<CRect>& screen_rects)
1878 {
1879 POINT mov{}; // 所需偏移量
1880 // 确保窗口在一个监视器内并且可见,判断移动距离并向所需移动距离较小的方向移动
1881 LONG mov_xy = 0; // 记录移动距离
1882 for (auto& a : screen_rects)
1883 {
1884 LONG x = 0, y = 0;
1885 if (check_rect.left < a.left || check_rect.Width() > a.Width()) // 需要向右移动
1886 x = a.left - check_rect.left;
1887 else if (check_rect.right > a.right) // 需要向左移动
1888 x = a.right - check_rect.right;
1889 if (check_rect.top < a.top || check_rect.Height() > a.Height()) // 需要向下移动
1890 y = a.top - check_rect.top;
1891 else if (check_rect.bottom > a.bottom) // 需要向上移动
1892 y = a.bottom - check_rect.bottom;
1893 if (x == 0 && y == 0) // 窗口已在一个监视器内
1894 {
1895 mov.x = 0;
1896 mov.y = 0;
1897 break;
1898 }
1899 else if (abs(x) + abs(y) < mov_xy || mov_xy == 0)
1900 {
1901 mov.x = x;
1902 mov.y = y;
1903 mov_xy = abs(x) + abs(y);
1904 }
1905 }
1906 return mov;
1907 }
1908
GetLastCompileTime(wstring & time_str,wstring & hash_str)1909 void CCommon::GetLastCompileTime(wstring& time_str, wstring& hash_str)
1910 {
1911 wstring compile_time = GetTextResource(IDR_COMPILE_TIME, CodeType::ANSI);
1912 size_t pos = compile_time.find(L"\r\n");
1913 time_str = compile_time.substr(0, pos);
1914 if (compile_time.size() > pos + 10) // 如果hash存在
1915 hash_str = compile_time.substr(pos + 2, 8); // 截取hash前8位
1916 }
1917
GetCurTimeElapse()1918 unsigned __int64 CCommon::GetCurTimeElapse()
1919 {
1920 SYSTEMTIME sys_time;
1921 GetLocalTime(&sys_time);
1922 CTime cur_time(sys_time);
1923 unsigned __int64 c_time = cur_time.GetTime();
1924 static unsigned __int64 last_time{};
1925 // 此处用作排序时间戳,需要避免重复
1926 last_time = (last_time < c_time) ? c_time : (last_time + 1);
1927 return last_time;
1928 }
1929
EncodeURIComponent(wstring uri)1930 wstring CCommon::EncodeURIComponent(wstring uri) {
1931 StrReplace(uri, L"%", L"%25");
1932 StrReplace(uri, L":", L"%3A");
1933 StrReplace(uri, L"/", L"%2F");
1934 StrReplace(uri, L"?", L"%3F");
1935 StrReplace(uri, L"#", L"%23");
1936 StrReplace(uri, L"[", L"%5B");
1937 StrReplace(uri, L"]", L"%5D");
1938 StrReplace(uri, L"@", L"%40");
1939 StrReplace(uri, L"$", L"%24");
1940 StrReplace(uri, L"&", L"%26");
1941 StrReplace(uri, L"+", L"%2B");
1942 StrReplace(uri, L",", L"%2C");
1943 StrReplace(uri, L";", L"%3B");
1944 StrReplace(uri, L"=", L"%3D");
1945 return uri;
1946 }
1947
OutputDebugStringFormat(LPCTSTR str,...)1948 void CCommon::OutputDebugStringFormat(LPCTSTR str, ...)
1949 {
1950 va_list args;
1951 va_start(args, str);
1952 TCHAR buf[1024] = { 0 };
1953 StringCchVPrintf(buf, 1023, str, args);
1954 va_end(args);
1955 buf[1023] = L'\0';
1956 OutputDebugString(buf);
1957 }
1958
StrReplace(wstring & input,wstring pattern,wstring new_content)1959 wstring CCommon::StrReplace(wstring& input, wstring pattern, wstring new_content) {
1960 auto loc = input.find(pattern, 0);
1961 auto len = pattern.length();
1962 auto len2 = new_content.length();
1963 while (loc != -1) {
1964 input.replace(loc, len, new_content);
1965 if (loc + len2 < input.length()) loc = input.find(pattern, max(0, loc + len2));
1966 else break;
1967 }
1968 return input;
1969 }
1970