Index: sandbox/win/sandbox_poc/main_ui_window.cc |
diff --git a/sandbox/win/sandbox_poc/main_ui_window.cc b/sandbox/win/sandbox_poc/main_ui_window.cc |
deleted file mode 100644 |
index c000ce13d006882ad38f84763d1cfd7a36a63d36..0000000000000000000000000000000000000000 |
--- a/sandbox/win/sandbox_poc/main_ui_window.cc |
+++ /dev/null |
@@ -1,663 +0,0 @@ |
-// Copyright (c) 2014 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "sandbox/win/sandbox_poc/main_ui_window.h" |
- |
-#include <windows.h> |
-#include <CommCtrl.h> |
-#include <commdlg.h> |
-#include <stdarg.h> |
-#include <stddef.h> |
-#include <time.h> |
-#include <windowsx.h> |
-#include <atlbase.h> |
-#include <atlsecurity.h> |
-#include <algorithm> |
-#include <sstream> |
- |
-#include "base/logging.h" |
-#include "sandbox/win/sandbox_poc/resource.h" |
-#include "sandbox/win/src/acl.h" |
-#include "sandbox/win/src/sandbox.h" |
-#include "sandbox/win/src/win_utils.h" |
- |
-HWND MainUIWindow::list_view_ = NULL; |
- |
-const wchar_t MainUIWindow::kDefaultDll_[] = L"\\POCDLL.dll"; |
-const wchar_t MainUIWindow::kDefaultEntryPoint_[] = L"Run"; |
-const wchar_t MainUIWindow::kDefaultLogFile_[] = L""; |
- |
-MainUIWindow::MainUIWindow() |
- : broker_(NULL), |
- spawn_target_(L""), |
- instance_handle_(NULL), |
- dll_path_(L""), |
- entry_point_(L"") { |
-} |
- |
-MainUIWindow::~MainUIWindow() { |
-} |
- |
-unsigned int MainUIWindow::CreateMainWindowAndLoop( |
- HINSTANCE instance, |
- wchar_t* command_line, |
- int show_command, |
- sandbox::BrokerServices* broker) { |
- DCHECK(instance); |
- DCHECK(command_line); |
- DCHECK(broker); |
- |
- instance_handle_ = instance; |
- spawn_target_ = command_line; |
- broker_ = broker; |
- |
- // We'll use spawn_target_ later for creating a child process, but |
- // CreateProcess doesn't like double quotes, so we remove them along with |
- // tabs and spaces from the start and end of the string |
- const wchar_t *trim_removal = L" \r\t\""; |
- spawn_target_.erase(0, spawn_target_.find_first_not_of(trim_removal)); |
- spawn_target_.erase(spawn_target_.find_last_not_of(trim_removal) + 1); |
- |
- WNDCLASSEX window_class = {0}; |
- window_class.cbSize = sizeof(WNDCLASSEX); |
- window_class.style = CS_HREDRAW | CS_VREDRAW; |
- window_class.lpfnWndProc = MainUIWindow::WndProc; |
- window_class.cbClsExtra = 0; |
- window_class.cbWndExtra = 0; |
- window_class.hInstance = instance; |
- window_class.hIcon = |
- ::LoadIcon(instance, MAKEINTRESOURCE(IDI_SANDBOX)); |
- window_class.hCursor = ::LoadCursor(NULL, IDC_ARROW); |
- window_class.hbrBackground = GetStockBrush(WHITE_BRUSH); |
- window_class.lpszMenuName = MAKEINTRESOURCE(IDR_MENU_MAIN_UI); |
- window_class.lpszClassName = L"sandbox_ui_1"; |
- window_class.hIconSm = NULL; |
- |
- INITCOMMONCONTROLSEX controls = { |
- sizeof(INITCOMMONCONTROLSEX), |
- ICC_STANDARD_CLASSES | ICC_LISTVIEW_CLASSES |
- }; |
- ::InitCommonControlsEx(&controls); |
- |
- if (!::RegisterClassEx(&window_class)) |
- return ::GetLastError(); |
- |
- // Create a main window of size 600x400 |
- HWND window = ::CreateWindowW(window_class.lpszClassName, |
- L"", // window name |
- WS_OVERLAPPEDWINDOW, |
- CW_USEDEFAULT, // x |
- CW_USEDEFAULT, // y |
- 600, // width |
- 400, // height |
- NULL, // parent |
- NULL, // NULL = use class menu |
- instance, |
- 0); // lpParam |
- |
- if (NULL == window) |
- return ::GetLastError(); |
- |
- ::SetWindowLongPtr(window, |
- GWLP_USERDATA, |
- reinterpret_cast<LONG_PTR>(this)); |
- |
- ::SetWindowText(window, L"Sandbox Proof of Concept"); |
- |
- ::ShowWindow(window, show_command); |
- |
- MSG message; |
- // Now lets start the message pump retrieving messages for any window that |
- // belongs to the current thread |
- while (::GetMessage(&message, NULL, 0, 0)) { |
- ::TranslateMessage(&message); |
- ::DispatchMessage(&message); |
- } |
- |
- return 0; |
-} |
- |
-LRESULT CALLBACK MainUIWindow::WndProc(HWND window, |
- UINT message_id, |
- WPARAM wparam, |
- LPARAM lparam) { |
- MainUIWindow* host = FromWindow(window); |
- |
- #define HANDLE_MSG(hwnd, message, fn) \ |
- case (message): return HANDLE_##message((hwnd), (wParam), (lParam), (fn)) |
- |
- switch (message_id) { |
- case WM_CREATE: |
- // 'host' is not yet available when we get the WM_CREATE message |
- return HANDLE_WM_CREATE(window, wparam, lparam, OnCreate); |
- case WM_DESTROY: |
- return HANDLE_WM_DESTROY(window, wparam, lparam, host->OnDestroy); |
- case WM_SIZE: |
- return HANDLE_WM_SIZE(window, wparam, lparam, host->OnSize); |
- case WM_COMMAND: { |
- // Look at which menu item was clicked on (or which accelerator) |
- int id = LOWORD(wparam); |
- switch (id) { |
- case ID_FILE_EXIT: |
- host->OnFileExit(); |
- break; |
- case ID_COMMANDS_SPAWNTARGET: |
- host->OnCommandsLaunch(window); |
- break; |
- default: |
- // Some other menu item or accelerator |
- break; |
- } |
- |
- return ERROR_SUCCESS; |
- } |
- |
- default: |
- // Some other WM_message, let it pass to DefWndProc |
- break; |
- } |
- |
- return DefWindowProc(window, message_id, wparam, lparam); |
-} |
- |
-INT_PTR CALLBACK MainUIWindow::SpawnTargetWndProc(HWND dialog, |
- UINT message_id, |
- WPARAM wparam, |
- LPARAM lparam) { |
- // Grab a reference to the main UI window (from the window handle) |
- MainUIWindow* host = FromWindow(GetParent(dialog)); |
- DCHECK(host); |
- |
- switch (message_id) { |
- case WM_INITDIALOG: { |
- // Initialize the window text for DLL name edit box |
- HWND edit_box_dll_name = ::GetDlgItem(dialog, IDC_DLL_NAME); |
- wchar_t current_dir[MAX_PATH]; |
- if (GetCurrentDirectory(MAX_PATH, current_dir)) { |
- base::string16 dll_path = base::string16(current_dir) + |
- base::string16(kDefaultDll_); |
- ::SetWindowText(edit_box_dll_name, dll_path.c_str()); |
- } |
- |
- // Initialize the window text for Entry Point edit box |
- HWND edit_box_entry_point = ::GetDlgItem(dialog, IDC_ENTRY_POINT); |
- ::SetWindowText(edit_box_entry_point, kDefaultEntryPoint_); |
- |
- // Initialize the window text for Log File edit box |
- HWND edit_box_log_file = ::GetDlgItem(dialog, IDC_LOG_FILE); |
- ::SetWindowText(edit_box_log_file, kDefaultLogFile_); |
- |
- return static_cast<INT_PTR>(TRUE); |
- } |
- case WM_COMMAND: |
- // If the user presses the OK button (Launch) |
- if (LOWORD(wparam) == IDOK) { |
- if (host->OnLaunchDll(dialog)) { |
- if (host->SpawnTarget()) { |
- ::EndDialog(dialog, LOWORD(wparam)); |
- } |
- } |
- return static_cast<INT_PTR>(TRUE); |
- } else if (LOWORD(wparam) == IDCANCEL) { |
- // If the user presses the Cancel button |
- ::EndDialog(dialog, LOWORD(wparam)); |
- return static_cast<INT_PTR>(TRUE); |
- } else if (LOWORD(wparam) == IDC_BROWSE_DLL) { |
- // If the user presses the Browse button to look for a DLL |
- base::string16 dll_path = host->OnShowBrowseForDllDlg(dialog); |
- if (dll_path.length() > 0) { |
- // Initialize the window text for Log File edit box |
- HWND edit_box_dll_path = ::GetDlgItem(dialog, IDC_DLL_NAME); |
- ::SetWindowText(edit_box_dll_path, dll_path.c_str()); |
- } |
- return static_cast<INT_PTR>(TRUE); |
- } else if (LOWORD(wparam) == IDC_BROWSE_LOG) { |
- // If the user presses the Browse button to look for a log file |
- base::string16 log_path = host->OnShowBrowseForLogFileDlg(dialog); |
- if (log_path.length() > 0) { |
- // Initialize the window text for Log File edit box |
- HWND edit_box_log_file = ::GetDlgItem(dialog, IDC_LOG_FILE); |
- ::SetWindowText(edit_box_log_file, log_path.c_str()); |
- } |
- return static_cast<INT_PTR>(TRUE); |
- } |
- |
- break; |
- } |
- |
- return static_cast<INT_PTR>(FALSE); |
-} |
- |
-MainUIWindow* MainUIWindow::FromWindow(HWND main_window) { |
- // We store a 'this' pointer using SetWindowLong in CreateMainWindowAndLoop |
- // so that we can retrieve it with this function later. This prevents us |
- // from having to define all the message handling functions (that we refer to |
- // in the window proc) as static |
- ::GetWindowLongPtr(main_window, GWLP_USERDATA); |
- return reinterpret_cast<MainUIWindow*>( |
- ::GetWindowLongPtr(main_window, GWLP_USERDATA)); |
-} |
- |
-BOOL MainUIWindow::OnCreate(HWND parent_window, LPCREATESTRUCT) { |
- // Create the listview that will the main app UI |
- list_view_ = ::CreateWindow(WC_LISTVIEW, // Class name |
- L"", // Window name |
- WS_CHILD | WS_VISIBLE | LVS_REPORT | |
- LVS_NOCOLUMNHEADER | WS_BORDER, |
- 0, // x |
- 0, // y |
- 0, // width |
- 0, // height |
- parent_window, // parent |
- NULL, // menu |
- ::GetModuleHandle(NULL), |
- 0); // lpParam |
- |
- DCHECK(list_view_); |
- if (!list_view_) |
- return FALSE; |
- |
- LVCOLUMN list_view_column = {0}; |
- list_view_column.mask = LVCF_FMT | LVCF_WIDTH; |
- list_view_column.fmt = LVCFMT_LEFT; |
- list_view_column.cx = 10000; // Maximum size of an entry in the list view. |
- ListView_InsertColumn(list_view_, 0, &list_view_column); |
- |
- // Set list view to show green font on black background |
- ListView_SetBkColor(list_view_, CLR_NONE); |
- ListView_SetTextColor(list_view_, RGB(0x0, 0x0, 0x0)); |
- ListView_SetTextBkColor(list_view_, CLR_NONE); |
- |
- return TRUE; |
-} |
- |
-void MainUIWindow::OnDestroy(HWND window) { |
- // Post a quit message because our application is over when the |
- // user closes this window. |
- ::PostQuitMessage(0); |
-} |
- |
-void MainUIWindow::OnSize(HWND window, UINT state, int cx, int cy) { |
- // If we have a valid inner child, resize it to cover the entire |
- // client area of the main UI window. |
- if (list_view_) { |
- ::MoveWindow(list_view_, |
- 0, // x |
- 0, // y |
- cx, // width |
- cy, // height |
- TRUE); // repaint |
- } |
-} |
- |
-void MainUIWindow::OnPaint(HWND window) { |
- PAINTSTRUCT paintstruct; |
- ::BeginPaint(window, &paintstruct); |
- // add painting code here if required |
- ::EndPaint(window, &paintstruct); |
-} |
- |
-void MainUIWindow::OnFileExit() { |
- ::PostQuitMessage(0); |
-} |
- |
-void MainUIWindow::OnCommandsLaunch(HWND window) { |
- // User wants to see the Select DLL dialog box |
- ::DialogBox(instance_handle_, |
- MAKEINTRESOURCE(IDD_LAUNCH_DLL), |
- window, |
- SpawnTargetWndProc); |
-} |
- |
-bool MainUIWindow::OnLaunchDll(HWND dialog) { |
- HWND edit_box_dll_name = ::GetDlgItem(dialog, IDC_DLL_NAME); |
- HWND edit_box_entry_point = ::GetDlgItem(dialog, IDC_ENTRY_POINT); |
- HWND edit_log_file = ::GetDlgItem(dialog, IDC_LOG_FILE); |
- |
- wchar_t dll_path[MAX_PATH]; |
- wchar_t entry_point[MAX_PATH]; |
- wchar_t log_file[MAX_PATH]; |
- |
- int dll_name_len = ::GetWindowText(edit_box_dll_name, dll_path, MAX_PATH); |
- int entry_point_len = ::GetWindowText(edit_box_entry_point, |
- entry_point, MAX_PATH); |
- // Log file is optional (can be blank) |
- ::GetWindowText(edit_log_file, log_file, MAX_PATH); |
- |
- if (0 >= dll_name_len) { |
- ::MessageBox(dialog, |
- L"Please specify a DLL for the target to load", |
- L"No DLL specified", |
- MB_ICONERROR); |
- return false; |
- } |
- |
- if (GetFileAttributes(dll_path) == INVALID_FILE_ATTRIBUTES) { |
- ::MessageBox(dialog, |
- L"DLL specified was not found", |
- L"DLL not found", |
- MB_ICONERROR); |
- return false; |
- } |
- |
- if (0 >= entry_point_len) { |
- ::MessageBox(dialog, |
- L"Please specify an entry point for the DLL", |
- L"No entry point specified", |
- MB_ICONERROR); |
- return false; |
- } |
- |
- // store these values in the member variables for use in SpawnTarget |
- log_file_ = base::string16(L"\"") + log_file + base::string16(L"\""); |
- dll_path_ = dll_path; |
- entry_point_ = entry_point; |
- |
- return true; |
-} |
- |
-DWORD WINAPI MainUIWindow::ListenPipeThunk(void *param) { |
- return reinterpret_cast<MainUIWindow*>(param)->ListenPipe(); |
-} |
- |
-DWORD WINAPI MainUIWindow::WaitForTargetThunk(void *param) { |
- return reinterpret_cast<MainUIWindow*>(param)->WaitForTarget(); |
-} |
- |
-// Thread waiting for the target application to die. It displays |
-// a message in the list view when it happens. |
-DWORD MainUIWindow::WaitForTarget() { |
- WaitForSingleObject(target_.hProcess, INFINITE); |
- |
- DWORD exit_code = 0; |
- if (!GetExitCodeProcess(target_.hProcess, &exit_code)) { |
- exit_code = 0xFFFF; // Default exit code |
- } |
- |
- ::CloseHandle(target_.hProcess); |
- ::CloseHandle(target_.hThread); |
- |
- AddDebugMessage(L"Targed exited with return code %d", exit_code); |
- return 0; |
-} |
- |
-// Thread waiting for messages on the log pipe. It displays the messages |
-// in the listview. |
-DWORD MainUIWindow::ListenPipe() { |
- HANDLE logfile_handle = NULL; |
- ATL::CString file_to_open = log_file_.c_str(); |
- file_to_open.Remove(L'\"'); |
- if (file_to_open.GetLength()) { |
- logfile_handle = ::CreateFile(file_to_open.GetBuffer(), |
- GENERIC_WRITE, |
- FILE_SHARE_READ | FILE_SHARE_WRITE, |
- NULL, // Default security attributes |
- CREATE_ALWAYS, |
- FILE_ATTRIBUTE_NORMAL, |
- NULL); // No template |
- if (INVALID_HANDLE_VALUE == logfile_handle) { |
- AddDebugMessage(L"Failed to open \"%ls\" for logging. Error %d", |
- file_to_open.GetBuffer(), ::GetLastError()); |
- logfile_handle = NULL; |
- } |
- } |
- |
- const int kSizeBuffer = 1024; |
- BYTE read_buffer[kSizeBuffer] = {0}; |
- ATL::CStringA read_buffer_global; |
- ATL::CStringA string_to_print; |
- |
- DWORD last_error = 0; |
- while (last_error == ERROR_SUCCESS || last_error == ERROR_PIPE_LISTENING || |
- last_error == ERROR_NO_DATA) { |
- DWORD read_data_length; |
- if (::ReadFile(pipe_handle_, |
- read_buffer, |
- kSizeBuffer - 1, // Max read size |
- &read_data_length, |
- NULL)) { // Not overlapped |
- if (logfile_handle) { |
- DWORD write_data_length; |
- ::WriteFile(logfile_handle, |
- read_buffer, |
- read_data_length, |
- &write_data_length, |
- FALSE); // Not overlapped |
- } |
- |
- // Append the new buffer to the current buffer |
- read_buffer[read_data_length] = NULL; |
- read_buffer_global += reinterpret_cast<char *>(read_buffer); |
- read_buffer_global.Remove(10); // Remove the CRs |
- |
- // If we completed a new line, output it |
- int endline = read_buffer_global.Find(13); // search for LF |
- while (-1 != endline) { |
- string_to_print = read_buffer_global; |
- string_to_print.Delete(endline, string_to_print.GetLength()); |
- read_buffer_global.Delete(0, endline); |
- |
- // print the line (with the ending LF) |
- OutputDebugStringA(string_to_print.GetBuffer()); |
- |
- // Remove the ending LF |
- read_buffer_global.Delete(0, 1); |
- |
- // Add the line to the log |
- AddDebugMessage(L"%S", string_to_print.GetBuffer()); |
- |
- endline = read_buffer_global.Find(13); |
- } |
- last_error = ERROR_SUCCESS; |
- } else { |
- last_error = GetLastError(); |
- Sleep(100); |
- } |
- } |
- |
- if (read_buffer_global.GetLength()) { |
- AddDebugMessage(L"%S", read_buffer_global.GetBuffer()); |
- } |
- |
- CloseHandle(pipe_handle_); |
- |
- if (logfile_handle) { |
- CloseHandle(logfile_handle); |
- } |
- |
- return 0; |
-} |
- |
-bool MainUIWindow::SpawnTarget() { |
- // Generate the pipe name |
- GUID random_id; |
- CoCreateGuid(&random_id); |
- |
- wchar_t log_pipe[MAX_PATH] = {0}; |
- wnsprintf(log_pipe, MAX_PATH - 1, |
- L"\\\\.\\pipe\\sbox_pipe_log_%lu_%lu_%lu_%lu", |
- random_id.Data1, |
- random_id.Data2, |
- random_id.Data3, |
- random_id.Data4); |
- |
- // We concatenate the four strings, add three spaces and a zero termination |
- // We use the resulting string as a param to CreateProcess (in SpawnTarget) |
- // Documented maximum for command line in CreateProcess is 32K (msdn) |
- size_t size_call = spawn_target_.length() + entry_point_.length() + |
- dll_path_.length() + wcslen(log_pipe) + 6; |
- if (32 * 1024 < (size_call * sizeof(wchar_t))) { |
- AddDebugMessage(L"The length of the arguments exceeded 32K. " |
- L"Aborting operation."); |
- return false; |
- } |
- |
- wchar_t * arguments = new wchar_t[size_call]; |
- wnsprintf(arguments, static_cast<int>(size_call), L"%ls %ls \"%ls\" %ls", |
- spawn_target_.c_str(), entry_point_.c_str(), |
- dll_path_.c_str(), log_pipe); |
- |
- arguments[size_call - 1] = L'\0'; |
- |
- sandbox::TargetPolicy* policy = broker_->CreatePolicy(); |
- policy->SetJobLevel(sandbox::JOB_LOCKDOWN, 0); |
- policy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS, |
- sandbox::USER_LOCKDOWN); |
- policy->SetAlternateDesktop(true); |
- policy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW); |
- |
- // Set the rule to allow the POC dll to be loaded by the target. Note that |
- // the rule allows 'all access' to the DLL, which could mean that the target |
- // could modify the DLL on disk. |
- policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES, |
- sandbox::TargetPolicy::FILES_ALLOW_ANY, dll_path_.c_str()); |
- |
- sandbox::ResultCode result = broker_->SpawnTarget(spawn_target_.c_str(), |
- arguments, policy, |
- &target_); |
- |
- policy->Release(); |
- policy = NULL; |
- |
- bool return_value = false; |
- if (sandbox::SBOX_ALL_OK != result) { |
- AddDebugMessage( |
- L"Failed to spawn target %ls w/args (%ls), sandbox error code: %d", |
- spawn_target_.c_str(), arguments, result); |
- return_value = false; |
- } else { |
- DWORD thread_id; |
- ::CreateThread(NULL, // Default security attributes |
- NULL, // Default stack size |
- &MainUIWindow::WaitForTargetThunk, |
- this, |
- 0, // No flags |
- &thread_id); |
- |
- pipe_handle_ = ::CreateNamedPipe(log_pipe, |
- PIPE_ACCESS_INBOUND | WRITE_DAC, |
- PIPE_TYPE_MESSAGE | PIPE_NOWAIT, |
- 1, // Number of instances. |
- 512, // Out buffer size. |
- 512, // In buffer size. |
- NMPWAIT_USE_DEFAULT_WAIT, |
- NULL); // Default security descriptor |
- |
- if (INVALID_HANDLE_VALUE == pipe_handle_) |
- AddDebugMessage(L"Failed to create pipe. Error %d", ::GetLastError()); |
- |
- if (!sandbox::AddKnownSidToObject(pipe_handle_, SE_KERNEL_OBJECT, |
- WinWorldSid, GRANT_ACCESS, |
- FILE_ALL_ACCESS)) |
- AddDebugMessage(L"Failed to set security on pipe. Error %d", |
- ::GetLastError()); |
- |
- ::CreateThread(NULL, // Default security attributes |
- NULL, // Default stack size |
- &MainUIWindow::ListenPipeThunk, |
- this, |
- 0, // No flags |
- &thread_id); |
- |
- ::ResumeThread(target_.hThread); |
- |
- AddDebugMessage(L"Successfully spawned target w/args (%ls)", arguments); |
- return_value = true; |
- } |
- |
- delete[] arguments; |
- return return_value; |
-} |
- |
-base::string16 MainUIWindow::OnShowBrowseForDllDlg(HWND owner) { |
- wchar_t filename[MAX_PATH]; |
- wcscpy_s(filename, MAX_PATH, L""); |
- |
- OPENFILENAMEW file_info = {0}; |
- file_info.lStructSize = sizeof(file_info); |
- file_info.hwndOwner = owner; |
- file_info.lpstrFile = filename; |
- file_info.nMaxFile = MAX_PATH; |
- file_info.lpstrFilter = L"DLL files (*.dll)\0*.dll\0All files\0*.*\0\0\0"; |
- |
- file_info.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST; |
- |
- if (GetOpenFileName(&file_info)) { |
- return file_info.lpstrFile; |
- } |
- |
- return L""; |
-} |
- |
-base::string16 MainUIWindow::OnShowBrowseForLogFileDlg(HWND owner) { |
- wchar_t filename[MAX_PATH]; |
- wcscpy_s(filename, MAX_PATH, L""); |
- |
- OPENFILENAMEW file_info = {0}; |
- file_info.lStructSize = sizeof(file_info); |
- file_info.hwndOwner = owner; |
- file_info.lpstrFile = filename; |
- file_info.nMaxFile = MAX_PATH; |
- file_info.lpstrFilter = L"Log file (*.txt)\0*.txt\0All files\0*.*\0\0\0"; |
- |
- file_info.Flags = OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST; |
- |
- if (GetSaveFileName(&file_info)) { |
- return file_info.lpstrFile; |
- } |
- |
- return L""; |
-} |
- |
-void MainUIWindow::AddDebugMessage(const wchar_t* format, ...) { |
- DCHECK(format); |
- if (!format) |
- return; |
- |
- const int kMaxDebugBuffSize = 1024; |
- |
- va_list arg_list; |
- va_start(arg_list, format); |
- |
- wchar_t text[kMaxDebugBuffSize + 1]; |
- vswprintf_s(text, kMaxDebugBuffSize, format, arg_list); |
- text[kMaxDebugBuffSize] = L'\0'; |
- |
- InsertLineInListView(text); |
-} |
- |
- |
-void MainUIWindow::InsertLineInListView(wchar_t* debug_message) { |
- DCHECK(debug_message); |
- if (!debug_message) |
- return; |
- |
- // Prepend the time to the message |
- const int kSizeTime = 100; |
- size_t size_message_with_time = wcslen(debug_message) + kSizeTime; |
- wchar_t * message_time = new wchar_t[size_message_with_time]; |
- |
- time_t time_temp; |
- time_temp = time(NULL); |
- |
- struct tm time = {0}; |
- localtime_s(&time, &time_temp); |
- |
- size_t return_code; |
- return_code = wcsftime(message_time, kSizeTime, L"[%H:%M:%S] ", &time); |
- |
- wcscat_s(message_time, size_message_with_time, debug_message); |
- |
- // We add the debug message to the top of the listview |
- LVITEM item; |
- item.iItem = ListView_GetItemCount(list_view_); |
- item.iSubItem = 0; |
- item.mask = LVIF_TEXT | LVIF_PARAM; |
- item.pszText = message_time; |
- item.lParam = 0; |
- |
- ListView_InsertItem(list_view_, &item); |
- |
- delete[] message_time; |
-} |