text: // Copyright (c) 2012 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 "stdafx.h"
  #include "winrt_utils.h"
  
  #include <shlobj.h>
  
  #include "base/files/file_path.h"
  #include "base/logging.h"
  #include "base/win/scoped_com_initializer.h"
  #include "base/win/scoped_comptr.h"
  
  void CheckHR(HRESULT hr, const char* message) {
    if (FAILED(hr)) {
      if (message)
        PLOG(DFATAL) << message << ", hr = " << std::hex << hr;
      else
        PLOG(DFATAL) << "COM ERROR" << ", hr = " << std::hex << hr;
    }
  }
  
  HSTRING MakeHString(const string16& str) {
    HSTRING hstr;
    if (FAILED(::WindowsCreateString(str.c_str(), static_cast<UINT32>(str.size()),
                                     &hstr))) {
      PLOG(DFATAL) << "Hstring creation failed";
    }
    return hstr;
  }
  
  string16 MakeStdWString(HSTRING hstring) {
    const wchar_t* str;
    UINT32 size = 0;
    str = ::WindowsGetStringRawBuffer(hstring, &size);
    if (!size)
      return string16();
    return string16(str, size);
  }
  
  namespace {
  
  #define IMPLEMENT_CREATE_PROPERTY(Name, Type) \
  HRESULT Create ## Name ## Property(Type value, \
                                     winfoundtn::IPropertyValue** prop) { \
    mswr::ComPtr<winfoundtn::IPropertyValueStatics> property_value_statics; \
    HRESULT hr = winrt_utils::CreateActivationFactory( \
        RuntimeClass_Windows_Foundation_PropertyValue, \
        property_value_statics.GetAddressOf()); \
    CheckHR(hr, "Can't create IPropertyValueStatics"); \
    hr = property_value_statics->Create ## Name ## ( \
        value, \
        reinterpret_cast<IInspectable**>(prop)); \
    CheckHR(hr, "Failed to create Property"); \
    return hr; \
  }
  
  #define COMPARE_ATOMIC_PROPERTY_VALUES(Name, Type) \
    Type lhs_value; \
    hr = lhs->Get ## Name ##(&lhs_value); \
    CheckHR(hr, "Can't get value for lhs"); \
    Type rhs_value; \
    hr = rhs->Get ## Name ##(&rhs_value); \
    CheckHR(hr, "Can't get value for rhs"); \
    if (lhs_value < rhs_value) \
      *result = -1; \
    else if (lhs_value > rhs_value) \
      *result = 1; \
    else \
      *result = 0; \
    hr = S_OK
  
  }  // namespace
  
  namespace winrt_utils {
  
  IMPLEMENT_CREATE_PROPERTY(String, HSTRING);
  IMPLEMENT_CREATE_PROPERTY(Int16, INT16);
  IMPLEMENT_CREATE_PROPERTY(Int32, INT32);
  IMPLEMENT_CREATE_PROPERTY(Int64, INT64);
  IMPLEMENT_CREATE_PROPERTY(UInt8, UINT8);
  IMPLEMENT_CREATE_PROPERTY(UInt16, UINT16);
  IMPLEMENT_CREATE_PROPERTY(UInt32, UINT32);
  IMPLEMENT_CREATE_PROPERTY(UInt64, UINT64);
  
  HRESULT CompareProperties(winfoundtn::IPropertyValue* lhs,
                            winfoundtn::IPropertyValue* rhs,
                            INT32* result) {
    if (result == nullptr) {
      PLOG(DFATAL) << "Invalid argument to CompareProperties.";
      return E_INVALIDARG;
    }
  
    if (lhs == rhs) {
      *result = 0;
      return S_OK;
    }
  
    winfoundtn::PropertyType lhs_property_type;
    HRESULT hr = lhs->get_Type(&lhs_property_type);
    if (FAILED(hr)) {
      PLOG(DFATAL) << "Can't get property type for lhs, hr=" << std::hex << hr;
    }
  
    winfoundtn::PropertyType rhs_property_type;
    hr = rhs->get_Type(&rhs_property_type);
    CheckHR(hr, "Can't get property type for rhs");
  
    if (lhs_property_type != rhs_property_type)
      return E_INVALIDARG;
  
    switch (lhs_property_type) {
      case winfoundtn::PropertyType::PropertyType_String: {
        mswrw::HString lhs_string;
        hr = lhs->GetString(lhs_string.GetAddressOf());
        CheckHR(hr, "Can't get string for lhs");
  
        mswrw::HString rhs_string;
        hr = rhs->GetString(rhs_string.GetAddressOf());
        CheckHR(hr, "Can't get string for rhs");
  
        hr = WindowsCompareStringOrdinal(
            lhs_string.Get(), rhs_string.Get(), result);
        break;
      }
      case winfoundtn::PropertyType::PropertyType_Char16: {
        COMPARE_ATOMIC_PROPERTY_VALUES(Char16, wchar_t);
        break;
      }
      case winfoundtn::PropertyType::PropertyType_Double: {
        COMPARE_ATOMIC_PROPERTY_VALUES(Double, double);
        break;
      }
      case winfoundtn::PropertyType::PropertyType_Int16: {
        COMPARE_ATOMIC_PROPERTY_VALUES(Int16, INT16);
        break;
      }
      case winfoundtn::PropertyType::PropertyType_Int32: {
        COMPARE_ATOMIC_PROPERTY_VALUES(Int32, INT32);
        break;
      }
      case winfoundtn::PropertyType::PropertyType_Int64: {
        COMPARE_ATOMIC_PROPERTY_VALUES(Int64, INT64);
        break;
      }
      case winfoundtn::PropertyType::PropertyType_UInt8: {
        COMPARE_ATOMIC_PROPERTY_VALUES(UInt8, UINT8);
        break;
      }
      case winfoundtn::PropertyType::PropertyType_UInt16: {
        COMPARE_ATOMIC_PROPERTY_VALUES(UInt16, UINT16);
        break;
      }
      case winfoundtn::PropertyType::PropertyType_UInt32: {
        COMPARE_ATOMIC_PROPERTY_VALUES(UInt32, UINT32);
        break;
      }
      case winfoundtn::PropertyType::PropertyType_UInt64: {
        COMPARE_ATOMIC_PROPERTY_VALUES(UInt64, UINT64);
        break;
      }
      default: {
        hr = E_NOTIMPL;
      }
    }
    return hr;
  }
  
  bool GetArgumentsFromShortcut(const base::FilePath& shortcut,
                                string16* arguments) {
    HRESULT result;
    base::win::ScopedComPtr<IShellLink> i_shell_link;
    bool is_resolved = false;
  
  
    base::win::ScopedCOMInitializer sta_com_initializer;
  
    // Get pointer to the IShellLink interface
    result = i_shell_link.CreateInstance(CLSID_ShellLink, NULL,
                                         CLSCTX_INPROC_SERVER);
    if (SUCCEEDED(result)) {
      base::win::ScopedComPtr<IPersistFile> persist;
      // Query IShellLink for the IPersistFile interface
      result = persist.QueryFrom(i_shell_link);
      if (SUCCEEDED(result)) {
        WCHAR temp_arguments[MAX_PATH];
        // Load the shell link
        result = persist->Load(shortcut.value().c_str(), STGM_READ);
        if (SUCCEEDED(result)) {
          result = i_shell_link->GetArguments(temp_arguments, MAX_PATH);
          *arguments = temp_arguments;
          is_resolved = true;
        }
      }
    }
  
    return is_resolved;
  }
  
  string16 ReadArgumentsFromPinnedTaskbarShortcut() {
    wchar_t path_buffer[MAX_PATH] = {};
  
    if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL,
                                  SHGFP_TYPE_CURRENT, path_buffer))) {
      base::FilePath shortcut(path_buffer);
      shortcut = shortcut.Append(
          L"Microsoft\\Internet Explorer\\Quick Launch\\User Pinned\\TaskBar");
  
      // TODO(robertshield): Get this stuff from BrowserDistribution.
  #if defined(GOOGLE_CHROME_BUILD)
      shortcut = shortcut.Append(L"Google Chrome.lnk");
  #else
      shortcut = shortcut.Append(L"Chromium.lnk");
  #endif
  
      string16 arguments;
      if (GetArgumentsFromShortcut(shortcut, &arguments)) {
        return arguments;
      }
    }
  
    return L"";
  }
  
  }  // namespace winrt_utils
  