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

Side by Side Diff: base/file_util_win.cc

Issue 10914109: Refactoring and tests for the highly undertested file_util::CreateOrUpdateShortcutLink() method. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 3 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/file_util.h" 5 #include "base/file_util.h"
6 6
7 #include <windows.h> 7 #include <windows.h>
8 #include <propvarutil.h> 8 #include <propvarutil.h>
9 #include <psapi.h> 9 #include <psapi.h>
10 #include <shellapi.h> 10 #include <shellapi.h>
(...skipping 363 matching lines...) Expand 10 before | Expand all | Expand 10 after
374 if (args) { 374 if (args) {
375 result = i_shell_link->GetArguments(temp, MAX_PATH); 375 result = i_shell_link->GetArguments(temp, MAX_PATH);
376 if (FAILED(result)) 376 if (FAILED(result))
377 return false; 377 return false;
378 378
379 *args = string16(temp); 379 *args = string16(temp);
380 } 380 }
381 return true; 381 return true;
382 } 382 }
383 383
384 bool CreateOrUpdateShortcutLink(const wchar_t *source, 384 bool CreateOrUpdateShortcutLink(const string16& shortcut_path,
385 const wchar_t *destination, 385 const ShortcutProperties& properties,
386 const wchar_t *working_dir, 386 ShortcutOperation operation) {
387 const wchar_t *arguments,
388 const wchar_t *description,
389 const wchar_t *icon,
390 int icon_index,
391 const wchar_t* app_id,
392 uint32 options) {
393 base::ThreadRestrictions::AssertIOAllowed(); 387 base::ThreadRestrictions::AssertIOAllowed();
394 388
395 bool create = (options & SHORTCUT_CREATE_ALWAYS) != 0; 389 // A target is required when |operation| is SHORTCUT_CREATE_ALWAYS.
396 390 if (operation == SHORTCUT_CREATE_ALWAYS &&
397 // |source| is required when SHORTCUT_CREATE_ALWAYS is specified. 391 (properties.bitfield & ShortcutProperties::PROPERTIES_TARGET) == 0) {
398 DCHECK(source || !create); 392 NOTREACHED();
393 return false;
394 }
399 395
400 // Length of arguments and description must be less than MAX_PATH. 396 // Length of arguments and description must be less than MAX_PATH.
401 DCHECK(lstrlen(arguments) < MAX_PATH); 397 DCHECK(properties.arguments.size() < MAX_PATH);
402 DCHECK(lstrlen(description) < MAX_PATH); 398 DCHECK(properties.description.size() < MAX_PATH);
robertshield 2012/09/06 02:37:34 Could these DCHECKs be moved to the setters on Sho
gab 2012/09/06 04:20:02 Sounds good to me, unless an argument is made that
403 399
404 base::win::ScopedComPtr<IShellLink> i_shell_link; 400 base::win::ScopedComPtr<IShellLink> i_shell_link;
405 base::win::ScopedComPtr<IPersistFile> i_persist_file; 401 base::win::ScopedComPtr<IPersistFile> i_persist_file;
406
407 // Get pointer to the IShellLink interface.
408 if (FAILED(i_shell_link.CreateInstance(CLSID_ShellLink, NULL, 402 if (FAILED(i_shell_link.CreateInstance(CLSID_ShellLink, NULL,
409 CLSCTX_INPROC_SERVER)) || 403 CLSCTX_INPROC_SERVER)) ||
410 FAILED(i_persist_file.QueryFrom(i_shell_link))) { 404 FAILED(i_persist_file.QueryFrom(i_shell_link))) {
411 return false; 405 return false;
412 } 406 }
413 407
414 if (!create && FAILED(i_persist_file->Load(destination, STGM_READWRITE))) 408 if (operation == SHORTCUT_UPDATE_EXISTING &&
409 FAILED(i_persist_file->Load(shortcut_path.c_str(), STGM_READWRITE))) {
415 return false; 410 return false;
411 }
416 412
417 if ((source || create) && FAILED(i_shell_link->SetPath(source))) 413 if ((properties.bitfield & ShortcutProperties::PROPERTIES_TARGET) != 0 &&
414 FAILED(i_shell_link->SetPath(properties.target.c_str()))) {
418 return false; 415 return false;
416 }
419 417
420 if (working_dir && FAILED(i_shell_link->SetWorkingDirectory(working_dir))) 418 if ((properties.bitfield & ShortcutProperties::PROPERTIES_WORKING_DIR) != 0 &&
419 FAILED(i_shell_link->SetWorkingDirectory(
420 properties.working_dir.c_str()))) {
421 return false; 421 return false;
422 }
422 423
423 if (arguments && FAILED(i_shell_link->SetArguments(arguments))) 424 if ((properties.bitfield & ShortcutProperties::PROPERTIES_ARGUMENTS) != 0 &&
425 FAILED(i_shell_link->SetArguments(properties.arguments.c_str()))) {
424 return false; 426 return false;
427 }
425 428
426 if (description && FAILED(i_shell_link->SetDescription(description))) 429 if ((properties.bitfield & ShortcutProperties::PROPERTIES_DESCRIPTION) &&
430 FAILED(i_shell_link->SetDescription(properties.description.c_str()))) {
427 return false; 431 return false;
432 }
428 433
429 if (icon && FAILED(i_shell_link->SetIconLocation(icon, icon_index))) 434 if ((properties.bitfield & ShortcutProperties::PROPERTIES_ICON) &&
435 FAILED(i_shell_link->SetIconLocation(properties.icon.c_str(),
436 properties.icon_index))) {
430 return false; 437 return false;
438 }
431 439
432 bool is_dual_mode = (options & SHORTCUT_DUAL_MODE) != 0; 440 const bool has_app_id =
robertshield 2012/09/06 02:37:34 don't think adding const here and on has_dual_mode
gab 2012/09/06 04:20:02 I like const here because it's one of those scenar
robertshield 2012/09/06 19:20:01 I'll insist a bit. The additional cognitive load i
gab 2012/09/07 04:58:05 Done.
433 if ((app_id || is_dual_mode) && 441 (properties.bitfield & ShortcutProperties::PROPERTIES_APP_ID) != 0;
442 const bool has_dual_mode =
443 (properties.bitfield & ShortcutProperties::PROPERTIES_DUAL_MODE) != 0;
robertshield 2012/09/06 02:37:34 how about: bool has_dual_mode = (properties.bitfie
gab 2012/09/06 04:20:02 That'd be an implicit cast from int to bool. Not h
robertshield 2012/09/06 19:20:01 I feel it makes the code more readable and I don't
gab 2012/09/07 04:58:05 Tried, but I'm getting warnings->errors: g:\src\c
444 if ((has_app_id || has_dual_mode) &&
434 base::win::GetVersion() >= base::win::VERSION_WIN7) { 445 base::win::GetVersion() >= base::win::VERSION_WIN7) {
435 base::win::ScopedComPtr<IPropertyStore> property_store; 446 base::win::ScopedComPtr<IPropertyStore> property_store;
436 if (FAILED(property_store.QueryFrom(i_shell_link)) || !property_store.get()) 447 if (FAILED(property_store.QueryFrom(i_shell_link)) || !property_store.get())
437 return false; 448 return false;
438 449
439 if (app_id && !base::win::SetAppIdForPropertyStore(property_store, app_id)) 450 if (has_app_id &&
451 !base::win::SetAppIdForPropertyStore(property_store,
452 properties.app_id.c_str())) {
440 return false; 453 return false;
441 if (is_dual_mode && 454 }
442 !base::win::SetDualModeForPropertyStore(property_store)) { 455 if (has_dual_mode &&
456 !base::win::SetDualModeForPropertyStore(property_store,
457 properties.dual_mode)) {
443 return false; 458 return false;
444 } 459 }
445 } 460 }
446 461
447 HRESULT result = i_persist_file->Save(destination, TRUE); 462 HRESULT result = i_persist_file->Save(shortcut_path.c_str(), TRUE);
448 463
449 // If we successfully updated the icon, notify the shell that we have done so. 464 // If we successfully updated the icon, notify the shell that we have done so.
450 if (!create && SUCCEEDED(result)) { 465 if (operation == SHORTCUT_UPDATE_EXISTING && SUCCEEDED(result)) {
451 // Release the interfaces in case the SHChangeNotify call below depends on 466 // Release the interfaces in case the SHChangeNotify call below depends on
452 // the operations above being fully completed. 467 // the operations above being fully completed.
453 i_persist_file.Release(); 468 i_persist_file.Release();
454 i_shell_link.Release(); 469 i_shell_link.Release();
455 470
456 SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL); 471 SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
457 } 472 }
458 473
459 return SUCCEEDED(result); 474 return SUCCEEDED(result);
460 } 475 }
(...skipping 661 matching lines...) Expand 10 before | Expand all | Expand 10 after
1122 HANDLE cp = GetCurrentProcess(); 1137 HANDLE cp = GetCurrentProcess();
1123 if (::GetMappedFileNameW(cp, file_view, mapped_file_path, kMaxPathLength)) { 1138 if (::GetMappedFileNameW(cp, file_view, mapped_file_path, kMaxPathLength)) {
1124 *nt_path = FilePath(mapped_file_path); 1139 *nt_path = FilePath(mapped_file_path);
1125 success = true; 1140 success = true;
1126 } 1141 }
1127 ::UnmapViewOfFile(file_view); 1142 ::UnmapViewOfFile(file_view);
1128 return success; 1143 return success;
1129 } 1144 }
1130 1145
1131 } // namespace file_util 1146 } // namespace file_util
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698