|
@@ -0,0 +1,1098 @@
|
|
|
+#include "StdAfx.h"
|
|
|
+#include "Global.h"
|
|
|
+
|
|
|
+
|
|
|
+#include <WinVer.h>
|
|
|
+#pragma comment(lib,"version.lib")
|
|
|
+using namespace std;
|
|
|
+#include <psapi.h>
|
|
|
+#pragma comment(lib,"Psapi.lib")
|
|
|
+#include <locale.h>
|
|
|
+#include <io.h>//_access头文件;
|
|
|
+
|
|
|
+TCHAR g_szModulePath[MAX_PATH] = _T("");
|
|
|
+TCHAR g_szModuleFileName[MAX_PATH] = _T("");
|
|
|
+TCHAR g_szIniFile[MAX_PATH] = _T("");
|
|
|
+
|
|
|
+
|
|
|
+TCHAR g_szServAddress[MAX_PATH] = _T("");
|
|
|
+DWORD g_dwServPort = 0;
|
|
|
+TCHAR g_szAccount[MAX_PATH] = _T("");
|
|
|
+TCHAR g_szPassword[MAX_PATH] = _T("");
|
|
|
+TCHAR g_szWeChatPath[MAX_PATH] = _T("");
|
|
|
+TCHAR g_szCacheDir[MAX_PATH] = _T("");
|
|
|
+TCHAR g_szDynamicLibraryPath[MAX_PATH] = _T("");
|
|
|
+
|
|
|
+
|
|
|
+BOOL g_bStdOut = FALSE;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+int GetIniInfo(LPCTSTR lpIniDir , LPCTSTR lpIniName )
|
|
|
+{
|
|
|
+ TCHAR szDrive[_MAX_DRIVE] = { 0 };
|
|
|
+ TCHAR szDir[_MAX_DIR] = { 0 };
|
|
|
+ TCHAR szFna[_MAX_DIR] = { 0 };
|
|
|
+ TCHAR szExt[_MAX_DIR] = { 0 };
|
|
|
+ ::GetModuleFileName(NULL, g_szModulePath, sizeof(g_szModulePath) / sizeof(TCHAR));
|
|
|
+ _stprintf_s(g_szModuleFileName, _T("%s"), g_szModulePath);
|
|
|
+
|
|
|
+ _tsplitpath_s(g_szModulePath, szDrive, szDir, szFna, szExt);
|
|
|
+ _tcscpy_s(g_szModulePath, szDrive);
|
|
|
+ _tcscat_s(g_szModulePath, szDir);
|
|
|
+
|
|
|
+
|
|
|
+ _stprintf_s(g_szDynamicLibraryPath, _T("%shook.dll"), g_szModulePath);
|
|
|
+#ifdef _DEBUG
|
|
|
+
|
|
|
+ WriteTextLog(_T("DLL路径=%s"),g_szDynamicLibraryPath);
|
|
|
+#endif
|
|
|
+
|
|
|
+ if (lpIniDir != NULL && lpIniName != NULL)
|
|
|
+ _stprintf_s(g_szIniFile, _T("%s%s"), lpIniDir, lpIniName);
|
|
|
+ else
|
|
|
+ _stprintf_s(g_szIniFile, _T("%sconfig.ini"), g_szModulePath);
|
|
|
+
|
|
|
+ HANDLE hFile = CreateFile(g_szIniFile, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
|
|
|
+
|
|
|
+ if (ERROR_FILE_NOT_FOUND == GetLastError())
|
|
|
+ {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ CloseHandle(hFile);
|
|
|
+ hFile = NULL;
|
|
|
+
|
|
|
+
|
|
|
+ GetPrivateProfileString(_T("ServerInfo"), _T("IP"), _T(""), g_szServAddress, MAX_PATH, g_szIniFile);
|
|
|
+ g_dwServPort = GetPrivateProfileInt(_T("ServerInfo"), _T("Port"), 0, g_szIniFile);
|
|
|
+ GetPrivateProfileString(_T("CustomerInfo"), _T("Account"), _T(""), g_szAccount, MAX_PATH, g_szIniFile);
|
|
|
+ GetPrivateProfileString(_T("CustomerInfo"), _T("Password"), _T(""), g_szPassword, MAX_PATH, g_szIniFile);
|
|
|
+ GetPrivateProfileString(_T("CustomerInfo"), _T("WeChat"), _T(""), g_szWeChatPath, MAX_PATH, g_szIniFile);
|
|
|
+ GetPrivateProfileString(_T("CustomerInfo"), _T("Cache"), _T(""), g_szCacheDir, MAX_PATH, g_szIniFile);
|
|
|
+
|
|
|
+ g_bStdOut = GetPrivateProfileInt(_T("CustomerInfo"), _T("StdOut"), 0, g_szIniFile);
|
|
|
+ if ( g_bStdOut )
|
|
|
+ {
|
|
|
+ AllocConsole();
|
|
|
+ SetConsoleTitle(_T("调试输出"));
|
|
|
+ freopen("CONOUT$", "w+t", stdout);
|
|
|
+ freopen("CONIN$", "r+t", stdin);
|
|
|
+
|
|
|
+ HWND hWnd = NULL;
|
|
|
+again:
|
|
|
+ hWnd = ::FindWindow(NULL, _T("调试输出"));
|
|
|
+ if( hWnd )
|
|
|
+ {
|
|
|
+ if (!::SetWindowPos(hWnd, HWND_TOPMOST, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE))
|
|
|
+ {
|
|
|
+ _tprintf_s(_T("前置设置失败\n"));
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ _tprintf_s(_T("前置设置成功\n"));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ goto again;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+DWORD FindProcess(LPCTSTR lpProName)
|
|
|
+{
|
|
|
+ ASSERT(lpProName!=NULL);
|
|
|
+
|
|
|
+ DWORD dwPID = 0;
|
|
|
+ PROCESSENTRY32 pe32 = { 0 };
|
|
|
+
|
|
|
+ HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
|
|
+ if (hSnapshot == NULL)
|
|
|
+ {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ pe32.dwSize = sizeof(PROCESSENTRY32);
|
|
|
+
|
|
|
+ if (Process32First(hSnapshot, &pe32))
|
|
|
+ {
|
|
|
+ do {
|
|
|
+ if (_tcsicmp(lpProName, pe32.szExeFile) == 0)
|
|
|
+ {
|
|
|
+ dwPID = pe32.th32ProcessID;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ } while (Process32Next(hSnapshot, &pe32));
|
|
|
+ }
|
|
|
+ CloseHandle(hSnapshot);
|
|
|
+
|
|
|
+ return dwPID;
|
|
|
+}
|
|
|
+
|
|
|
+vector<DWORD> FindAllProcess(LPCTSTR lpProName)
|
|
|
+{
|
|
|
+ ASSERT(lpProName!=NULL);
|
|
|
+
|
|
|
+ vector<DWORD> vtPID;
|
|
|
+ PROCESSENTRY32 pe32 = { 0 };
|
|
|
+
|
|
|
+ HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
|
|
+ if (hSnapshot == NULL)
|
|
|
+ return vector<DWORD>();
|
|
|
+
|
|
|
+ pe32.dwSize = sizeof(PROCESSENTRY32);
|
|
|
+ if (Process32First(hSnapshot, &pe32))
|
|
|
+ {
|
|
|
+ do {
|
|
|
+ if (_tcsicmp(lpProName, pe32.szExeFile) == 0)
|
|
|
+ {
|
|
|
+ vtPID.push_back(pe32.th32ProcessID);
|
|
|
+ }
|
|
|
+ } while (Process32Next(hSnapshot, &pe32));
|
|
|
+ }
|
|
|
+ CloseHandle(hSnapshot);
|
|
|
+
|
|
|
+ return vtPID;
|
|
|
+}
|
|
|
+
|
|
|
+void FindAllProcess(std::vector<ProInfo> &vtProInfo)
|
|
|
+{
|
|
|
+ PROCESSENTRY32 pe32 = { 0 };
|
|
|
+ HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
|
|
+ if (hSnapshot == NULL)
|
|
|
+ return;
|
|
|
+
|
|
|
+ pe32.dwSize = sizeof(PROCESSENTRY32);
|
|
|
+ if (!Process32First(hSnapshot, &pe32))
|
|
|
+ goto end;
|
|
|
+
|
|
|
+ do
|
|
|
+ {
|
|
|
+ ProInfo proinfo;
|
|
|
+ proinfo.dwProId = pe32.th32ProcessID;
|
|
|
+ proinfo.strProName = pe32.szExeFile;
|
|
|
+ vtProInfo.push_back(proinfo);
|
|
|
+ } while (Process32Next(hSnapshot, &pe32));
|
|
|
+
|
|
|
+end:
|
|
|
+ CloseHandle(hSnapshot);
|
|
|
+}
|
|
|
+
|
|
|
+HANDLE FindModule(LPCTSTR lpModuleName, DWORD dwPID)
|
|
|
+{
|
|
|
+ ASSERT(lpModuleName!=NULL);
|
|
|
+
|
|
|
+ DWORD dwMID = 0;
|
|
|
+ MODULEENTRY32 me32 = { 0 };
|
|
|
+ HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPALL, dwPID);
|
|
|
+ if (hSnapshot == NULL)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ me32.dwSize = sizeof(PROCESSENTRY32);
|
|
|
+ if (Module32First(hSnapshot, &me32))
|
|
|
+ {
|
|
|
+ do {
|
|
|
+ if (_tcsicmp(lpModuleName, me32.szModule) == 0)
|
|
|
+ {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ } while (Module32Next(hSnapshot, &me32));
|
|
|
+ }
|
|
|
+ CloseHandle(hSnapshot);
|
|
|
+
|
|
|
+ return me32.hModule;
|
|
|
+}
|
|
|
+
|
|
|
+HANDLE FindModuleEx(LPCTSTR lpModuleName, DWORD dwPid)
|
|
|
+{
|
|
|
+ HMODULE hMods[1024] = {0};
|
|
|
+ DWORD cbNeeded = 0;
|
|
|
+ TCHAR szModName[MAX_PATH];
|
|
|
+ BOOL Wow64Process;
|
|
|
+
|
|
|
+ HANDLE hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ|PROCESS_QUERY_LIMITED_INFORMATION, FALSE, dwPid);
|
|
|
+ IsWow64Process(hProcess, &Wow64Process);
|
|
|
+ if ( EnumProcessModulesEx(hProcess, hMods, sizeof(hMods), &cbNeeded, Wow64Process?LIST_MODULES_32BIT:LIST_MODULES_64BIT) )
|
|
|
+ {
|
|
|
+ for (UINT i = 0; i < (cbNeeded / sizeof(HMODULE)); i++ )
|
|
|
+ {
|
|
|
+ GetModuleFileNameEx(hProcess, hMods[i], szModName, _countof(szModName));
|
|
|
+#ifdef _DEBUG
|
|
|
+ WriteTextLog(_T("目标=%s, 原始=%s, 地址=%p"), szModName, lpModuleName, hMods[i]);
|
|
|
+#endif
|
|
|
+ if (_tcsicmp(lpModuleName, szModName) == 0)
|
|
|
+ {
|
|
|
+ CloseHandle(hProcess);
|
|
|
+ WriteTextLog(_T("【目标=%s, 原始=%s, 地址=%p】"), szModName, lpModuleName, hMods[i]);
|
|
|
+ return hMods[i];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ CloseHandle(hProcess);
|
|
|
+
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+BOOL GetDebugPriv()
|
|
|
+{
|
|
|
+
|
|
|
+ HANDLE hToken;
|
|
|
+
|
|
|
+ LUID sedebugnameValue;
|
|
|
+
|
|
|
+ TOKEN_PRIVILEGES tkp;
|
|
|
+
|
|
|
+
|
|
|
+ HANDLE hCurProc = ::GetCurrentProcess();
|
|
|
+
|
|
|
+
|
|
|
+ if (!::OpenProcessToken(hCurProc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
|
|
|
+ {
|
|
|
+ return FALSE;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!::LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &sedebugnameValue))
|
|
|
+ {
|
|
|
+ CloseHandle(hToken);
|
|
|
+ return FALSE;
|
|
|
+ }
|
|
|
+
|
|
|
+ tkp.PrivilegeCount = 1;
|
|
|
+ tkp.Privileges[0].Luid = sedebugnameValue;
|
|
|
+ tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
|
|
+
|
|
|
+ if (!::AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof tkp, NULL, NULL))
|
|
|
+ {
|
|
|
+ CloseHandle(hToken);
|
|
|
+ return FALSE;
|
|
|
+ }
|
|
|
+
|
|
|
+ CloseHandle(hCurProc);
|
|
|
+ CloseHandle(hToken);
|
|
|
+ return TRUE;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ 函数:GetFileVersion
|
|
|
+ 描述:获取可执行文件的文件版号;
|
|
|
+ 参数:
|
|
|
+ hModule[IN] 可执行文件模块句柄;
|
|
|
+ dwArray[OUT] 返回的文件版本号;
|
|
|
+ 返回:
|
|
|
+ 成功返回TRUE,失败返回FALSE;
|
|
|
+ 注意:
|
|
|
+ 当hModule为空时,表示要获取的可执行文件为本程序的文件版本号;
|
|
|
+*/
|
|
|
+
|
|
|
+BOOL GetFileVersion( IN HMODULE hModule, OUT DWORD (&dwArray)[4])
|
|
|
+{
|
|
|
+ TCHAR fname[MAX_PATH];
|
|
|
+ VS_FIXEDFILEINFO *pVi;
|
|
|
+ DWORD dwHandle;
|
|
|
+
|
|
|
+ if ( GetModuleFileName(hModule, fname, MAX_PATH))
|
|
|
+ {
|
|
|
+ INT nSize = GetFileVersionInfoSize(fname, &dwHandle);
|
|
|
+
|
|
|
+ if (nSize > 0)
|
|
|
+ {
|
|
|
+ BYTE *pBuffer = new BYTE[nSize];
|
|
|
+ memset(pBuffer, 0, nSize);
|
|
|
+
|
|
|
+ if (GetFileVersionInfo(fname, dwHandle, nSize, pBuffer))
|
|
|
+ {
|
|
|
+ if (VerQueryValue(pBuffer, _T("\\"), (LPVOID *)&pVi, (PUINT)&nSize))
|
|
|
+ {
|
|
|
+ dwArray[0] = HIWORD(pVi->dwFileVersionMS);
|
|
|
+ dwArray[1] = LOWORD(pVi->dwFileVersionMS);
|
|
|
+ dwArray[2] = HIWORD(pVi->dwFileVersionLS);
|
|
|
+ dwArray[3] = LOWORD(pVi->dwFileVersionLS);
|
|
|
+
|
|
|
+ delete[]pBuffer;
|
|
|
+ return TRUE;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if ( pBuffer )
|
|
|
+ delete[]pBuffer;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return FALSE;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ 函数:GetFileVersion
|
|
|
+ 描述:获取可执行文件的文件版号;
|
|
|
+ 参数:
|
|
|
+ lpFileName[IN] 可执行文件名全路径;
|
|
|
+ dwArray[OUT] 返回的文件版本号;
|
|
|
+ 返回:
|
|
|
+ 成功返回TRUE,失败返回FALSE;
|
|
|
+ 注意:
|
|
|
+*/
|
|
|
+
|
|
|
+BOOL GetFileVersionEx( IN LPCTSTR lpFileName, IN DWORD (&dwArray)[4] )
|
|
|
+{
|
|
|
+ if ( lpFileName == NULL || !PathFileExists(lpFileName) )
|
|
|
+ {
|
|
|
+ OutputDebugString(_T("文件名错误或文件不存在\n"));
|
|
|
+ return FALSE;
|
|
|
+ }
|
|
|
+
|
|
|
+ DWORD dwHandle = 0;
|
|
|
+ VS_FIXEDFILEINFO *pVi = NULL;
|
|
|
+ INT nSize = GetFileVersionInfoSize(lpFileName, &dwHandle);
|
|
|
+ if ( nSize > 0 )
|
|
|
+ {
|
|
|
+ BYTE *pBuffer = new BYTE[nSize];
|
|
|
+ memset(pBuffer, 0, nSize);
|
|
|
+
|
|
|
+ if ( GetFileVersionInfo(lpFileName, dwHandle, nSize, pBuffer) )
|
|
|
+ {
|
|
|
+ if (VerQueryValue(pBuffer, _T("\\"), (LPVOID *)&pVi, (PUINT)&nSize))
|
|
|
+ {
|
|
|
+ dwArray[0] = HIWORD(pVi->dwFileVersionMS);
|
|
|
+ dwArray[1] = LOWORD(pVi->dwFileVersionMS);
|
|
|
+ dwArray[2] = HIWORD(pVi->dwFileVersionLS);
|
|
|
+ dwArray[3] = LOWORD(pVi->dwFileVersionLS);
|
|
|
+
|
|
|
+ if (pBuffer)
|
|
|
+ delete[]pBuffer;
|
|
|
+ return TRUE;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (pBuffer)
|
|
|
+ delete[]pBuffer;
|
|
|
+ }
|
|
|
+
|
|
|
+ return FALSE;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ 函数:GetProductVersion
|
|
|
+ 描述:获取可执行文件的产品版号;
|
|
|
+ 参数:
|
|
|
+ hModule[IN] 可执行文件模块句柄;
|
|
|
+ dwArray[OUT] 返回的产品版本号;
|
|
|
+ 返回:
|
|
|
+ 成功返回TRUE,失败返回FALSE;
|
|
|
+ 注意:
|
|
|
+ 当hModule为空时,表示要获取的可执行文件为本程序的产品版本号;
|
|
|
+*/
|
|
|
+
|
|
|
+BOOL GetProductVersion(IN HMODULE hModule, IN DWORD (&dwArray)[4] )
|
|
|
+{
|
|
|
+ TCHAR fname[MAX_PATH];
|
|
|
+ VS_FIXEDFILEINFO *pVi;
|
|
|
+ DWORD dwHandle;
|
|
|
+
|
|
|
+ if (::GetModuleFileName(hModule, fname, MAX_PATH))
|
|
|
+ {
|
|
|
+ INT nSize = GetFileVersionInfoSize(fname, &dwHandle);
|
|
|
+
|
|
|
+ if (nSize > 0)
|
|
|
+ {
|
|
|
+ BYTE *pBuffer = new BYTE[nSize];
|
|
|
+ memset(pBuffer, 0, nSize);
|
|
|
+
|
|
|
+ if (GetFileVersionInfo(fname, dwHandle, nSize, pBuffer))
|
|
|
+ {
|
|
|
+ if (VerQueryValue(pBuffer, _T("\\"), (LPVOID *)&pVi, (PUINT)&nSize))
|
|
|
+ {
|
|
|
+ dwArray[0] = HIWORD(pVi->dwProductVersionMS);
|
|
|
+ dwArray[1] = LOWORD(pVi->dwProductVersionMS);
|
|
|
+ dwArray[2] = HIWORD(pVi->dwProductVersionLS);
|
|
|
+ dwArray[3] = LOWORD(pVi->dwProductVersionLS);
|
|
|
+
|
|
|
+ if(pBuffer)
|
|
|
+ delete[]pBuffer;
|
|
|
+ return TRUE;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(pBuffer)
|
|
|
+ delete[]pBuffer;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return FALSE;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ 函数:GetProductVersion
|
|
|
+ 描述:获取可执行文件的产品版号;
|
|
|
+ 参数:
|
|
|
+ lpFileName[IN] 可执行文件名全路径;
|
|
|
+ dwArray[OUT] 返回的产品版本号;
|
|
|
+ 返回:
|
|
|
+ 成功返回TRUE,失败返回FALSE;
|
|
|
+ 注意:
|
|
|
+*/
|
|
|
+
|
|
|
+BOOL GetProductVersionEx( IN LPCTSTR lpFileName, IN DWORD (&dwArray)[4] )
|
|
|
+{
|
|
|
+ if ( lpFileName == NULL || !PathFileExists(lpFileName) )
|
|
|
+ {
|
|
|
+ OutputDebugString(_T("文件名错误或文件不存在\n"));
|
|
|
+ return FALSE;
|
|
|
+ }
|
|
|
+
|
|
|
+ DWORD dwHandle = 0;
|
|
|
+ VS_FIXEDFILEINFO *pVi = NULL;
|
|
|
+ INT nSize = GetFileVersionInfoSize(lpFileName, &dwHandle);
|
|
|
+ if ( nSize > 0 )
|
|
|
+ {
|
|
|
+ BYTE *pBuffer = new BYTE[nSize];
|
|
|
+ memset(pBuffer, 0, nSize);
|
|
|
+
|
|
|
+ if ( GetFileVersionInfo(lpFileName, dwHandle, nSize, pBuffer) )
|
|
|
+ {
|
|
|
+ if (VerQueryValue(pBuffer, _T("\\"), (LPVOID *)&pVi, (PUINT)&nSize))
|
|
|
+ {
|
|
|
+ dwArray[0] = HIWORD(pVi->dwProductVersionMS);
|
|
|
+ dwArray[1] = LOWORD(pVi->dwProductVersionMS);
|
|
|
+ dwArray[2] = HIWORD(pVi->dwProductVersionLS);
|
|
|
+ dwArray[3] = LOWORD(pVi->dwProductVersionLS);
|
|
|
+
|
|
|
+ if (pBuffer)
|
|
|
+ delete[]pBuffer;
|
|
|
+ return TRUE;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (pBuffer)
|
|
|
+ delete[]pBuffer;
|
|
|
+ }
|
|
|
+
|
|
|
+ return FALSE;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+void WriteTextLog(const TCHAR *format, ...)
|
|
|
+{
|
|
|
+#if 0
|
|
|
+ try
|
|
|
+ {
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ TCHAR szlogpath[MAX_PATH] = {0};
|
|
|
+ static TCHAR szModulePath[MAX_PATH] = {0};
|
|
|
+ static TCHAR szFna[_MAX_DIR] = { 0 };
|
|
|
+ if ( szModulePath[0] == _T('\0') )
|
|
|
+ {
|
|
|
+ TCHAR szDrive[_MAX_DRIVE] = { 0 };
|
|
|
+ TCHAR szDir[_MAX_DIR] = { 0 };
|
|
|
+ TCHAR szExt[_MAX_DIR] = { 0 };
|
|
|
+ ::GetModuleFileName(NULL, szModulePath, sizeof(szModulePath) / sizeof(TCHAR));
|
|
|
+ _tsplitpath_s(szModulePath, szDrive, szDir, szFna, szExt);
|
|
|
+ _tcscpy_s(szModulePath, szDrive);
|
|
|
+ _tcscat_s(szModulePath, szDir);
|
|
|
+ }
|
|
|
+
|
|
|
+ _stprintf_s(szlogpath, _T("%s日志\\%s%s.txt"), szModulePath, szFna, CTime::GetCurrentTime().Format("[%Y-%m-%d]"));
|
|
|
+
|
|
|
+
|
|
|
+ CStdioFile fp;
|
|
|
+ if (PathFileExists(szlogpath))
|
|
|
+ {
|
|
|
+ if (fp.Open(szlogpath, CFile::modeWrite) == FALSE)
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ fp.SeekToEnd();
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ fp.Open(szlogpath, CFile::modeCreate | CFile::modeWrite);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ TCHAR* old_locale = _tcsdup(_tsetlocale(LC_CTYPE, NULL));
|
|
|
+ _tsetlocale(LC_CTYPE, _T("chs"));
|
|
|
+
|
|
|
+
|
|
|
+ va_list args = NULL;
|
|
|
+ int len = 0;
|
|
|
+ TCHAR *buffer = NULL;
|
|
|
+ va_start( args, format );
|
|
|
+
|
|
|
+ len = _vsctprintf( format, args ) + 1;
|
|
|
+ buffer = (TCHAR*)malloc( len * sizeof(TCHAR) );
|
|
|
+ _vstprintf_s( buffer, len, format, args );
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ fp.WriteString( CTime::GetCurrentTime().Format(_T("%Y-%m-%d %H:%M:%S ")) );
|
|
|
+ fp.WriteString(buffer);
|
|
|
+ fp.WriteString(_T("\n"));
|
|
|
+
|
|
|
+
|
|
|
+ free( buffer );
|
|
|
+ _tsetlocale(LC_CTYPE, old_locale);
|
|
|
+ free(old_locale);
|
|
|
+ fp.Close();
|
|
|
+ }
|
|
|
+ catch (CException *e)
|
|
|
+ {
|
|
|
+ e->ReportError();
|
|
|
+ e->Delete();
|
|
|
+ }
|
|
|
+#else
|
|
|
+
|
|
|
+ TCHAR szlogpath[MAX_PATH] = { 0 };
|
|
|
+ static TCHAR szModulePath[MAX_PATH] = { 0 };
|
|
|
+ static TCHAR szFna[MAX_PATH] = { 0 };
|
|
|
+ if (szModulePath[0] == _T('\0'))
|
|
|
+ {
|
|
|
+ TCHAR szDrive[MAX_PATH] = { 0 };
|
|
|
+ TCHAR szDir[MAX_PATH] = { 0 };
|
|
|
+ TCHAR szExt[MAX_PATH] = { 0 };
|
|
|
+ ::GetModuleFileName(NULL, szModulePath, sizeof(szModulePath) / sizeof(TCHAR));
|
|
|
+ _tsplitpath_s(szModulePath, szDrive, szDir, szFna, szExt);
|
|
|
+ _tcscpy_s(szModulePath, szDrive);
|
|
|
+ _tcscat_s(szModulePath, szDir);
|
|
|
+ }
|
|
|
+
|
|
|
+ _stprintf_s(szlogpath, _T("%s%s.txt"), szModulePath, szFna);
|
|
|
+
|
|
|
+ FILE *fp = NULL;
|
|
|
+
|
|
|
+#ifndef UNICODE
|
|
|
+ if (_access(szlogpath, 0) != -1)
|
|
|
+#else
|
|
|
+ if (_taccess(szlogpath, 0) != -1)
|
|
|
+#endif
|
|
|
+ {
|
|
|
+ fp = _tfopen(szlogpath, _T("a+"));
|
|
|
+
|
|
|
+ fseek(fp, 0, SEEK_END);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ fp = _tfopen(szlogpath, _T("w+"));
|
|
|
+ }
|
|
|
+
|
|
|
+ if (fp == NULL)
|
|
|
+ return;
|
|
|
+
|
|
|
+
|
|
|
+ TCHAR* old_locale = _tcsdup(_tsetlocale(LC_CTYPE, NULL));
|
|
|
+ _tsetlocale(LC_CTYPE, _T("chs"));
|
|
|
+
|
|
|
+
|
|
|
+ va_list args = NULL;
|
|
|
+ int len = 0;
|
|
|
+ TCHAR *buffer = NULL;
|
|
|
+ va_start(args, format);
|
|
|
+
|
|
|
+ len = _vsctprintf(format, args) + 1;
|
|
|
+ buffer = (TCHAR*)malloc(len * sizeof(TCHAR));
|
|
|
+ _vstprintf_s(buffer, len, format, args);
|
|
|
+
|
|
|
+
|
|
|
+ __time64_t gmt = time(NULL);
|
|
|
+ struct tm gmtm = { 0 };
|
|
|
+ localtime_s(&gmtm, &gmt);
|
|
|
+ _ftprintf(fp, _T("%04d-%02d-%02d %02d:%02d:%02d %s\n"), gmtm.tm_year + 1990, gmtm.tm_mon + 1, gmtm.tm_mday, gmtm.tm_hour, gmtm.tm_min, gmtm.tm_sec, buffer);
|
|
|
+
|
|
|
+
|
|
|
+ free(buffer);
|
|
|
+ fclose(fp);
|
|
|
+ _tsetlocale(LC_CTYPE, old_locale);
|
|
|
+ free(old_locale);
|
|
|
+#endif
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+BOOL IsDirectoryLegitimate(const CString &strDirectory)
|
|
|
+{
|
|
|
+ if (strDirectory.Find('/') != -1 ||
|
|
|
+ strDirectory.Find('\\') != -1 ||
|
|
|
+ strDirectory.Find(':') != -1 ||
|
|
|
+ strDirectory.Find('*') != -1 ||
|
|
|
+ strDirectory.Find('?') != -1 ||
|
|
|
+ strDirectory.Find('\"') != -1 ||
|
|
|
+ strDirectory.Find('>') != -1 ||
|
|
|
+ strDirectory.Find('<') != -1 ||
|
|
|
+ strDirectory.Find('|') != -1
|
|
|
+ )
|
|
|
+ return FALSE;
|
|
|
+
|
|
|
+ return TRUE;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+void ShowSystemErrorInfo(CString strDescription, const DWORD &dwError)
|
|
|
+{
|
|
|
+#if 1
|
|
|
+ LPVOID lpMsgBuf;
|
|
|
+
|
|
|
+ BOOL fOk = FormatMessage(
|
|
|
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
|
+ FORMAT_MESSAGE_FROM_SYSTEM |
|
|
|
+ FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
|
+ NULL,
|
|
|
+ dwError,
|
|
|
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
|
+ (LPTSTR)&lpMsgBuf,
|
|
|
+ 0, NULL);
|
|
|
+
|
|
|
+ if (!fOk)
|
|
|
+ {
|
|
|
+
|
|
|
+ HMODULE hDll = LoadLibraryEx(TEXT("netmsg.dll"), NULL, DONT_RESOLVE_DLL_REFERENCES);
|
|
|
+
|
|
|
+ if (hDll != NULL)
|
|
|
+ {
|
|
|
+ FormatMessage(
|
|
|
+ FORMAT_MESSAGE_FROM_HMODULE |
|
|
|
+ FORMAT_MESSAGE_FROM_SYSTEM |
|
|
|
+ FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
|
+ hDll,
|
|
|
+ dwError,
|
|
|
+ MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
|
|
|
+ (LPTSTR)&lpMsgBuf,
|
|
|
+ 0,
|
|
|
+ NULL);
|
|
|
+
|
|
|
+ FreeLibrary(hDll);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (lpMsgBuf != NULL)
|
|
|
+ {
|
|
|
+ CString strDisplay;
|
|
|
+ strDisplay.Format(_T("%s.错误码=%d,Windows描述:%s"), strDescription, dwError, (PCTSTR)LocalLock(lpMsgBuf));
|
|
|
+
|
|
|
+ LocalFree(lpMsgBuf);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+
|
|
|
+ }
|
|
|
+#else
|
|
|
+ HLOCAL hlocal = NULL;
|
|
|
+
|
|
|
+
|
|
|
+ BOOL fOk = FormatMessage(
|
|
|
+ FORMAT_MESSAGE_FROM_SYSTEM |
|
|
|
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
|
+ FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
|
+ NULL,
|
|
|
+ dwError,
|
|
|
+ MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
|
|
|
+ (PTSTR)&hlocal,
|
|
|
+ 0,
|
|
|
+ NULL);
|
|
|
+
|
|
|
+ if (!fOk)
|
|
|
+ {
|
|
|
+
|
|
|
+ HMODULE hDll = LoadLibraryEx(TEXT("netmsg.dll"), NULL, DONT_RESOLVE_DLL_REFERENCES);
|
|
|
+
|
|
|
+ if (hDll != NULL)
|
|
|
+ {
|
|
|
+ FormatMessage(
|
|
|
+ FORMAT_MESSAGE_FROM_HMODULE |
|
|
|
+ FORMAT_MESSAGE_FROM_SYSTEM |
|
|
|
+ FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
|
+ hDll,
|
|
|
+ dwError,
|
|
|
+ MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
|
|
|
+ (PTSTR)&hlocal,
|
|
|
+ 0,
|
|
|
+ NULL);
|
|
|
+ FreeLibrary(hDll);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (hlocal != NULL)
|
|
|
+ {
|
|
|
+ CString strDisplay;
|
|
|
+ strDisplay.Format("%s 失败错误码=%d,Windows系统描述:%s", strDescription, dwError, (PCTSTR)LocalLock(hlocal));
|
|
|
+
|
|
|
+ LocalFree(hlocal);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+
|
|
|
+ }
|
|
|
+#endif
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+BOOL MySystemShutdown(LPTSTR lpMsg)
|
|
|
+{
|
|
|
+ HANDLE hToken;
|
|
|
+ TOKEN_PRIVILEGES tkp;
|
|
|
+
|
|
|
+ BOOL fResult;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ if (!OpenProcessToken(GetCurrentProcess(),
|
|
|
+ TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
|
|
|
+ return FALSE;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,
|
|
|
+ &tkp.Privileges[0].Luid);
|
|
|
+
|
|
|
+ tkp.PrivilegeCount = 1;
|
|
|
+ tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
|
|
|
+ (PTOKEN_PRIVILEGES)NULL, 0);
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ if (GetLastError() != ERROR_SUCCESS)
|
|
|
+ return FALSE;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ fResult = InitiateSystemShutdown(
|
|
|
+ NULL,
|
|
|
+ lpMsg,
|
|
|
+ 30,
|
|
|
+ FALSE,
|
|
|
+ TRUE);
|
|
|
+
|
|
|
+ if (!fResult)
|
|
|
+ return FALSE;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ tkp.Privileges[0].Attributes = 0;
|
|
|
+ AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
|
|
|
+ (PTOKEN_PRIVILEGES)NULL, 0);
|
|
|
+
|
|
|
+ return TRUE;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+BOOL PreventSystemShutdown()
|
|
|
+{
|
|
|
+ HANDLE hToken;
|
|
|
+ TOKEN_PRIVILEGES tkp;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ if (!OpenProcessToken(GetCurrentProcess(),
|
|
|
+ TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
|
|
|
+ return FALSE;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,
|
|
|
+ &tkp.Privileges[0].Luid);
|
|
|
+
|
|
|
+ tkp.PrivilegeCount = 1;
|
|
|
+ tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
|
|
|
+ (PTOKEN_PRIVILEGES)NULL, 0);
|
|
|
+
|
|
|
+ if (GetLastError() != ERROR_SUCCESS)
|
|
|
+ return FALSE;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ if (!AbortSystemShutdown(NULL))
|
|
|
+ return FALSE;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ tkp.Privileges[0].Attributes = 0;
|
|
|
+ AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
|
|
|
+ (PTOKEN_PRIVILEGES)NULL, 0);
|
|
|
+
|
|
|
+ return TRUE;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+BOOL MySystemShutdown()
|
|
|
+{
|
|
|
+ HANDLE hToken;
|
|
|
+ TOKEN_PRIVILEGES tkp;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ if (!OpenProcessToken(GetCurrentProcess(),
|
|
|
+ TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
|
|
|
+ return(FALSE);
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,
|
|
|
+ &tkp.Privileges[0].Luid);
|
|
|
+
|
|
|
+ tkp.PrivilegeCount = 1;
|
|
|
+ tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
|
|
|
+ (PTOKEN_PRIVILEGES)NULL, 0);
|
|
|
+
|
|
|
+ if (GetLastError() != ERROR_SUCCESS)
|
|
|
+ return FALSE;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ if (!ExitWindowsEx(EWX_SHUTDOWN | EWX_FORCE,
|
|
|
+ SHTDN_REASON_MAJOR_OPERATINGSYSTEM |
|
|
|
+ SHTDN_REASON_MINOR_UPGRADE |
|
|
|
+ SHTDN_REASON_FLAG_PLANNED))
|
|
|
+ return FALSE;
|
|
|
+
|
|
|
+ return TRUE;
|
|
|
+}
|
|
|
+
|
|
|
+BOOL GetWeChatPath()
|
|
|
+{
|
|
|
+
|
|
|
+ HKEY hKey = NULL;
|
|
|
+ if(ERROR_SUCCESS != RegOpenKey(HKEY_CURRENT_USER, _T("Software\\Tencent\\WeChat"), &hKey))
|
|
|
+ {
|
|
|
+ return FALSE;
|
|
|
+ }
|
|
|
+
|
|
|
+ DWORD Type = REG_SZ;
|
|
|
+ DWORD cbData = MAX_PATH*sizeof(WCHAR);
|
|
|
+ if(ERROR_SUCCESS != RegQueryValueEx(hKey, _T("InstallPath"), 0, &Type, (LPBYTE)g_szWeChatPath, &cbData))
|
|
|
+ {
|
|
|
+ RegCloseKey(hKey);
|
|
|
+ return FALSE;
|
|
|
+ }
|
|
|
+
|
|
|
+ PathAppend(g_szWeChatPath, _T("WeChat.exe"));
|
|
|
+
|
|
|
+ return TRUE;
|
|
|
+}
|
|
|
+
|
|
|
+BOOL OpenWeChat()
|
|
|
+{
|
|
|
+ STARTUPINFO si;
|
|
|
+ PROCESS_INFORMATION pi;
|
|
|
+ ZeroMemory(&si, sizeof(si));
|
|
|
+ si.cb = sizeof(si);
|
|
|
+ ZeroMemory(&pi, sizeof(pi));
|
|
|
+
|
|
|
+ si.dwFlags = STARTF_USESHOWWINDOW;
|
|
|
+ si.wShowWindow = SW_HIDE;
|
|
|
+
|
|
|
+ BOOL bRet = ::CreateProcess (
|
|
|
+ g_szWeChatPath,
|
|
|
+ NULL,
|
|
|
+ NULL,
|
|
|
+ NULL,
|
|
|
+ FALSE,
|
|
|
+ NULL,
|
|
|
+ NULL,
|
|
|
+ NULL,
|
|
|
+ &si,
|
|
|
+ &pi);
|
|
|
+
|
|
|
+ if(bRet)
|
|
|
+ {
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ ::CloseHandle (pi.hThread);
|
|
|
+ ::CloseHandle (pi.hProcess);
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ return TRUE;
|
|
|
+}
|
|
|
+
|
|
|
+BOOL OpenWeChat2()
|
|
|
+{
|
|
|
+ SHELLEXECUTEINFO sei;
|
|
|
+ memset(&sei, 0, sizeof(SHELLEXECUTEINFO));
|
|
|
+ sei.cbSize = sizeof(SHELLEXECUTEINFO);
|
|
|
+ sei.hwnd = NULL;
|
|
|
+ sei.lpVerb = _T("open");
|
|
|
+
|
|
|
+
|
|
|
+ sei.lpFile = g_szWeChatPath;
|
|
|
+ sei.lpParameters = NULL;
|
|
|
+ sei.lpDirectory = NULL;
|
|
|
+ sei.nShow = SW_NORMAL;
|
|
|
+ sei.hInstApp = NULL;
|
|
|
+
|
|
|
+ if (!ShellExecuteEx(&sei))
|
|
|
+ {
|
|
|
+ DWORD dw = GetLastError();
|
|
|
+ return FALSE;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ return TRUE;
|
|
|
+}
|
|
|
+
|
|
|
+BOOL OpenWeChatAndSuspended()
|
|
|
+{
|
|
|
+ STARTUPINFO si;
|
|
|
+ PROCESS_INFORMATION pi;
|
|
|
+ ZeroMemory(&si, sizeof(si));
|
|
|
+ si.cb = sizeof(si);
|
|
|
+ ZeroMemory(&pi, sizeof(pi));
|
|
|
+
|
|
|
+ si.dwFlags = STARTF_USESHOWWINDOW;
|
|
|
+ si.wShowWindow = TRUE;
|
|
|
+
|
|
|
+ BOOL bRet = ::CreateProcess(
|
|
|
+ g_szWeChatPath,
|
|
|
+ NULL,
|
|
|
+ NULL,
|
|
|
+ NULL,
|
|
|
+ FALSE,
|
|
|
+ CREATE_SUSPENDED,
|
|
|
+ NULL,
|
|
|
+ NULL,
|
|
|
+ &si,
|
|
|
+ &pi);
|
|
|
+
|
|
|
+ if (bRet)
|
|
|
+ {
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ CONTEXT ct = { 0 };
|
|
|
+ ct.ContextFlags = CONTEXT_CONTROL;
|
|
|
+ GetThreadContext(pi.hThread, &ct);
|
|
|
+
|
|
|
+ ::ResumeThread(pi.hThread);
|
|
|
+
|
|
|
+
|
|
|
+ ::CloseHandle(pi.hThread);
|
|
|
+ ::CloseHandle(pi.hProcess);
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ return TRUE;
|
|
|
+}
|