Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(300)

Side by Side Diff: sandbox/win/sandbox_poc/main_ui_window.cc

Issue 1851213002: Remove sandbox on Windows. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix nacl compile issues Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « sandbox/win/sandbox_poc/main_ui_window.h ('k') | sandbox/win/sandbox_poc/pocdll/exports.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "sandbox/win/sandbox_poc/main_ui_window.h"
6
7 #include <windows.h>
8 #include <CommCtrl.h>
9 #include <commdlg.h>
10 #include <stdarg.h>
11 #include <stddef.h>
12 #include <time.h>
13 #include <windowsx.h>
14 #include <atlbase.h>
15 #include <atlsecurity.h>
16 #include <algorithm>
17 #include <sstream>
18
19 #include "base/logging.h"
20 #include "sandbox/win/sandbox_poc/resource.h"
21 #include "sandbox/win/src/acl.h"
22 #include "sandbox/win/src/sandbox.h"
23 #include "sandbox/win/src/win_utils.h"
24
25 HWND MainUIWindow::list_view_ = NULL;
26
27 const wchar_t MainUIWindow::kDefaultDll_[] = L"\\POCDLL.dll";
28 const wchar_t MainUIWindow::kDefaultEntryPoint_[] = L"Run";
29 const wchar_t MainUIWindow::kDefaultLogFile_[] = L"";
30
31 MainUIWindow::MainUIWindow()
32 : broker_(NULL),
33 spawn_target_(L""),
34 instance_handle_(NULL),
35 dll_path_(L""),
36 entry_point_(L"") {
37 }
38
39 MainUIWindow::~MainUIWindow() {
40 }
41
42 unsigned int MainUIWindow::CreateMainWindowAndLoop(
43 HINSTANCE instance,
44 wchar_t* command_line,
45 int show_command,
46 sandbox::BrokerServices* broker) {
47 DCHECK(instance);
48 DCHECK(command_line);
49 DCHECK(broker);
50
51 instance_handle_ = instance;
52 spawn_target_ = command_line;
53 broker_ = broker;
54
55 // We'll use spawn_target_ later for creating a child process, but
56 // CreateProcess doesn't like double quotes, so we remove them along with
57 // tabs and spaces from the start and end of the string
58 const wchar_t *trim_removal = L" \r\t\"";
59 spawn_target_.erase(0, spawn_target_.find_first_not_of(trim_removal));
60 spawn_target_.erase(spawn_target_.find_last_not_of(trim_removal) + 1);
61
62 WNDCLASSEX window_class = {0};
63 window_class.cbSize = sizeof(WNDCLASSEX);
64 window_class.style = CS_HREDRAW | CS_VREDRAW;
65 window_class.lpfnWndProc = MainUIWindow::WndProc;
66 window_class.cbClsExtra = 0;
67 window_class.cbWndExtra = 0;
68 window_class.hInstance = instance;
69 window_class.hIcon =
70 ::LoadIcon(instance, MAKEINTRESOURCE(IDI_SANDBOX));
71 window_class.hCursor = ::LoadCursor(NULL, IDC_ARROW);
72 window_class.hbrBackground = GetStockBrush(WHITE_BRUSH);
73 window_class.lpszMenuName = MAKEINTRESOURCE(IDR_MENU_MAIN_UI);
74 window_class.lpszClassName = L"sandbox_ui_1";
75 window_class.hIconSm = NULL;
76
77 INITCOMMONCONTROLSEX controls = {
78 sizeof(INITCOMMONCONTROLSEX),
79 ICC_STANDARD_CLASSES | ICC_LISTVIEW_CLASSES
80 };
81 ::InitCommonControlsEx(&controls);
82
83 if (!::RegisterClassEx(&window_class))
84 return ::GetLastError();
85
86 // Create a main window of size 600x400
87 HWND window = ::CreateWindowW(window_class.lpszClassName,
88 L"", // window name
89 WS_OVERLAPPEDWINDOW,
90 CW_USEDEFAULT, // x
91 CW_USEDEFAULT, // y
92 600, // width
93 400, // height
94 NULL, // parent
95 NULL, // NULL = use class menu
96 instance,
97 0); // lpParam
98
99 if (NULL == window)
100 return ::GetLastError();
101
102 ::SetWindowLongPtr(window,
103 GWLP_USERDATA,
104 reinterpret_cast<LONG_PTR>(this));
105
106 ::SetWindowText(window, L"Sandbox Proof of Concept");
107
108 ::ShowWindow(window, show_command);
109
110 MSG message;
111 // Now lets start the message pump retrieving messages for any window that
112 // belongs to the current thread
113 while (::GetMessage(&message, NULL, 0, 0)) {
114 ::TranslateMessage(&message);
115 ::DispatchMessage(&message);
116 }
117
118 return 0;
119 }
120
121 LRESULT CALLBACK MainUIWindow::WndProc(HWND window,
122 UINT message_id,
123 WPARAM wparam,
124 LPARAM lparam) {
125 MainUIWindow* host = FromWindow(window);
126
127 #define HANDLE_MSG(hwnd, message, fn) \
128 case (message): return HANDLE_##message((hwnd), (wParam), (lParam), (fn))
129
130 switch (message_id) {
131 case WM_CREATE:
132 // 'host' is not yet available when we get the WM_CREATE message
133 return HANDLE_WM_CREATE(window, wparam, lparam, OnCreate);
134 case WM_DESTROY:
135 return HANDLE_WM_DESTROY(window, wparam, lparam, host->OnDestroy);
136 case WM_SIZE:
137 return HANDLE_WM_SIZE(window, wparam, lparam, host->OnSize);
138 case WM_COMMAND: {
139 // Look at which menu item was clicked on (or which accelerator)
140 int id = LOWORD(wparam);
141 switch (id) {
142 case ID_FILE_EXIT:
143 host->OnFileExit();
144 break;
145 case ID_COMMANDS_SPAWNTARGET:
146 host->OnCommandsLaunch(window);
147 break;
148 default:
149 // Some other menu item or accelerator
150 break;
151 }
152
153 return ERROR_SUCCESS;
154 }
155
156 default:
157 // Some other WM_message, let it pass to DefWndProc
158 break;
159 }
160
161 return DefWindowProc(window, message_id, wparam, lparam);
162 }
163
164 INT_PTR CALLBACK MainUIWindow::SpawnTargetWndProc(HWND dialog,
165 UINT message_id,
166 WPARAM wparam,
167 LPARAM lparam) {
168 // Grab a reference to the main UI window (from the window handle)
169 MainUIWindow* host = FromWindow(GetParent(dialog));
170 DCHECK(host);
171
172 switch (message_id) {
173 case WM_INITDIALOG: {
174 // Initialize the window text for DLL name edit box
175 HWND edit_box_dll_name = ::GetDlgItem(dialog, IDC_DLL_NAME);
176 wchar_t current_dir[MAX_PATH];
177 if (GetCurrentDirectory(MAX_PATH, current_dir)) {
178 base::string16 dll_path = base::string16(current_dir) +
179 base::string16(kDefaultDll_);
180 ::SetWindowText(edit_box_dll_name, dll_path.c_str());
181 }
182
183 // Initialize the window text for Entry Point edit box
184 HWND edit_box_entry_point = ::GetDlgItem(dialog, IDC_ENTRY_POINT);
185 ::SetWindowText(edit_box_entry_point, kDefaultEntryPoint_);
186
187 // Initialize the window text for Log File edit box
188 HWND edit_box_log_file = ::GetDlgItem(dialog, IDC_LOG_FILE);
189 ::SetWindowText(edit_box_log_file, kDefaultLogFile_);
190
191 return static_cast<INT_PTR>(TRUE);
192 }
193 case WM_COMMAND:
194 // If the user presses the OK button (Launch)
195 if (LOWORD(wparam) == IDOK) {
196 if (host->OnLaunchDll(dialog)) {
197 if (host->SpawnTarget()) {
198 ::EndDialog(dialog, LOWORD(wparam));
199 }
200 }
201 return static_cast<INT_PTR>(TRUE);
202 } else if (LOWORD(wparam) == IDCANCEL) {
203 // If the user presses the Cancel button
204 ::EndDialog(dialog, LOWORD(wparam));
205 return static_cast<INT_PTR>(TRUE);
206 } else if (LOWORD(wparam) == IDC_BROWSE_DLL) {
207 // If the user presses the Browse button to look for a DLL
208 base::string16 dll_path = host->OnShowBrowseForDllDlg(dialog);
209 if (dll_path.length() > 0) {
210 // Initialize the window text for Log File edit box
211 HWND edit_box_dll_path = ::GetDlgItem(dialog, IDC_DLL_NAME);
212 ::SetWindowText(edit_box_dll_path, dll_path.c_str());
213 }
214 return static_cast<INT_PTR>(TRUE);
215 } else if (LOWORD(wparam) == IDC_BROWSE_LOG) {
216 // If the user presses the Browse button to look for a log file
217 base::string16 log_path = host->OnShowBrowseForLogFileDlg(dialog);
218 if (log_path.length() > 0) {
219 // Initialize the window text for Log File edit box
220 HWND edit_box_log_file = ::GetDlgItem(dialog, IDC_LOG_FILE);
221 ::SetWindowText(edit_box_log_file, log_path.c_str());
222 }
223 return static_cast<INT_PTR>(TRUE);
224 }
225
226 break;
227 }
228
229 return static_cast<INT_PTR>(FALSE);
230 }
231
232 MainUIWindow* MainUIWindow::FromWindow(HWND main_window) {
233 // We store a 'this' pointer using SetWindowLong in CreateMainWindowAndLoop
234 // so that we can retrieve it with this function later. This prevents us
235 // from having to define all the message handling functions (that we refer to
236 // in the window proc) as static
237 ::GetWindowLongPtr(main_window, GWLP_USERDATA);
238 return reinterpret_cast<MainUIWindow*>(
239 ::GetWindowLongPtr(main_window, GWLP_USERDATA));
240 }
241
242 BOOL MainUIWindow::OnCreate(HWND parent_window, LPCREATESTRUCT) {
243 // Create the listview that will the main app UI
244 list_view_ = ::CreateWindow(WC_LISTVIEW, // Class name
245 L"", // Window name
246 WS_CHILD | WS_VISIBLE | LVS_REPORT |
247 LVS_NOCOLUMNHEADER | WS_BORDER,
248 0, // x
249 0, // y
250 0, // width
251 0, // height
252 parent_window, // parent
253 NULL, // menu
254 ::GetModuleHandle(NULL),
255 0); // lpParam
256
257 DCHECK(list_view_);
258 if (!list_view_)
259 return FALSE;
260
261 LVCOLUMN list_view_column = {0};
262 list_view_column.mask = LVCF_FMT | LVCF_WIDTH;
263 list_view_column.fmt = LVCFMT_LEFT;
264 list_view_column.cx = 10000; // Maximum size of an entry in the list view.
265 ListView_InsertColumn(list_view_, 0, &list_view_column);
266
267 // Set list view to show green font on black background
268 ListView_SetBkColor(list_view_, CLR_NONE);
269 ListView_SetTextColor(list_view_, RGB(0x0, 0x0, 0x0));
270 ListView_SetTextBkColor(list_view_, CLR_NONE);
271
272 return TRUE;
273 }
274
275 void MainUIWindow::OnDestroy(HWND window) {
276 // Post a quit message because our application is over when the
277 // user closes this window.
278 ::PostQuitMessage(0);
279 }
280
281 void MainUIWindow::OnSize(HWND window, UINT state, int cx, int cy) {
282 // If we have a valid inner child, resize it to cover the entire
283 // client area of the main UI window.
284 if (list_view_) {
285 ::MoveWindow(list_view_,
286 0, // x
287 0, // y
288 cx, // width
289 cy, // height
290 TRUE); // repaint
291 }
292 }
293
294 void MainUIWindow::OnPaint(HWND window) {
295 PAINTSTRUCT paintstruct;
296 ::BeginPaint(window, &paintstruct);
297 // add painting code here if required
298 ::EndPaint(window, &paintstruct);
299 }
300
301 void MainUIWindow::OnFileExit() {
302 ::PostQuitMessage(0);
303 }
304
305 void MainUIWindow::OnCommandsLaunch(HWND window) {
306 // User wants to see the Select DLL dialog box
307 ::DialogBox(instance_handle_,
308 MAKEINTRESOURCE(IDD_LAUNCH_DLL),
309 window,
310 SpawnTargetWndProc);
311 }
312
313 bool MainUIWindow::OnLaunchDll(HWND dialog) {
314 HWND edit_box_dll_name = ::GetDlgItem(dialog, IDC_DLL_NAME);
315 HWND edit_box_entry_point = ::GetDlgItem(dialog, IDC_ENTRY_POINT);
316 HWND edit_log_file = ::GetDlgItem(dialog, IDC_LOG_FILE);
317
318 wchar_t dll_path[MAX_PATH];
319 wchar_t entry_point[MAX_PATH];
320 wchar_t log_file[MAX_PATH];
321
322 int dll_name_len = ::GetWindowText(edit_box_dll_name, dll_path, MAX_PATH);
323 int entry_point_len = ::GetWindowText(edit_box_entry_point,
324 entry_point, MAX_PATH);
325 // Log file is optional (can be blank)
326 ::GetWindowText(edit_log_file, log_file, MAX_PATH);
327
328 if (0 >= dll_name_len) {
329 ::MessageBox(dialog,
330 L"Please specify a DLL for the target to load",
331 L"No DLL specified",
332 MB_ICONERROR);
333 return false;
334 }
335
336 if (GetFileAttributes(dll_path) == INVALID_FILE_ATTRIBUTES) {
337 ::MessageBox(dialog,
338 L"DLL specified was not found",
339 L"DLL not found",
340 MB_ICONERROR);
341 return false;
342 }
343
344 if (0 >= entry_point_len) {
345 ::MessageBox(dialog,
346 L"Please specify an entry point for the DLL",
347 L"No entry point specified",
348 MB_ICONERROR);
349 return false;
350 }
351
352 // store these values in the member variables for use in SpawnTarget
353 log_file_ = base::string16(L"\"") + log_file + base::string16(L"\"");
354 dll_path_ = dll_path;
355 entry_point_ = entry_point;
356
357 return true;
358 }
359
360 DWORD WINAPI MainUIWindow::ListenPipeThunk(void *param) {
361 return reinterpret_cast<MainUIWindow*>(param)->ListenPipe();
362 }
363
364 DWORD WINAPI MainUIWindow::WaitForTargetThunk(void *param) {
365 return reinterpret_cast<MainUIWindow*>(param)->WaitForTarget();
366 }
367
368 // Thread waiting for the target application to die. It displays
369 // a message in the list view when it happens.
370 DWORD MainUIWindow::WaitForTarget() {
371 WaitForSingleObject(target_.hProcess, INFINITE);
372
373 DWORD exit_code = 0;
374 if (!GetExitCodeProcess(target_.hProcess, &exit_code)) {
375 exit_code = 0xFFFF; // Default exit code
376 }
377
378 ::CloseHandle(target_.hProcess);
379 ::CloseHandle(target_.hThread);
380
381 AddDebugMessage(L"Targed exited with return code %d", exit_code);
382 return 0;
383 }
384
385 // Thread waiting for messages on the log pipe. It displays the messages
386 // in the listview.
387 DWORD MainUIWindow::ListenPipe() {
388 HANDLE logfile_handle = NULL;
389 ATL::CString file_to_open = log_file_.c_str();
390 file_to_open.Remove(L'\"');
391 if (file_to_open.GetLength()) {
392 logfile_handle = ::CreateFile(file_to_open.GetBuffer(),
393 GENERIC_WRITE,
394 FILE_SHARE_READ | FILE_SHARE_WRITE,
395 NULL, // Default security attributes
396 CREATE_ALWAYS,
397 FILE_ATTRIBUTE_NORMAL,
398 NULL); // No template
399 if (INVALID_HANDLE_VALUE == logfile_handle) {
400 AddDebugMessage(L"Failed to open \"%ls\" for logging. Error %d",
401 file_to_open.GetBuffer(), ::GetLastError());
402 logfile_handle = NULL;
403 }
404 }
405
406 const int kSizeBuffer = 1024;
407 BYTE read_buffer[kSizeBuffer] = {0};
408 ATL::CStringA read_buffer_global;
409 ATL::CStringA string_to_print;
410
411 DWORD last_error = 0;
412 while (last_error == ERROR_SUCCESS || last_error == ERROR_PIPE_LISTENING ||
413 last_error == ERROR_NO_DATA) {
414 DWORD read_data_length;
415 if (::ReadFile(pipe_handle_,
416 read_buffer,
417 kSizeBuffer - 1, // Max read size
418 &read_data_length,
419 NULL)) { // Not overlapped
420 if (logfile_handle) {
421 DWORD write_data_length;
422 ::WriteFile(logfile_handle,
423 read_buffer,
424 read_data_length,
425 &write_data_length,
426 FALSE); // Not overlapped
427 }
428
429 // Append the new buffer to the current buffer
430 read_buffer[read_data_length] = NULL;
431 read_buffer_global += reinterpret_cast<char *>(read_buffer);
432 read_buffer_global.Remove(10); // Remove the CRs
433
434 // If we completed a new line, output it
435 int endline = read_buffer_global.Find(13); // search for LF
436 while (-1 != endline) {
437 string_to_print = read_buffer_global;
438 string_to_print.Delete(endline, string_to_print.GetLength());
439 read_buffer_global.Delete(0, endline);
440
441 // print the line (with the ending LF)
442 OutputDebugStringA(string_to_print.GetBuffer());
443
444 // Remove the ending LF
445 read_buffer_global.Delete(0, 1);
446
447 // Add the line to the log
448 AddDebugMessage(L"%S", string_to_print.GetBuffer());
449
450 endline = read_buffer_global.Find(13);
451 }
452 last_error = ERROR_SUCCESS;
453 } else {
454 last_error = GetLastError();
455 Sleep(100);
456 }
457 }
458
459 if (read_buffer_global.GetLength()) {
460 AddDebugMessage(L"%S", read_buffer_global.GetBuffer());
461 }
462
463 CloseHandle(pipe_handle_);
464
465 if (logfile_handle) {
466 CloseHandle(logfile_handle);
467 }
468
469 return 0;
470 }
471
472 bool MainUIWindow::SpawnTarget() {
473 // Generate the pipe name
474 GUID random_id;
475 CoCreateGuid(&random_id);
476
477 wchar_t log_pipe[MAX_PATH] = {0};
478 wnsprintf(log_pipe, MAX_PATH - 1,
479 L"\\\\.\\pipe\\sbox_pipe_log_%lu_%lu_%lu_%lu",
480 random_id.Data1,
481 random_id.Data2,
482 random_id.Data3,
483 random_id.Data4);
484
485 // We concatenate the four strings, add three spaces and a zero termination
486 // We use the resulting string as a param to CreateProcess (in SpawnTarget)
487 // Documented maximum for command line in CreateProcess is 32K (msdn)
488 size_t size_call = spawn_target_.length() + entry_point_.length() +
489 dll_path_.length() + wcslen(log_pipe) + 6;
490 if (32 * 1024 < (size_call * sizeof(wchar_t))) {
491 AddDebugMessage(L"The length of the arguments exceeded 32K. "
492 L"Aborting operation.");
493 return false;
494 }
495
496 wchar_t * arguments = new wchar_t[size_call];
497 wnsprintf(arguments, static_cast<int>(size_call), L"%ls %ls \"%ls\" %ls",
498 spawn_target_.c_str(), entry_point_.c_str(),
499 dll_path_.c_str(), log_pipe);
500
501 arguments[size_call - 1] = L'\0';
502
503 sandbox::TargetPolicy* policy = broker_->CreatePolicy();
504 policy->SetJobLevel(sandbox::JOB_LOCKDOWN, 0);
505 policy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS,
506 sandbox::USER_LOCKDOWN);
507 policy->SetAlternateDesktop(true);
508 policy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW);
509
510 // Set the rule to allow the POC dll to be loaded by the target. Note that
511 // the rule allows 'all access' to the DLL, which could mean that the target
512 // could modify the DLL on disk.
513 policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES,
514 sandbox::TargetPolicy::FILES_ALLOW_ANY, dll_path_.c_str());
515
516 sandbox::ResultCode result = broker_->SpawnTarget(spawn_target_.c_str(),
517 arguments, policy,
518 &target_);
519
520 policy->Release();
521 policy = NULL;
522
523 bool return_value = false;
524 if (sandbox::SBOX_ALL_OK != result) {
525 AddDebugMessage(
526 L"Failed to spawn target %ls w/args (%ls), sandbox error code: %d",
527 spawn_target_.c_str(), arguments, result);
528 return_value = false;
529 } else {
530 DWORD thread_id;
531 ::CreateThread(NULL, // Default security attributes
532 NULL, // Default stack size
533 &MainUIWindow::WaitForTargetThunk,
534 this,
535 0, // No flags
536 &thread_id);
537
538 pipe_handle_ = ::CreateNamedPipe(log_pipe,
539 PIPE_ACCESS_INBOUND | WRITE_DAC,
540 PIPE_TYPE_MESSAGE | PIPE_NOWAIT,
541 1, // Number of instances.
542 512, // Out buffer size.
543 512, // In buffer size.
544 NMPWAIT_USE_DEFAULT_WAIT,
545 NULL); // Default security descriptor
546
547 if (INVALID_HANDLE_VALUE == pipe_handle_)
548 AddDebugMessage(L"Failed to create pipe. Error %d", ::GetLastError());
549
550 if (!sandbox::AddKnownSidToObject(pipe_handle_, SE_KERNEL_OBJECT,
551 WinWorldSid, GRANT_ACCESS,
552 FILE_ALL_ACCESS))
553 AddDebugMessage(L"Failed to set security on pipe. Error %d",
554 ::GetLastError());
555
556 ::CreateThread(NULL, // Default security attributes
557 NULL, // Default stack size
558 &MainUIWindow::ListenPipeThunk,
559 this,
560 0, // No flags
561 &thread_id);
562
563 ::ResumeThread(target_.hThread);
564
565 AddDebugMessage(L"Successfully spawned target w/args (%ls)", arguments);
566 return_value = true;
567 }
568
569 delete[] arguments;
570 return return_value;
571 }
572
573 base::string16 MainUIWindow::OnShowBrowseForDllDlg(HWND owner) {
574 wchar_t filename[MAX_PATH];
575 wcscpy_s(filename, MAX_PATH, L"");
576
577 OPENFILENAMEW file_info = {0};
578 file_info.lStructSize = sizeof(file_info);
579 file_info.hwndOwner = owner;
580 file_info.lpstrFile = filename;
581 file_info.nMaxFile = MAX_PATH;
582 file_info.lpstrFilter = L"DLL files (*.dll)\0*.dll\0All files\0*.*\0\0\0";
583
584 file_info.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
585
586 if (GetOpenFileName(&file_info)) {
587 return file_info.lpstrFile;
588 }
589
590 return L"";
591 }
592
593 base::string16 MainUIWindow::OnShowBrowseForLogFileDlg(HWND owner) {
594 wchar_t filename[MAX_PATH];
595 wcscpy_s(filename, MAX_PATH, L"");
596
597 OPENFILENAMEW file_info = {0};
598 file_info.lStructSize = sizeof(file_info);
599 file_info.hwndOwner = owner;
600 file_info.lpstrFile = filename;
601 file_info.nMaxFile = MAX_PATH;
602 file_info.lpstrFilter = L"Log file (*.txt)\0*.txt\0All files\0*.*\0\0\0";
603
604 file_info.Flags = OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST;
605
606 if (GetSaveFileName(&file_info)) {
607 return file_info.lpstrFile;
608 }
609
610 return L"";
611 }
612
613 void MainUIWindow::AddDebugMessage(const wchar_t* format, ...) {
614 DCHECK(format);
615 if (!format)
616 return;
617
618 const int kMaxDebugBuffSize = 1024;
619
620 va_list arg_list;
621 va_start(arg_list, format);
622
623 wchar_t text[kMaxDebugBuffSize + 1];
624 vswprintf_s(text, kMaxDebugBuffSize, format, arg_list);
625 text[kMaxDebugBuffSize] = L'\0';
626
627 InsertLineInListView(text);
628 }
629
630
631 void MainUIWindow::InsertLineInListView(wchar_t* debug_message) {
632 DCHECK(debug_message);
633 if (!debug_message)
634 return;
635
636 // Prepend the time to the message
637 const int kSizeTime = 100;
638 size_t size_message_with_time = wcslen(debug_message) + kSizeTime;
639 wchar_t * message_time = new wchar_t[size_message_with_time];
640
641 time_t time_temp;
642 time_temp = time(NULL);
643
644 struct tm time = {0};
645 localtime_s(&time, &time_temp);
646
647 size_t return_code;
648 return_code = wcsftime(message_time, kSizeTime, L"[%H:%M:%S] ", &time);
649
650 wcscat_s(message_time, size_message_with_time, debug_message);
651
652 // We add the debug message to the top of the listview
653 LVITEM item;
654 item.iItem = ListView_GetItemCount(list_view_);
655 item.iSubItem = 0;
656 item.mask = LVIF_TEXT | LVIF_PARAM;
657 item.pszText = message_time;
658 item.lParam = 0;
659
660 ListView_InsertItem(list_view_, &item);
661
662 delete[] message_time;
663 }
OLDNEW
« no previous file with comments | « sandbox/win/sandbox_poc/main_ui_window.h ('k') | sandbox/win/sandbox_poc/pocdll/exports.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698