Эквивалент LaunchAdvancedAssociationUI для Windows 10

Начиная с Windows 10, IApplicationAssociationRegistrationUI::LaunchAdvancedAssociationUI method < / a> больше не работает.

В Windows Vista, 7 и 8 он открывает панель управления на странице Установить связи программ для указанного приложения.

В Windows 10 ничего не делает.

Это даже задокументировано в документации Microsoft:

Начиная с Windows 10, это не запускает диалоговое окно ассоциации. Он отображает диалоговое окно, информирующее пользователя о том, что он может изменить программы по умолчанию, используемые для открытия расширений файлов, в своих Настройках.

(Даже вторая часть утверждения больше не соответствует действительности в текущей версии Windows 10)


И на самом деле в последних версиях Windows 10 этой панели управления больше нет. Его функции перенесены в приложение «Настройки» в раздел Приложения> Приложения по умолчанию> Установить значения по умолчанию для приложения> [Имя приложения].

введите описание изображения здесь

Есть ли способ программно открыть экран Установить значения по умолчанию для приложения для моего приложения в приложении настроек Windows 10?

Или для приложения рекомендуется другой подход, позволяющий пользователям настраивать ассоциации в Windows 10?


person Martin Prikryl    schedule 24.08.2015    source источник
comment
может быть SHOpenWithDialog?   -  person Jichao    schedule 25.08.2015
comment
@Jichao У меня нет опыта работы с этой функцией, поэтому я не уверен, соответствует ли она моей цели. Но в любом случае см. Примечание в MSDN: < i> Начиная с Windows 10, флаги OAIF_ALLOW_REGISTRATION, OAIF_FORCE_REGISTRATION и OAIF_HIDE_REGISTRATION будут игнорироваться SHOpenWithDialog. Диалоговое окно "Открыть с помощью" больше нельзя использовать для изменения программы по умолчанию, используемой для открытия расширения файла.   -  person Martin Prikryl    schedule 25.08.2015
comment
Chromium использует этот API для изменения ассоциации в Windows 8+. но я не тестировал его на Windows 10. В любом случае, вы можете посмотреть исходный код хрома, чтобы найти стандартный способ изменить ассоциацию.   -  person Jichao    schedule 25.08.2015
comment
Посмотрел исходники хрома. Он использовал ваш второй метод. Так что я думаю, что нет другого лучшего способа выполнить эту работу.   -  person Jichao    schedule 25.08.2015
comment
@Jichao Спасибо. Я фактически взял код из исходного кода Mozilla. Для веб-браузера этого достаточно, потому что страница SettingsPageAppsDefaults позволяет изменить веб-браузер по умолчанию. Таким образом, им не нужно искать другое решение (а значит, оно может быть). Но для небраузерных приложений этого недостаточно.   -  person Martin Prikryl    schedule 25.08.2015
comment
Связано: Вызов ActivateApplication через C #   -  person DavidRR    schedule 02.12.2016
comment
Извините, но я не уверен, какой именно экран / окно / диалоговое окно Windows 10 вы хотите отображать? Этот экран вообще существует?   -  person Simon Mourier    schedule 29.08.2018
comment
@SimonMourier Правда, мой вопрос тоже несколько устарел. Я его обновил.   -  person Martin Prikryl    schedule 30.08.2018
comment
Чтобы попасть на этот экран, вы можете использовать автоматизацию пользовательского интерфейса. Я могу поработать над примером, если вам интересно (C # или C ++).   -  person Simon Mourier    schedule 30.08.2018
comment
@SimonMourier Спасибо. Лучше чем ничего. Но это не совсем то решение, на которое я надеялся :) Но вполне возможно, что другого решения нет ...   -  person Martin Prikryl    schedule 30.08.2018
comment
Вы предпочитаете C # или C ++?   -  person Simon Mourier    schedule 30.08.2018
comment
Я предпочитаю C ++. Спасибо.   -  person Martin Prikryl    schedule 30.08.2018
comment
К вашему сведению, я потерпел неудачу. Я могу получить список приложений, но почему-то МАУ всегда присылает мне только 50 детей (50 приложений ...)   -  person Simon Mourier    schedule 05.09.2018
comment
@SimonMourier Хорошо, спасибо за попытку!   -  person Martin Prikryl    schedule 06.09.2018
comment
Отказ не был вариантом :-) ... мне потребовалось время, чтобы понять, что список виртуализирован.   -  person Simon Mourier    schedule 06.09.2018


Ответы (4)


Чтобы открыть страницу Установить программы по умолчанию:

%windir%\system32\control.exe /name Microsoft.DefaultPrograms /page pageDefaultProgram

Ссылка: https://msdn.microsoft.com/en-us/library/windows/desktop/ee330741.aspx

Примечание. Этот метод не работает с обновлением за апрель 2018 г.


Чтобы открыть страницу Выбрать приложения по умолчанию по типу файла:

Activator->ActivateApplication(
    L"windows.immersivecontrolpanel_cw5n1h2txyewy"
    L"!microsoft.windows.immersivecontrolpanel",
    L"page=SettingsPageAppsDefaults"
    L"&target=SettingsPageAppsDefaultsFileExtensionView", AO_NONE, &pid);

Версия 1709 или новее

Чтобы открыть страницу Установить значения по умолчанию для приложения:

Activator->ActivateApplication(
    L"windows.immersivecontrolpanel_cw5n1h2txyewy"
    L"!microsoft.windows.immersivecontrolpanel",
    L"page=SettingsPageAppsDefaults"
    L"&target=SettingsPageAppsDefaultsDefaultAppsListView", AO_NONE, &pid);
person emk    schedule 27.02.2016
comment
Спасибо! По крайней мере, шаг вперед к окончательному решению. - person Martin Prikryl; 28.02.2016

Изменение системных приложений по умолчанию больше не разрешено. Вот объявление на Блог программы предварительной оценки Windows:

Изменения в том, как Windows 10 обрабатывает приложения по умолчанию: «Приложения по умолчанию» означает способ, которым Windows сопоставляет типы файлов и протоколы (например, HTTP) с приложениями Windows, которые они открывают по умолчанию. Например, ваш любимый фоторедактор может быть установлен в качестве приложения по умолчанию для файлов .JPG, что означает, что когда вы дважды щелкаете файл .JPG в проводнике, он открывается в этом редакторе фотографий. В Windows 8.1 классические приложения Windows (Win32) могут вызывать запрос с просьбой изменить настройки по умолчанию, поэтому вы могли видеть несколько запросов во время установки и после их запуска. Однако приложения из Магазина Windows не могли вызвать это приглашение. Вместо этого после установки ваших приложений появится баннер с уведомлением о том, что доступны новые приложения, и вы должны щелкнуть этот баннер, чтобы изменить настройки по умолчанию.

Мы знаем, что ваши действия по умолчанию важны для вас. В Windows 10 все приложения - как классические приложения для Windows, так и универсальные приложения для Windows - не смогут вызывать запрос на изменение настроек по умолчанию, только Windows. Вы по-прежнему полностью контролируете свои действия по умолчанию, уменьшая при этом некоторый нежелательный шум, который могут вызвать несколько запросов.

Даже если есть способ запустить приложение настроек, вы не сможете сделать больше.

person Vincent    schedule 11.02.2016

  • Откройте главное окно Программы по умолчанию в Панели управления:

    %windir%\system32\control.exe /name Microsoft.DefaultPrograms

  • Откройте страницу Установите программы по умолчанию:

    %windir%\system32\control.exe /name Microsoft.DefaultPrograms /page pageDefaultProgram

  • Откройте страницу Установить связи для программы:

    %windir%\system32\control.exe /name Microsoft.DefaultPrograms /page pageDefaultProgram\pageAdvancedSettings?pszAppName=YourAppRegName

    YourAppRegName - это имя вашего зарегистрированного приложения из HKEY_LOCAL_MACHINE (или HKEY_CURRENT_USER) \ SOFTWARE \ RegisteredApplications, которые необходимо экранировать (используйте UrlEscape, Люк!) перед использованием. Например:

    %windir%\system32\control.exe /name Microsoft.DefaultPrograms /page pageDefaultProgram\pageAdvancedSettings?pszAppName=Internet%20Explorer

  • Откройте страницу Связывание типа файла или протокола с программой:

    %windir%\system32\control.exe /name Microsoft.DefaultPrograms /page pageFileAssoc

  • Откройте страницу Изменить настройки автозапуска:

    %windir%\system32\control.exe /name Microsoft.AutoPlay

  • Откройте страницу Установить доступ к программе и настройки компьютера по умолчанию:

    %windir%\system32\ComputerDefaults.exe

P.S. Также вы можете использовать _8 _, чтобы вместо этого открыть элемент / страницу панели управления:

IOpenControlPanel * OpenControlPanel;

HRESULT Result =
  CoCreateInstance(CLSID_OpenControlPanel,
    NULL, CLSCTX_INPROC, __uuidof(IOpenControlPanel), (void**)&OpenControlPanel);
if (SUCCEEDED(Result))
{
  const wchar_t * Page = L"pageDefaultProgram\\pageAdvancedSettings?pszAppName=YourAppRegName";
  OpenControlPanel->Open(L"Microsoft.DefaultPrograms", Page, NULL);
  OpenControlPanel->Release();
}
person El Sanchez    schedule 06.08.2016
comment
Спасибо. Как вы узнали pageDefaultProgram\pageAdvancedSettings?pszAppName=YourAppRegName? - person Martin Prikryl; 07.08.2016
comment
Ничего не стоит, что pageDefaultProgram\pageAdvancedSettings?pszAppName=YourAppRegName работает и на Windows 7. Но, похоже, это не работает в Windows Vista. - person Martin Prikryl; 07.08.2016
comment
@Martin Prikryl, IApplicationAssociationRegistrationUI интерфейс реализован в библиотеке sud.dll. Я открыл Sud.dll в IDA Pro и попытался найти строковые литералы, такие как pageDefaultProgram. См. Функцию CApplicationAssociationRegistrationUI::LaunchAdvancedAssociationUI. - person El Sanchez; 08.08.2016
comment
Связано: Вызов control.exe через C # - person DavidRR; 02.12.2016
comment
Начиная с обновления за апрель 2018 года, этот метод (или любые другие известные мне методы) больше не будут открывать [Установить ассоциации для программы] и [Установить ассоциации для программы]. Вместо этого откроется настройка [Приложения по умолчанию]. - person emk; 23.06.2018
comment
К сожалению, я не принимаю ответ, поскольку @emk верен, это больше не работает. - person Martin Prikryl; 29.08.2018

Мне удалось это сделать с помощью UI Automation. . Это не идеальное решение, но похоже, что оно работает. Вот код со встроенными комментариями:

#include <stdio.h>
#include <windows.h>
#include <atlbase.h>
#include <atlcom.h>
#include <UIAutomationCore.h>
#include <UIAutomationClient.h>

// the main function
HRESULT OpenSetDefaultsByApp(LPCWSTR appName);

// helpers
HRESULT FindFirstChild(IUIAutomation *automation, IUIAutomationElement *element, PROPERTYID pid, VARIANT value, IUIAutomationElement **child);
HRESULT FindFirstChildInList(IUIAutomation *automation, IUIAutomationElement *list, PROPERTYID pid, VARIANT value, IUIAutomationElement **child);
HRESULT OpenSetDefaultsByApp();

// some useful macros for error handling
// uses wprintf so you might want to change it, if running in a non-console context
#define WIDEN2(x) L ## x
#define WIDEN(x) WIDEN2(x)
#define __WFILE__ WIDEN(__FILE__)
#define HRCHECK(__expr) {hr=(__expr);if(FAILED(hr)){wprintf(L"FAILURE 0x%08X (%i)\n\tline: %u file: '%s'\n\texpr: '" WIDEN(#__expr) L"'\n",hr, hr, __LINE__,__WFILE__);goto cleanup;}}

int main()
{
  CoInitialize(NULL);
  OpenSetDefaultsByApp(L"Google Chrome"); // pass the app name as it's displayed in app settings
  CoUninitialize();
}

HRESULT OpenSetDefaultsByApp(LPCWSTR appName)
{
  HRESULT hr = S_OK;
  CComBSTR name = appName;
  CComPtr<IUIAutomation> automation;
  CComPtr<IUIAutomationElement> root;
  CComPtr<IUIAutomationElement> settingsWindow;
  CComPtr<IUIAutomationElement> coreWindow;
  CComPtr<IUIAutomationElement> content;
  CComPtr<IUIAutomationElement> list;
  CComPtr<IUIAutomationElement> scrollViewer;
  CComPtr<IUIAutomationElement> appNameListItem;
  CComPtr<IUIAutomationElement> manageButton;
  CComPtr<IUIAutomationSelectionItemPattern> selection;
  CComPtr<IUIAutomationInvokePattern> invoke;

  // because setting windows and content are completely refreshed, we need two rounds
  // one to open the list of apps
  HRCHECK(OpenSetDefaultsByApp());

  // another one to select the app that starts now...
  // create UIA COM server and get root
  HRCHECK(automation.CoCreateInstance(CLSID_CUIAutomation8));
  HRCHECK(automation->GetRootElement(&root));

  // get hierarchy one by one. This is so it doesn't take too much time
  HRCHECK(FindFirstChild(automation, root, UIA_ClassNamePropertyId, CComVariant("ApplicationFrameWindow"), &settingsWindow));
  HRCHECK(FindFirstChild(automation, settingsWindow, UIA_ClassNamePropertyId, CComVariant("Windows.UI.Core.CoreWindow"), &coreWindow));
  HRCHECK(FindFirstChild(automation, coreWindow, UIA_AutomationIdPropertyId, CComVariant("pageContent"), &content));
  HRCHECK(FindFirstChild(automation, content, UIA_AutomationIdPropertyId, CComVariant("ItemsControlScrollViewer"), &scrollViewer));

  // now the list of app should be shown, get it
  HRCHECK(FindFirstChild(automation, scrollViewer, UIA_AutomationIdPropertyId, CComVariant("SystemSettings_DefaultApps_DefaultAppsList_ListView"), &list));

  // find the item by it's name
  // the list is virtualized so we use a helper method
  // note for some reason, the name is the name plus a space... 
  name.Append(" ");
  HRCHECK(FindFirstChildInList(automation, list, UIA_NamePropertyId, CComVariant(name), &appNameListItem));

  // we got the app item, select it so the 'Manage' button can appear
  HRCHECK(appNameListItem->GetCurrentPatternAs(UIA_SelectionItemPatternId, IID_PPV_ARGS(&selection)));
  if (!selection) HRCHECK(E_FAIL);
  HRCHECK(selection->Select());

  // get the 'Manage' button
  HRCHECK(FindFirstChild(automation, scrollViewer, UIA_ClassNamePropertyId, CComVariant("Button"), &manageButton));

  // press the 'Manage' button
  HRCHECK(manageButton->GetCurrentPatternAs(UIA_InvokePatternId, IID_PPV_ARGS(&invoke)));
  if (!invoke) HRCHECK(E_FAIL);
  HRCHECK(invoke->Invoke());

cleanup:
  return hr;
}

HRESULT OpenSetDefaultsByApp()
{
  HRESULT hr = S_OK;
  CComPtr<IUIAutomation> automation;
  CComPtr<IUIAutomationElement> root;
  CComPtr<IUIAutomationElement> settingsWindow;
  CComPtr<IUIAutomationElement> coreWindow;
  CComPtr<IUIAutomationElement> content;
  CComPtr<IUIAutomationElement> setDefaultsByAppLink;
  CComPtr<IUIAutomationInvokePattern> invoke;

  // create UIA COM server and get root
  HRCHECK(automation.CoCreateInstance(CLSID_CUIAutomation8));
  HRCHECK(automation->GetRootElement(&root));

  // show up to the deepest we can
  WinExec("control.exe /name Microsoft.DefaultPrograms /page pageDefaultProgram", SW_NORMAL);

  // find the 'Set defaults by app' link (button).
  HRCHECK(FindFirstChild(automation, root, UIA_ClassNamePropertyId, CComVariant("ApplicationFrameWindow"), &settingsWindow));
  HRCHECK(FindFirstChild(automation, settingsWindow, UIA_ClassNamePropertyId, CComVariant("Windows.UI.Core.CoreWindow"), &coreWindow));
  HRCHECK(FindFirstChild(automation, coreWindow, UIA_AutomationIdPropertyId, CComVariant("pageContent"), &content));
  HRCHECK(FindFirstChild(automation, content, UIA_AutomationIdPropertyId, CComVariant("SettingsPageAppsDefaultsDefaultAppsListView_HyperlinkButton"), &setDefaultsByAppLink));

  // yes, so press this button
  HRCHECK(setDefaultsByAppLink->GetCurrentPatternAs(UIA_InvokePatternId, IID_PPV_ARGS(&invoke)));
  if (!invoke) HRCHECK(E_FAIL);
  HRCHECK(invoke->Invoke());

cleanup:
  return hr;
}

// this method has retries with timeouts included, so it's much better than a raw call to FindFirst
HRESULT FindFirstChild(IUIAutomation *automation, IUIAutomationElement *element, PROPERTYID pid, VARIANT value, IUIAutomationElement **child)
{
  HRESULT hr = S_OK;
  int timeout = 5000; // max timeout is defined here as 5 sec. This should be ok for most machines
  int slice = 100; // time between too retries, defined as 100 ms.
  int time = 0;
  CComPtr<IUIAutomationCondition> condition;
  HRCHECK(automation->CreatePropertyCondition(pid, value, &condition));

  do
  {
    // I used SubTree here, this may not be appropriate in all context
    // for performance issues. In fact, this could be passed as a parameter...
    hr = element->FindFirst(TreeScope_Subtree, condition, child);
    if (*child) break;
    time += slice;
    if (time >= timeout) HRCHECK(E_FAIL);
    Sleep(slice);
  } while (TRUE);

cleanup:
  return hr;
}

// this helper supports virtualized list
HRESULT FindFirstChildInList(IUIAutomation *automation, IUIAutomationElement *list, PROPERTYID pid, VARIANT value, IUIAutomationElement **child)
{
  HRESULT hr = S_OK;
  CComBSTR lastName;
  int lastNameCount = 0;
  CComPtr<IUIAutomationCondition> trueCondition;
  HRCHECK(automation->CreateTrueCondition(&trueCondition));

  do
  {
    // get all children
    CComPtr<IUIAutomationElementArray> all;
    HRCHECK(list->FindAll(TreeScope_Children, trueCondition, &all));

    int count;
    HRCHECK(all->get_Length(&count));
    if (count == 0) continue; // there shouldn't be zero element, so go on scanning

    for (int i = 0; i < count; i++)
    {
      // test each element for the searched property
      CComPtr<IUIAutomationElement> element;
      HRCHECK(all->GetElement(i, &element));

      CComVariant v;
      HRCHECK(element->GetCurrentPropertyValue(pid, &v));
      if (VarCmp(&v, &value, 0) == 1)
      {
        HRCHECK(element.QueryInterface(child));
        goto cleanup;
      }
    }

    // not found in the current page/set, go to last element and scroll it into view to force list to load the next
    CComPtr<IUIAutomationElement> last;
    CComPtr<IUIAutomationScrollItemPattern> pattern;
    HRCHECK(all->GetElement(count - 1, &last));

    // check if we didn't progress (same name for 20 rounds)
    CComBSTR name;
    HRCHECK(last->get_CurrentName(&name));
    if (name == lastName)
    {
      lastNameCount++;
      if (lastNameCount > 20) HRCHECK(E_FAIL); // not found!
    }
    else
    {
      lastNameCount = 0;
    }
    lastName = name;

    HRCHECK(last->GetCurrentPatternAs(UIA_ScrollItemPatternId, IID_PPV_ARGS(&pattern)));
    if (!pattern) HRCHECK(E_FAIL);
    HRCHECK(pattern->ScrollIntoView());
  } while (TRUE);

cleanup:
  return hr;
}
person Simon Mourier    schedule 06.09.2018
comment
Спасибо. Как я уже писал выше, я рад этому обходному пути, но я бы не принял такой ответ. Но определенно стоит одобрения и награды. - person Martin Prikryl; 06.09.2018