//MailSlot of flush DNS cache sender bool WINAPI FlushDNSMailSlotSender( void) { //Create mailslot. HANDLE hFile = CreateFileW(MAILSLOT_NAME, GENERIC_WRITE, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); if (hFile == INVALID_HANDLE_VALUE) { std::unique_lock<std::mutex> ScreenMutex(ScreenLock); fwprintf_s(stderr, L"Create mailslot error, error code is %lu.\n", GetLastError()); return false; } //Write into mailslot. DWORD cbWritten = 0; if (!WriteFile(hFile, MAILSLOT_MESSAGE_FLUSH_DNS, (DWORD)(lstrlenW(MAILSLOT_MESSAGE_FLUSH_DNS) + 1U) * sizeof(wchar_t), &cbWritten, nullptr)) { std::unique_lock<std::mutex> ScreenMutex(ScreenLock); fwprintf_s(stderr, L"MailSlot write messages error, error code is %lu.\n", GetLastError()); CloseHandle(hFile); return false; } CloseHandle(hFile); std::unique_lock<std::mutex> ScreenMutex(ScreenLock); fwprintf_s(stderr, L"Flush DNS cache message was sent successfully.\n"); return true; }
//Flush DNS cache void __fastcall FlushAllDNSCache( void) { //Flush DNS cache in program. std::unique_lock<std::mutex> DNSCacheListMutex(DNSCacheListLock); DNSCacheList.clear(); DNSCacheList.shrink_to_fit(); DNSCacheListMutex.unlock(); //Flush DNS cache in system. std::unique_lock<std::mutex> ScreenMutex(ScreenLock); #if defined(PLATFORM_WIN) system("ipconfig /flushdns 2>nul"); //All Windows version fwprintf_s(stderr, L"\n"); #elif defined(PLATFORM_LINUX) #if defined(PLATFORM_OPENWRT) system("/etc/init.d/dnsmasq restart 2>/dev/null"); //Dnsmasq manage DNS cache on OpenWrt #else auto Result = system("service nscd restart 2>/dev/null"); //Name Service Cache Daemon service Result = system("service dnsmasq restart 2>/dev/null"); //Dnsmasq service Result = system("rndc restart 2>/dev/null"); //Name server control utility of BIND(9.1.3 and older version) Result = system("rndc flush 2>/dev/null"); //Name server control utility of BIND(9.2.0 and newer version) #endif #elif defined(PLATFORM_MACX) // system("lookupd -flushcache 2>/dev/null"); //Less than Mac OS X Tiger(10.4) // system("dscacheutil -flushcache 2>/dev/null"); //Mac OS X Leopard(10.5) and Snow Leopard(10.6) system("killall -HUP mDNSResponder 2>/dev/null"); //Mac OS X Lion(10.7), Mountain Lion(10.8) and Mavericks(10.9) system("discoveryutil mdnsflushcache 2>/dev/null"); //Mac OS X Yosemite(10.10) and newer version #endif return; }
//Catch Control-C exception from keyboard. BOOL WINAPI CtrlHandler( const DWORD fdwCtrlType) { //Print to screen. if (GlobalRunningStatus.Console) { std::unique_lock<std::mutex> ScreenMutex(ScreenLock); switch (fdwCtrlType) { case CTRL_C_EVENT: //Handle the CTRL-C signal. { fwprintf_s(stderr, L"Get Control-C.\n"); }break; case CTRL_BREAK_EVENT: //Handle the CTRL-Break signal. { fwprintf_s(stderr, L"Get Control-Break.\n"); }break; default: //Handle other signals. { fwprintf_s(stderr, L"Get closing signal.\n"); }break; } } return FALSE; }
//Flush DNS cache FIFO sender bool FlushDNSFIFOSender( void) { int FileFIFO = open(FIFO_PATH_NAME, O_WRONLY|O_TRUNC|O_NONBLOCK, 0); if (FileFIFO > 0 && write(FileFIFO, FIFO_MESSAGE_FLUSH_DNS, strlen(FIFO_MESSAGE_FLUSH_DNS) + 1U) > 0) { std::unique_lock<std::mutex> ScreenMutex(ScreenLock); fwprintf(stderr, L"Flush DNS cache message was sent successfully.\n"); close(FileFIFO); } else { std::unique_lock<std::mutex> ScreenMutex(ScreenLock); fwprintf(stderr, L"FIFO write messages error, error code is %d.\n", errno); return false; } return true; }
//Flush DNS cache void FlushDNSCache( const uint8_t *Domain) { //Flush DNS cache in program. std::unique_lock<std::mutex> DNSCacheListMutex(DNSCacheListLock); if (Domain == nullptr) //Flush all DNS cache. { DNSCacheList.clear(); } //Flush single domain cache. else { for (auto DNSCacheDataIter = DNSCacheList.begin();DNSCacheDataIter != DNSCacheList.end();) { if (DNSCacheDataIter->Domain == (const char *)Domain) DNSCacheDataIter = DNSCacheList.erase(DNSCacheDataIter); else ++DNSCacheDataIter; } } DNSCacheListMutex.unlock(); //Flush DNS cache in system. std::lock_guard<std::mutex> ScreenMutex(ScreenLock); #if defined(PLATFORM_WIN) system("ipconfig /flushdns 2>nul"); //All Windows version fwprintf_s(stderr, L"\n"); #elif defined(PLATFORM_LINUX) #if defined(PLATFORM_OPENWRT) system("/etc/init.d/dnsmasq restart 2>/dev/null"); //Dnsmasq manage DNS cache on OpenWrt #else auto Result = system("service nscd restart 2>/dev/null"); //Name Service Cache Daemon service Result = system("service dnsmasq restart 2>/dev/null"); //Dnsmasq service Result = system("rndc restart 2>/dev/null"); //Name server control utility of BIND(9.1.3 and older version) Result = system("rndc flush 2>/dev/null"); //Name server control utility of BIND(9.2.0 and newer version) #endif #elif defined(PLATFORM_MACX) // system("lookupd -flushcache 2>/dev/null"); //Less than Mac OS X Tiger(10.4) // system("dscacheutil -flushcache 2>/dev/null"); //Mac OS X Leopard(10.5) and Snow Leopard(10.6) system("killall -HUP mDNSResponder 2>/dev/null"); //Mac OS X Lion(10.7), Mountain Lion(10.8) and Mavericks(10.9) system("discoveryutil mdnsflushcache 2>/dev/null"); //Mac OS X Yosemite(10.10) and newer version #endif return; }
//Flush DNS cache FIFO sender bool FlushDNSFIFOSender( const uint8_t *Domain) { //Message initialization std::string Message(FIFO_MESSAGE_FLUSH_DNS); if (Domain != nullptr) { Message.append(": "); Message.append((const char *)Domain); } //Write into FIFO file. errno = 0; int FIFO_Handle = open(FIFO_PATH_NAME, O_WRONLY|O_TRUNC|O_NONBLOCK, 0); if (FIFO_Handle > 0) { if (write(FIFO_Handle, Message.c_str(), Message.length() + 1U) > 0) { close(FIFO_Handle); PrintToScreen(true, L"Flush DNS cache message was sent successfully.\n"); return true; } else { close(FIFO_Handle); } } //Print error log. std::lock_guard<std::mutex> ScreenMutex(ScreenLock); PrintToScreen(false, L"FIFO write messages error"); if (errno > 0) PrintToScreen(false, L", error code is %d.\n", errno); else PrintToScreen(false, L".\n"); return false; }
int wmain( int argc, wchar_t* argv[]) { #elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX)) int main( int argc, char *argv[]) { #endif //Get commands. if (argc > 0) { if (!ReadCommand(argc, argv)) return EXIT_SUCCESS; } else { return EXIT_FAILURE; } //Read configuration file. if (!ReadParameter(true)) return EXIT_FAILURE; //DNSCurve initialization #if defined(ENABLE_LIBSODIUM) if (Parameter.DNSCurve) { DNSCurveParameterModificating.SetToMonitorItem(); //Encryption mode initialization if (DNSCurveParameter.IsEncryption) DNSCurveInit(); } #endif //Mark Local DNS address to PTR Records, read Parameter(Monitor mode), IPFilter and Hosts. ParameterModificating.SetToMonitorItem(); std::thread NetworkInformationMonitorThread(std::bind(NetworkInformationMonitor)); NetworkInformationMonitorThread.detach(); std::thread ReadParameterThread(std::bind(ReadParameter, false)); ReadParameterThread.detach(); std::thread ReadHostsThread(std::bind(ReadHosts)); ReadHostsThread.detach(); if (Parameter.OperationMode == LISTEN_MODE_CUSTOM || Parameter.DataCheck_Blacklist || Parameter.LocalRouting) { std::thread ReadIPFilterThread(std::bind(ReadIPFilter)); ReadIPFilterThread.detach(); } #if defined(PLATFORM_WIN) //Service initialization and start service. SERVICE_TABLE_ENTRYW ServiceTable[]{{SYSTEM_SERVICE_NAME, (LPSERVICE_MAIN_FUNCTIONW)ServiceMain}, {nullptr, nullptr}}; if (!StartServiceCtrlDispatcherW(ServiceTable)) { GlobalRunningStatus.Console = true; auto ErrorCode = GetLastError(); //Print to screen. std::unique_lock<std::mutex> ScreenMutex(ScreenLock); fwprintf_s(stderr, L"System Error: Service start error, error code is %lu.\n", ErrorCode); fwprintf_s(stderr, L"System Error: Program will continue to run in console mode.\n"); fwprintf_s(stderr, L"Please ignore these error messages if you want to run in console mode.\n\n"); ScreenMutex.unlock(); //Handle the system signal and start all monitors. SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE); MonitorInit(); } #elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX)) MonitorInit(); #endif return EXIT_SUCCESS; } //Read commands from main program #if defined(PLATFORM_WIN) bool __fastcall ReadCommand( int argc, wchar_t *argv[]) #elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX)) bool ReadCommand( int argc, char *argv[]) #endif { //Path initialization #if defined(PLATFORM_WIN) if (!FileNameInit(argv[0])) return false; #elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX)) char FileName[PATH_MAX + 1U] = {0}; if (getcwd(FileName, PATH_MAX) == nullptr) { std::unique_lock<std::mutex> ScreenMutex(ScreenLock); fwprintf(stderr, L"Path initialization error.\n"); return false; } if (!FileNameInit(FileName)) return false; #endif //Screen output buffer setting if (setvbuf(stderr, NULL, _IONBF, 0) != 0) { auto ErrorCode = errno; std::unique_lock<std::mutex> ScreenMutex(ScreenLock); fwprintf_s(stderr, L"Screen output buffer setting error, error code is %d.\n", ErrorCode); ScreenLock.unlock(); PrintError(LOG_LEVEL_2, LOG_ERROR_NETWORK, L"Screen output buffer setting error", ErrorCode, nullptr, 0); return false; } //Winsock initialization #if defined(PLATFORM_WIN) WSAData WSAInitialization = {0}; if (WSAStartup(MAKEWORD(WINSOCK_VERSION_HIGH, WINSOCK_VERSION_LOW), &WSAInitialization) != 0 || LOBYTE(WSAInitialization.wVersion) != WINSOCK_VERSION_LOW || HIBYTE(WSAInitialization.wVersion) != WINSOCK_VERSION_HIGH) { auto ErrorCode = WSAGetLastError(); std::unique_lock<std::mutex> ScreenMutex(ScreenLock); fwprintf_s(stderr, L"Winsock initialization error, error code is %d.\n", ErrorCode); ScreenLock.unlock(); PrintError(LOG_LEVEL_1, LOG_ERROR_NETWORK, L"Winsock initialization error", ErrorCode, nullptr, 0); return false; } else { GlobalRunningStatus.Initialization_WinSock = true; } //Read commands. std::wstring Commands; #elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX)) std::string Commands; #endif for (size_t Index = 1U;(SSIZE_T)Index < argc;++Index) { Commands = argv[Index]; //Flush DNS Cache from user. if (Commands == COMMAND_FLUSH_DNS) { #if defined(PLATFORM_WIN) FlushDNSMailSlotSender(); #elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX)) FlushDNSFIFOSender(); #endif return false; } //Windows Firewall Test in first start. #if defined(PLATFORM_WIN) else if (Commands == COMMAND_FIREWALL_TEST) { if (!FirewallTest(AF_INET6) && !FirewallTest(AF_INET)) { auto ErrorCode = WSAGetLastError(); std::unique_lock<std::mutex> ScreenMutex(ScreenLock); fwprintf_s(stderr, L"Windows Firewall Test error, error code is %d.\n", ErrorCode); ScreenMutex.unlock(); PrintError(LOG_LEVEL_2, LOG_ERROR_NETWORK, L"Windows Firewall Test error", ErrorCode, nullptr, 0); } return false; } #endif //Set system daemon. #if defined(PLATFORM_LINUX) else if (Commands == COMMAND_DISABLE_DAEMON) { GlobalRunningStatus.Daemon = false; } #endif //Print current version. else if (Commands == COMMAND_LONG_PRINT_VERSION || Commands == COMMAND_SHORT_PRINT_VERSION) { std::unique_lock<std::mutex> ScreenMutex(ScreenLock); fwprintf_s(stderr, L"Pcap_DNSProxy "); fwprintf_s(stderr, FULL_VERSION); fwprintf_s(stderr, L"\n"); return false; } //Print library version. else if (Commands == COMMAND_LIB_VERSION) { std::unique_lock<std::mutex> ScreenMutex(ScreenLock); #if (defined(ENABLE_LIBSODIUM) || defined(ENABLE_PCAP)) std::wstring LibVersion; //LibSodium version #if defined(ENABLE_LIBSODIUM) if (MBSToWCSString(SODIUM_VERSION_STRING, strlen(SODIUM_VERSION_STRING), LibVersion)) fwprintf_s(stderr, L"LibSodium version %ls\n", LibVersion.c_str()); #endif //WinPcap or LibPcap version #if defined(ENABLE_PCAP) if (MBSToWCSString(pcap_lib_version(), strlen(pcap_lib_version()), LibVersion)) fwprintf_s(stderr, L"%ls\n", LibVersion.c_str()); #endif #else fwprintf(stderr, L"No any available libraries.\n"); #endif return false; } //Print help messages. else if (Commands == COMMAND_LONG_HELP || Commands == COMMAND_SHORT_HELP) { std::unique_lock<std::mutex> ScreenMutex(ScreenLock); fwprintf_s(stderr, L"Pcap_DNSProxy "); fwprintf_s(stderr, FULL_VERSION); #if defined(PLATFORM_WIN) fwprintf_s(stderr, L"(Windows)\n"); #elif defined(PLATFORM_OPENWRT) fwprintf(stderr, L"(OpenWrt)\n"); #elif defined(PLATFORM_LINUX) fwprintf(stderr, L"(Linux)\n"); #elif defined(PLATFORM_MACX) fwprintf(stderr, L"(Mac)\n"); #endif fwprintf_s(stderr, COPYRIGHT_MESSAGE); fwprintf_s(stderr, L"\nUsage: Please visit ReadMe... files in Documents folder.\n"); fwprintf_s(stderr, L" -v/--version: Print current version on screen.\n"); fwprintf_s(stderr, L" --lib-version: Print current version of libraries on screen.\n"); fwprintf_s(stderr, L" -h/--help: Print help messages on screen.\n"); fwprintf_s(stderr, L" --flush-dns: Flush all DNS cache in program and system immediately.\n"); #if defined(PLATFORM_WIN) fwprintf_s(stderr, L" --first-setup: Test local firewall.\n"); #endif fwprintf_s(stderr, L" -c/--config-file Path: Set path of configuration file.\n"); #if defined(PLATFORM_LINUX) fwprintf(stderr, L" --disable-daemon: Disable daemon mode.\n"); #endif return false; } //Set working directory from commands. else if (Commands == COMMAND_LONG_SET_PATH || Commands == COMMAND_SHORT_SET_PATH) { //Commands check if ((SSIZE_T)Index + 1 >= argc) { std::unique_lock<std::mutex> ScreenMutex(ScreenLock); fwprintf(stderr, L"Commands error.\n"); ScreenMutex.unlock(); PrintError(LOG_LEVEL_1, LOG_ERROR_SYSTEM, L"Commands error", 0, nullptr, 0); return false; } else { ++Index; Commands = argv[Index]; //Path check. if (Commands.length() > MAX_PATH) { std::unique_lock<std::mutex> ScreenMutex(ScreenLock); fwprintf_s(stderr, L"Commands error.\n"); ScreenLock.unlock(); PrintError(LOG_LEVEL_1, LOG_ERROR_SYSTEM, L"Commands error", 0, nullptr, 0); return false; } else { if (!FileNameInit(Commands.c_str())) return false; } } } } //Set system daemon. #if defined(PLATFORM_LINUX) if (GlobalRunningStatus.Daemon && daemon(0, 0) == RETURN_ERROR) { PrintError(LOG_LEVEL_2, LOG_ERROR_SYSTEM, L"Set system daemon error", 0, nullptr, 0); return false; } #endif return true; } //Get path of program from the main function parameter and Winsock initialization #if defined(PLATFORM_WIN) bool __fastcall FileNameInit( const wchar_t *OriginalPath) #elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX)) bool FileNameInit( const char *OriginalPath) #endif { //Path process #if defined(PLATFORM_WIN) GlobalRunningStatus.Path_Global->clear(); GlobalRunningStatus.Path_Global->push_back(OriginalPath); GlobalRunningStatus.Path_Global->front().erase(GlobalRunningStatus.Path_Global->front().rfind(L"\\") + 1U); for (size_t Index = 0;Index < GlobalRunningStatus.Path_Global->front().length();++Index) { if ((GlobalRunningStatus.Path_Global->front()).at(Index) == L'\\') { GlobalRunningStatus.Path_Global->front().insert(Index, L"\\"); ++Index; } } #elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX)) GlobalRunningStatus.sPath_Global->clear(); GlobalRunningStatus.sPath_Global->push_back(OriginalPath); GlobalRunningStatus.sPath_Global->front().append("/"); std::wstring StringTemp; if (!MBSToWCSString(OriginalPath, PATH_MAX + 1U, StringTemp)) return false; StringTemp.append(L"/"); GlobalRunningStatus.Path_Global->clear(); GlobalRunningStatus.Path_Global->push_back(StringTemp); StringTemp.clear(); #endif //Get path of error/running status log file and mark start time. GlobalRunningStatus.Path_ErrorLog->clear(); *GlobalRunningStatus.Path_ErrorLog = GlobalRunningStatus.Path_Global->front(); GlobalRunningStatus.Path_ErrorLog->append(L"Error.log"); #if (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX)) GlobalRunningStatus.sPath_ErrorLog->clear(); *GlobalRunningStatus.sPath_ErrorLog = GlobalRunningStatus.sPath_Global->front(); GlobalRunningStatus.sPath_ErrorLog->append("Error.log"); #endif Parameter.PrintLogLevel = DEFAULT_LOG_LEVEL; GlobalRunningStatus.StartupTime = time(nullptr); return true; }
//Print to screen and write to file bool __fastcall PrintScreenAndWriteFile( _In_ const std::wstring Message, _In_opt_ const SSIZE_T ErrorCode, _In_opt_ const size_t Line) { //Get current date and time. auto TimeStructure = std::make_shared<tm>(); memset(TimeStructure.get(), 0, sizeof(tm)); auto TimeValues = time(nullptr); #if defined(PLATFORM_WIN) if (localtime_s(TimeStructure.get(), &TimeValues) > 0) #elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX)) if (localtime_r(&TimeValues, TimeStructure.get()) == nullptr) #endif return false; //Print startup time at first printing. time_t LogStartupTime = 0; if (GlobalRunningStatus.StartupTime > 0) { LogStartupTime = GlobalRunningStatus.StartupTime; GlobalRunningStatus.StartupTime = 0; } //Print to screen. #if defined(PLATFORM_WIN) if (GlobalRunningStatus.Console) #elif defined(PLATFORM_LINUX) if (!GlobalRunningStatus.Daemon) #endif { std::unique_lock<std::mutex> ScreenMutex(ScreenLock); //Print startup time. if (LogStartupTime > 0) { fwprintf_s(stderr, L"%d-%02d-%02d %02d:%02d:%02d -> Log opened at this moment.\n", TimeStructure->tm_year + 1900, TimeStructure->tm_mon + 1, TimeStructure->tm_mday, TimeStructure->tm_hour, TimeStructure->tm_min, TimeStructure->tm_sec); } //Print message. fwprintf_s(stderr, L"%d-%02d-%02d %02d:%02d:%02d -> ", TimeStructure->tm_year + 1900, TimeStructure->tm_mon + 1, TimeStructure->tm_mday, TimeStructure->tm_hour, TimeStructure->tm_min, TimeStructure->tm_sec); if (Line > 0 && ErrorCode > 0) fwprintf_s(stderr, Message.c_str(), Line, ErrorCode); else if (Line > 0) fwprintf_s(stderr, Message.c_str(), Line); else if (ErrorCode > 0) fwprintf_s(stderr, Message.c_str(), ErrorCode); else fwprintf_s(stderr, Message.c_str()); } //Check whole file size. std::unique_lock<std::mutex> ErrorLogMutex(ErrorLogLock); #if defined(PLATFORM_WIN) auto File_WIN32_FILE_ATTRIBUTE_DATA = std::make_shared<WIN32_FILE_ATTRIBUTE_DATA>(); memset(File_WIN32_FILE_ATTRIBUTE_DATA.get(), 0, sizeof(WIN32_FILE_ATTRIBUTE_DATA)); if (GetFileAttributesExW(GlobalRunningStatus.Path_ErrorLog->c_str(), GetFileExInfoStandard, File_WIN32_FILE_ATTRIBUTE_DATA.get()) != FALSE) { auto ErrorFileSize = std::make_shared<LARGE_INTEGER>(); memset(ErrorFileSize.get(), 0, sizeof(LARGE_INTEGER)); ErrorFileSize->HighPart = File_WIN32_FILE_ATTRIBUTE_DATA->nFileSizeHigh; ErrorFileSize->LowPart = File_WIN32_FILE_ATTRIBUTE_DATA->nFileSizeLow; if (ErrorFileSize->QuadPart > 0 && (size_t)ErrorFileSize->QuadPart >= Parameter.LogMaxSize) { if (DeleteFileW(GlobalRunningStatus.Path_ErrorLog->c_str()) != FALSE) { ErrorLogMutex.unlock(); PrintError(LOG_ERROR_SYSTEM, L"Old error log file was deleted", 0, nullptr, 0); ErrorLogMutex.lock(); } else { return false; } } } File_WIN32_FILE_ATTRIBUTE_DATA.reset(); #elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX)) auto FileStat = std::make_shared<struct stat>(); memset(FileStat.get(), 0, sizeof(struct stat)); if (stat(GlobalRunningStatus.sPath_ErrorLog->c_str(), FileStat.get()) == 0 && FileStat->st_size >= (off_t)Parameter.LogMaxSize) { if (remove(GlobalRunningStatus.sPath_ErrorLog->c_str()) == 0) { ErrorLogMutex.unlock(); PrintError(LOG_ERROR_SYSTEM, L"Old error log file was deleted", 0, nullptr, 0); ErrorLogMutex.lock(); } else { return false; } } FileStat.reset(); #endif //Write to file. #if defined(PLATFORM_WIN) FILE *Output = nullptr; if (_wfopen_s(&Output, GlobalRunningStatus.Path_ErrorLog->c_str(), L"a,ccs=UTF-8") == 0 && Output != nullptr) #elif (defined(PLATFORM_LINUX) || defined(PLATFORM_MACX)) auto Output = fopen(GlobalRunningStatus.sPath_ErrorLog->c_str(), "a"); if (Output != nullptr) #endif { //Print startup time. if (LogStartupTime > 0) { fwprintf_s(Output, L"%d-%02d-%02d %02d:%02d:%02d -> Log opened at this moment.\n", TimeStructure->tm_year + 1900, TimeStructure->tm_mon + 1, TimeStructure->tm_mday, TimeStructure->tm_hour, TimeStructure->tm_min, TimeStructure->tm_sec); } //Print message. fwprintf_s(Output, L"%d-%02d-%02d %02d:%02d:%02d -> ", TimeStructure->tm_year + 1900, TimeStructure->tm_mon + 1, TimeStructure->tm_mday, TimeStructure->tm_hour, TimeStructure->tm_min, TimeStructure->tm_sec); if (Line > 0 && ErrorCode > 0) fwprintf_s(Output, Message.c_str(), Line, ErrorCode); else if (Line > 0) fwprintf_s(Output, Message.c_str(), Line); else if (ErrorCode > 0) fwprintf_s(Output, Message.c_str(), ErrorCode); else fwprintf_s(Output, Message.c_str()); fclose(Output); } else { return false; } return true; }