From 898071bb085251fef322526dac659e40b8576128 Mon Sep 17 00:00:00 2001 From: Rafal Harabien Date: Thu, 5 Jan 2012 18:31:18 +0000 Subject: [PATCH] [SHELL32] - Rewrite Open With menu and dialog - Load all applications - Use treeview with Recommended and Other programs - Don't allow duplicates - Load registry keys in proper way svn path=/trunk/; revision=54844 --- reactos/dll/win32/shell32/lang/bg-BG.rc | 5 +- reactos/dll/win32/shell32/lang/ca-ES.rc | 7 +- reactos/dll/win32/shell32/lang/cs-CZ.rc | 7 +- reactos/dll/win32/shell32/lang/da-DK.rc | 5 +- reactos/dll/win32/shell32/lang/de-DE.rc | 7 +- reactos/dll/win32/shell32/lang/el-GR.rc | 9 +- reactos/dll/win32/shell32/lang/en-GB.rc | 7 +- reactos/dll/win32/shell32/lang/en-US.rc | 8 +- reactos/dll/win32/shell32/lang/es-ES.rc | 3 + reactos/dll/win32/shell32/lang/fi-FI.rc | 7 +- reactos/dll/win32/shell32/lang/fr-FR.rc | 7 +- reactos/dll/win32/shell32/lang/hu-HU.rc | 7 +- reactos/dll/win32/shell32/lang/it-IT.rc | 7 +- reactos/dll/win32/shell32/lang/ja-JP.rc | 7 +- reactos/dll/win32/shell32/lang/ko-KR.rc | 7 +- reactos/dll/win32/shell32/lang/nl-NL.rc | 9 +- reactos/dll/win32/shell32/lang/no-NO.rc | 7 +- reactos/dll/win32/shell32/lang/pl-PL.rc | 9 +- reactos/dll/win32/shell32/lang/pt-BR.rc | 7 +- reactos/dll/win32/shell32/lang/pt-PT.rc | 7 +- reactos/dll/win32/shell32/lang/ro-RO.rc | 3 + reactos/dll/win32/shell32/lang/ru-RU.rc | 6 +- reactos/dll/win32/shell32/lang/sk-SK.rc | 7 +- reactos/dll/win32/shell32/lang/sl-SI.rc | 7 +- reactos/dll/win32/shell32/lang/sv-SE.rc | 7 +- reactos/dll/win32/shell32/lang/tr-TR.rc | 7 +- reactos/dll/win32/shell32/lang/uk-UA.rc | 7 +- reactos/dll/win32/shell32/lang/zh-CN.rc | 5 +- reactos/dll/win32/shell32/lang/zh-TW.rc | 7 +- reactos/dll/win32/shell32/openwithmenu.cpp | 1916 +++++++++++--------- reactos/dll/win32/shell32/openwithmenu.h | 7 + reactos/dll/win32/shell32/shresdef.h | 2 + 32 files changed, 1251 insertions(+), 869 deletions(-) diff --git a/reactos/dll/win32/shell32/lang/bg-BG.rc b/reactos/dll/win32/shell32/lang/bg-BG.rc index 5f9ad83c7b4..163260d16cf 100644 --- a/reactos/dll/win32/shell32/lang/bg-BG.rc +++ b/reactos/dll/win32/shell32/lang/bg-BG.rc @@ -371,7 +371,7 @@ BEGIN LTEXT "Изберете приложение, което да отвори този файл:", -1, 44, 12, 211, 10 LTEXT "Файл: ", 14001, 44, 25, 188, 10 GROUPBOX "&Приложения", -1, 7, 42, 249, 187 - LISTBOX 14002, 16 ,57, 230, 130, LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP, WS_EX_STATICEDGE + CONTROL "Programs", 14002, WC_TREEVIEW, WS_BORDER | WS_TABSTOP | TVS_SHOWSELALWAYS, 16 ,57, 230, 130 AUTOCHECKBOX "&Винаги избраното приложение да отваря този вид файлове.", 14003, 20, 193, 225, 10 PUSHBUTTON "&Обзор...", 14004, 198, 207, 50, 14 PUSHBUTTON "Добре", 14005, 150, 236, 50, 14 @@ -714,8 +714,11 @@ BEGIN IDS_DRIVE_CDROM "КД четец" IDS_DRIVE_NETWORK "Мрежов диск" + /* Open With */ IDS_OPEN_WITH "Отваряне с" IDS_OPEN_WITH_CHOOSE "Избор на приложение..." + IDS_OPEN_WITH_RECOMMENDED "Recommended Programs:" + IDS_OPEN_WITH_OTHER "Other Programs:" IDS_SHELL_ABOUT_AUTHORS "&Създатели" IDS_SHELL_ABOUT_BACK "< &Назад" diff --git a/reactos/dll/win32/shell32/lang/ca-ES.rc b/reactos/dll/win32/shell32/lang/ca-ES.rc index 409b5a457c4..c1e9ab7c85f 100644 --- a/reactos/dll/win32/shell32/lang/ca-ES.rc +++ b/reactos/dll/win32/shell32/lang/ca-ES.rc @@ -372,10 +372,10 @@ BEGIN LTEXT "Choose the program you want to use to open this file:", -1, 44, 12, 211, 10 LTEXT "File: ", 14001, 44, 25, 188, 10 GROUPBOX "&Programs", -1, 7, 42, 249, 187 - LISTBOX 14002, 16 ,57, 230, 130, LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP, WS_EX_STATICEDGE + CONTROL "Programs", 14002, WC_TREEVIEW, WS_BORDER | WS_TABSTOP | TVS_SHOWSELALWAYS, 16 ,57, 230, 130 AUTOCHECKBOX "&Always use the selected program to open this kind of file", 14003, 20, 193, 225, 10 PUSHBUTTON "&Browse...", 14004, 198, 207, 50, 14 - PUSHBUTTON "OK", 14005, 150, 236, 50, 14 + DEFPUSHBUTTON "OK", 14005, 150, 236, 50, 14 PUSHBUTTON "Cancel", 14006, 206, 236, 50, 14 END @@ -713,8 +713,11 @@ BEGIN IDS_DRIVE_CDROM "CDROM" IDS_DRIVE_NETWORK "Network Disk" + /* Open With */ IDS_OPEN_WITH "Open With" IDS_OPEN_WITH_CHOOSE "Choose Program..." + IDS_OPEN_WITH_RECOMMENDED "Recommended Programs:" + IDS_OPEN_WITH_OTHER "Other Programs:" IDS_SHELL_ABOUT_AUTHORS "&Authors" IDS_SHELL_ABOUT_BACK "< &Back" diff --git a/reactos/dll/win32/shell32/lang/cs-CZ.rc b/reactos/dll/win32/shell32/lang/cs-CZ.rc index a02d4cf5fd9..b655f31a3ca 100644 --- a/reactos/dll/win32/shell32/lang/cs-CZ.rc +++ b/reactos/dll/win32/shell32/lang/cs-CZ.rc @@ -360,10 +360,10 @@ BEGIN LTEXT "Vyberte program, ve kterém chcete otevřít tento soubor: ", -1, 44, 12, 211, 10 LTEXT "Soubor: ", 14001, 44, 25, 188, 10 GROUPBOX "&Programy", -1, 7, 42, 249, 187 - LISTBOX 14002, 16 ,57, 230, 130, LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP, WS_EX_STATICEDGE + CONTROL "Programs", 14002, WC_TREEVIEW, WS_BORDER | WS_TABSTOP | TVS_SHOWSELALWAYS, 16 ,57, 230, 130 AUTOCHECKBOX "&Vždy použít vybraný program k otevření tohoto typu souboru", 14003, 20, 193, 225, 10 PUSHBUTTON "P&rocházet...", 14004, 198, 207, 50, 14 - PUSHBUTTON "OK", 14005, 150, 236, 50, 14 + DEFPUSHBUTTON "OK", 14005, 150, 236, 50, 14 PUSHBUTTON "Storno", 14006, 206, 236, 50, 14 END @@ -701,8 +701,11 @@ BEGIN IDS_DRIVE_CDROM "CDROM" IDS_DRIVE_NETWORK "Síťový Disk" + /* Open With */ IDS_OPEN_WITH "Otevřít v" IDS_OPEN_WITH_CHOOSE "Zvolit program..." + IDS_OPEN_WITH_RECOMMENDED "Recommended Programs:" + IDS_OPEN_WITH_OTHER "Other Programs:" IDS_SHELL_ABOUT_AUTHORS "&Autoři" IDS_SHELL_ABOUT_BACK "< &Zpět" diff --git a/reactos/dll/win32/shell32/lang/da-DK.rc b/reactos/dll/win32/shell32/lang/da-DK.rc index fdfc825b13d..5c6343667c3 100644 --- a/reactos/dll/win32/shell32/lang/da-DK.rc +++ b/reactos/dll/win32/shell32/lang/da-DK.rc @@ -364,7 +364,7 @@ BEGIN LISTBOX 14002, 16 ,57, 230, 130, LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP,WS_EX_STATICEDGE AUTOCHECKBOX "&Always use the selected program to open this kind of file", 14003, 20, 193, 225, 10 PUSHBUTTON "&Browse...", 14004, 198, 207, 50, 14 - PUSHBUTTON "OK", 14005, 150, 236, 50, 14 + DEFPUSHBUTTON "OK", 14005, 150, 236, 50, 14 PUSHBUTTON "Cancel", 14006, 206, 236, 50, 14 END @@ -702,8 +702,11 @@ BEGIN IDS_DRIVE_CDROM "CDROM" IDS_DRIVE_NETWORK "Network Disk" + /* Open With */ IDS_OPEN_WITH "Open With" IDS_OPEN_WITH_CHOOSE "Choose Program..." + IDS_OPEN_WITH_RECOMMENDED "Recommended Programs:" + IDS_OPEN_WITH_OTHER "Other Programs:" IDS_SHELL_ABOUT_AUTHORS "&Authors" IDS_SHELL_ABOUT_BACK "< &Back" diff --git a/reactos/dll/win32/shell32/lang/de-DE.rc b/reactos/dll/win32/shell32/lang/de-DE.rc index 6ab0782fbad..a49b50d0f44 100644 --- a/reactos/dll/win32/shell32/lang/de-DE.rc +++ b/reactos/dll/win32/shell32/lang/de-DE.rc @@ -375,10 +375,10 @@ BEGIN LTEXT "Wählen Sie das Programm, das zum Öffnen dieser Datei verwendet werden soll:", -1, 44, 12, 211, 18 LTEXT "Datei: ", 14001, 44, 30, 188, 10 GROUPBOX "&Programme", -1, 7, 42, 249, 187 - LISTBOX 14002, 16 ,57, 230, 130, LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP, WS_EX_STATICEDGE + CONTROL "Programs", 14002, WC_TREEVIEW, WS_BORDER | WS_TABSTOP | TVS_SHOWSELALWAYS, 16 ,57, 230, 130 AUTOCHECKBOX "&Dateityp &immer mit dem ausgewählten Programm öffnen", 14003, 20, 193, 225, 10 PUSHBUTTON "&Durchsuchen...", 14004, 188, 207, 60, 14 - PUSHBUTTON "OK", 14005, 150, 236, 50, 14 + DEFPUSHBUTTON "OK", 14005, 150, 236, 50, 14 PUSHBUTTON "Abbrechen", 14006, 206, 236, 50, 14 END @@ -718,8 +718,11 @@ BEGIN IDS_DRIVE_CDROM "CD-Laufwerk" IDS_DRIVE_NETWORK "Netzlaufwerk" + /* Open With */ IDS_OPEN_WITH "Öffnen &mit..." IDS_OPEN_WITH_CHOOSE "Programm wählen..." + IDS_OPEN_WITH_RECOMMENDED "Recommended Programs:" + IDS_OPEN_WITH_OTHER "Other Programs:" IDS_SHELL_ABOUT_AUTHORS "&Autoren" IDS_SHELL_ABOUT_BACK "< &Zurück" diff --git a/reactos/dll/win32/shell32/lang/el-GR.rc b/reactos/dll/win32/shell32/lang/el-GR.rc index 5ff89e67758..d9addc071fe 100644 --- a/reactos/dll/win32/shell32/lang/el-GR.rc +++ b/reactos/dll/win32/shell32/lang/el-GR.rc @@ -372,10 +372,10 @@ BEGIN LTEXT "Επιλέξτε το πρόγραμμα με το οποίο θέλετε να ανοίξετε αυτό το αρχείο:", -1, 44, 12, 211, 10 LTEXT "Αρχείο: %s", 14001, 44, 25, 188, 10 GROUPBOX "Προγράμματα", -1, 7, 42, 249, 187 - LISTBOX 14002, 16 ,57, 230, 130, LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP, WS_EX_STATICEDGE + CONTROL "Programs", 14002, WC_TREEVIEW, WS_BORDER | WS_TABSTOP | TVS_SHOWSELALWAYS, 16 ,57, 230, 130 CHECKBOX "&Άνοιγμα αυτού του είδους αρχείου, πάντα με το επιλεγμένο πρόγραμμα", 14003, 20, 193, 225, 10 PUSHBUTTON "&Αναζήτηση...", 14004, 198, 207, 50, 14 - PUSHBUTTON "OK", 14005, 150, 236, 50, 14 + DEFPUSHBUTTON "OK", 14005, 150, 236, 50, 14 PUSHBUTTON "Άκυρο", 14006, 206, 236, 50, 14 END @@ -714,8 +714,11 @@ BEGIN IDS_DRIVE_CDROM "Μονάδα CD" IDS_DRIVE_NETWORK "Δίσκος δικτύου" - IDS_OPEN_WITH "Άνοιγμα με" + /* Open With */ + IDS_OPEN_WITH "Άνοιγμαμε" IDS_OPEN_WITH_CHOOSE "Επιλογή προγράμματος..." + IDS_OPEN_WITH_RECOMMENDED "Recommended Programs:" + IDS_OPEN_WITH_OTHER "Other Programs:" IDS_SHELL_ABOUT_AUTHORS "&Προγραμματιστές" IDS_SHELL_ABOUT_BACK "< &Επιστροφή" diff --git a/reactos/dll/win32/shell32/lang/en-GB.rc b/reactos/dll/win32/shell32/lang/en-GB.rc index 0884bb62dfc..09845eeabe2 100644 --- a/reactos/dll/win32/shell32/lang/en-GB.rc +++ b/reactos/dll/win32/shell32/lang/en-GB.rc @@ -372,10 +372,10 @@ BEGIN LTEXT "Choose the program you want to use to open this file:", -1, 44, 12, 211, 10 LTEXT "File: ", 14001, 44, 25, 188, 10 GROUPBOX "&Programs", -1, 7, 42, 249, 187 - LISTBOX 14002, 16 ,57, 230, 130, LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP, WS_EX_STATICEDGE + CONTROL "Programs", 14002, WC_TREEVIEW, WS_BORDER | WS_TABSTOP | TVS_SHOWSELALWAYS, 16 ,57, 230, 130 AUTOCHECKBOX "&Always use the selected program to open this kind of file", 14003, 20, 193, 225, 10 PUSHBUTTON "&Browse...", 14004, 198, 207, 50, 14 - PUSHBUTTON "OK", 14005, 150, 236, 50, 14 + DEFPUSHBUTTON "OK", 14005, 150, 236, 50, 14 PUSHBUTTON "Cancel", 14006, 206, 236, 50, 14 END @@ -713,8 +713,11 @@ BEGIN IDS_DRIVE_CDROM "CDROM" IDS_DRIVE_NETWORK "Network Disk" + /* Open With */ IDS_OPEN_WITH "Open With" IDS_OPEN_WITH_CHOOSE "Choose Program..." + IDS_OPEN_WITH_RECOMMENDED "Recommended Programs:" + IDS_OPEN_WITH_OTHER "Other Programs:" IDS_SHELL_ABOUT_AUTHORS "&Authors" IDS_SHELL_ABOUT_BACK "< &Back" diff --git a/reactos/dll/win32/shell32/lang/en-US.rc b/reactos/dll/win32/shell32/lang/en-US.rc index 1dc59cbad55..41d2c5ce9e6 100644 --- a/reactos/dll/win32/shell32/lang/en-US.rc +++ b/reactos/dll/win32/shell32/lang/en-US.rc @@ -372,10 +372,10 @@ BEGIN LTEXT "Choose the program you want to use to open this file:", -1, 44, 12, 211, 10 LTEXT "File: ", 14001, 44, 25, 188, 10 GROUPBOX "&Programs", -1, 7, 42, 249, 187 - LISTBOX 14002, 16 ,57, 230, 130, LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP, WS_EX_STATICEDGE + CONTROL "Programs", 14002, WC_TREEVIEW, WS_BORDER | WS_TABSTOP | TVS_SHOWSELALWAYS, 16 ,57, 230, 130 AUTOCHECKBOX "&Always use the selected program to open this kind of file", 14003, 20, 193, 225, 10 PUSHBUTTON "&Browse...", 14004, 198, 207, 50, 14 - PUSHBUTTON "OK", 14005, 150, 236, 50, 14 + DEFPUSHBUTTON "OK", 14005, 150, 236, 50, 14 PUSHBUTTON "Cancel", 14006, 206, 236, 50, 14 END @@ -389,7 +389,6 @@ BEGIN LTEXT "File", 14001, 8, 6, 169, 10 END - FOLDER_OPTIONS_GENERAL_DLG DIALOGEX 0, 0, 264, 256 STYLE DS_SHELLFONT | WS_POPUP | WS_CAPTION CAPTION "General" @@ -724,8 +723,11 @@ BEGIN IDS_DRIVE_CDROM "CDROM" IDS_DRIVE_NETWORK "Network Disk" + /* Open With */ IDS_OPEN_WITH "Open With" IDS_OPEN_WITH_CHOOSE "Choose Program..." + IDS_OPEN_WITH_RECOMMENDED "Recommended Programs:" + IDS_OPEN_WITH_OTHER "Other Programs:" IDS_SHELL_ABOUT_AUTHORS "&Authors" IDS_SHELL_ABOUT_BACK "< &Back" diff --git a/reactos/dll/win32/shell32/lang/es-ES.rc b/reactos/dll/win32/shell32/lang/es-ES.rc index 1c2a4bd322f..38d9016f926 100644 --- a/reactos/dll/win32/shell32/lang/es-ES.rc +++ b/reactos/dll/win32/shell32/lang/es-ES.rc @@ -726,8 +726,11 @@ BEGIN IDS_DRIVE_CDROM "CDROM" IDS_DRIVE_NETWORK "Unidad de red" + /* Open With */ IDS_OPEN_WITH "Abrir con" IDS_OPEN_WITH_CHOOSE "Elegir programa..." + IDS_OPEN_WITH_RECOMMENDED "Recommended Programs:" + IDS_OPEN_WITH_OTHER "Other Programs:" IDS_SHELL_ABOUT_AUTHORS "&Autores" IDS_SHELL_ABOUT_BACK "< A&trás" diff --git a/reactos/dll/win32/shell32/lang/fi-FI.rc b/reactos/dll/win32/shell32/lang/fi-FI.rc index 848a1cbd7bd..80be6e89a07 100644 --- a/reactos/dll/win32/shell32/lang/fi-FI.rc +++ b/reactos/dll/win32/shell32/lang/fi-FI.rc @@ -372,10 +372,10 @@ BEGIN LTEXT "Choose the program you want to use to open this file:", -1, 44, 12, 211, 10 LTEXT "File: ", 14001, 44, 25, 188, 10 GROUPBOX "&Programs", -1, 7, 42, 249, 187 - LISTBOX 14002, 16 ,57, 230, 130, LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP, WS_EX_STATICEDGE + CONTROL "Programs", 14002, WC_TREEVIEW, WS_BORDER | WS_TABSTOP | TVS_SHOWSELALWAYS, 16 ,57, 230, 130 AUTOCHECKBOX "&Always use the selected program to open this kind of file", 14003, 20, 193, 225, 10 PUSHBUTTON "&Browse...", 14004, 198, 207, 50, 14 - PUSHBUTTON "OK", 14005, 150, 236, 50, 14 + DEFPUSHBUTTON "OK", 14005, 150, 236, 50, 14 PUSHBUTTON "Cancel", 14006, 206, 236, 50, 14 END @@ -713,8 +713,11 @@ BEGIN IDS_DRIVE_CDROM "CDROM" IDS_DRIVE_NETWORK "Network Disk" + /* Open With */ IDS_OPEN_WITH "Open With" IDS_OPEN_WITH_CHOOSE "Choose Program..." + IDS_OPEN_WITH_RECOMMENDED "Recommended Programs:" + IDS_OPEN_WITH_OTHER "Other Programs:" IDS_SHELL_ABOUT_AUTHORS "&Authors" IDS_SHELL_ABOUT_BACK "< &Back" diff --git a/reactos/dll/win32/shell32/lang/fr-FR.rc b/reactos/dll/win32/shell32/lang/fr-FR.rc index c177de667a1..48b91fd0b94 100644 --- a/reactos/dll/win32/shell32/lang/fr-FR.rc +++ b/reactos/dll/win32/shell32/lang/fr-FR.rc @@ -376,10 +376,10 @@ BEGIN LTEXT "Choisissez le programme que vous désirez utiliser pour ouvrir ce fichier :", -1, 44, 12, 211, 10 LTEXT "Fichier : ", 14001, 44, 25, 188, 10 GROUPBOX "&Programmes", -1, 7, 42, 249, 187 - LISTBOX 14002, 16 ,57, 230, 130, LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP, WS_EX_STATICEDGE + CONTROL "Programs", 14002, WC_TREEVIEW, WS_BORDER | WS_TABSTOP | TVS_SHOWSELALWAYS, 16 ,57, 230, 130 AUTOCHECKBOX "Toujours utiliser le progr&amme sélectionné pour ouvrir ce type de fichier", 14003, 20, 193, 225, 10 PUSHBUTTON "Parcourir...", 14004, 198, 207, 50, 14 - PUSHBUTTON "OK", 14005, 150, 236, 50, 14 + DEFPUSHBUTTON "OK", 14005, 150, 236, 50, 14 PUSHBUTTON "Annuler", 14006, 206, 236, 50, 14 END @@ -717,8 +717,11 @@ BEGIN IDS_DRIVE_CDROM "CDROM" IDS_DRIVE_NETWORK "Disque réseau" + /* Open With */ IDS_OPEN_WITH "Ouvrir avec" IDS_OPEN_WITH_CHOOSE "Choisir le programme..." + IDS_OPEN_WITH_RECOMMENDED "Recommended Programs:" + IDS_OPEN_WITH_OTHER "Other Programs:" IDS_SHELL_ABOUT_AUTHORS "&Auteurs" IDS_SHELL_ABOUT_BACK "< Précédent" diff --git a/reactos/dll/win32/shell32/lang/hu-HU.rc b/reactos/dll/win32/shell32/lang/hu-HU.rc index 4a31fd92b13..72fcb298090 100644 --- a/reactos/dll/win32/shell32/lang/hu-HU.rc +++ b/reactos/dll/win32/shell32/lang/hu-HU.rc @@ -375,10 +375,10 @@ BEGIN LTEXT "Choose the program you want to use to open this file:", -1, 44, 12, 211, 10 LTEXT "File: ", 14001, 44, 25, 188, 10 GROUPBOX "&Programs", -1, 7, 42, 249, 187 - LISTBOX 14002, 16 ,57, 230, 130, LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP, WS_EX_STATICEDGE + CONTROL "Programs", 14002, WC_TREEVIEW, WS_BORDER | WS_TABSTOP | TVS_SHOWSELALWAYS, 16 ,57, 230, 130 AUTOCHECKBOX "&Always use the selected program to open this kind of file", 14003, 20, 193, 225, 10 PUSHBUTTON "&Browse...", 14004, 198, 207, 50, 14 - PUSHBUTTON "OK", 14005, 150, 236, 50, 14 + DEFPUSHBUTTON "OK", 14005, 150, 236, 50, 14 PUSHBUTTON "Cancel", 14006, 206, 236, 50, 14 END @@ -716,8 +716,11 @@ BEGIN IDS_DRIVE_CDROM "CDROM" IDS_DRIVE_NETWORK "Network Disk" + /* Open With */ IDS_OPEN_WITH "Open With" IDS_OPEN_WITH_CHOOSE "Choose Program..." + IDS_OPEN_WITH_RECOMMENDED "Recommended Programs:" + IDS_OPEN_WITH_OTHER "Other Programs:" IDS_SHELL_ABOUT_AUTHORS "&Authors" IDS_SHELL_ABOUT_BACK "< &Back" diff --git a/reactos/dll/win32/shell32/lang/it-IT.rc b/reactos/dll/win32/shell32/lang/it-IT.rc index 5fc021f6bb1..75ed2e60e27 100644 --- a/reactos/dll/win32/shell32/lang/it-IT.rc +++ b/reactos/dll/win32/shell32/lang/it-IT.rc @@ -373,10 +373,10 @@ BEGIN LTEXT "Scegliere il programma che volete usare per aprire questo file:", -1, 44, 12, 211, 10 LTEXT "File: ", 14001, 44, 25, 188, 10 GROUPBOX "&Programmi", -1, 7, 42, 249, 187 - LISTBOX 14002, 16 ,57, 230, 130, LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP, WS_EX_STATICEDGE + CONTROL "Programs", 14002, WC_TREEVIEW, WS_BORDER | WS_TABSTOP | TVS_SHOWSELALWAYS, 16 ,57, 230, 130 AUTOCHECKBOX "&Usare sempre il programma selezionato per aprire questo tipo di file", 14003, 20, 193, 225, 10 PUSHBUTTON "&Sfoglia...", 14004, 198, 207, 50, 14 - PUSHBUTTON "OK", 14005, 150, 236, 50, 14 + DEFPUSHBUTTON "OK", 14005, 150, 236, 50, 14 PUSHBUTTON "Annulla", 14006, 206, 236, 50, 14 END @@ -724,8 +724,11 @@ BEGIN IDS_DRIVE_CDROM "CDROM" IDS_DRIVE_NETWORK "Disco di Rete" + /* Open With */ IDS_OPEN_WITH "Apri con" IDS_OPEN_WITH_CHOOSE "Scegliere un programma..." + IDS_OPEN_WITH_RECOMMENDED "Recommended Programs:" + IDS_OPEN_WITH_OTHER "Other Programs:" IDS_SHELL_ABOUT_AUTHORS "&Autori" IDS_SHELL_ABOUT_BACK "< &Indietro" diff --git a/reactos/dll/win32/shell32/lang/ja-JP.rc b/reactos/dll/win32/shell32/lang/ja-JP.rc index c2a52557635..847c2fdeb42 100644 --- a/reactos/dll/win32/shell32/lang/ja-JP.rc +++ b/reactos/dll/win32/shell32/lang/ja-JP.rc @@ -372,10 +372,10 @@ BEGIN LTEXT "このファイルを開くために使用するプログラムを選択してください:", -1, 44, 12, 211, 10 LTEXT "ファイル: ", 14001, 44, 25, 188, 10 GROUPBOX "プログラムの一覧(&P)", -1, 7, 42, 249, 187 - LISTBOX 14002, 16 ,57, 230, 130, LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP, WS_EX_STATICEDGE + CONTROL "Programs", 14002, WC_TREEVIEW, WS_BORDER | WS_TABSTOP | TVS_SHOWSELALWAYS, 16 ,57, 230, 130 AUTOCHECKBOX "この種類のファイルを開くときは、常に選択したプログラムを使用する(&A)", 14003, 20, 193, 225, 10 PUSHBUTTON "参照(&B)...", 14004, 198, 207, 50, 14 - PUSHBUTTON "OK", 14005, 150, 236, 50, 14 + DEFPUSHBUTTON "OK", 14005, 150, 236, 50, 14 PUSHBUTTON "キャンセル", 14006, 206, 236, 50, 14 END @@ -713,8 +713,11 @@ BEGIN IDS_DRIVE_CDROM "CDROM" IDS_DRIVE_NETWORK "ネットワーク ディスク" + /* Open With */ IDS_OPEN_WITH "プログラムから開く" IDS_OPEN_WITH_CHOOSE "プログラムの選択..." + IDS_OPEN_WITH_RECOMMENDED "Recommended Programs:" + IDS_OPEN_WITH_OTHER "Other Programs:" IDS_SHELL_ABOUT_AUTHORS "制作者(&A)" IDS_SHELL_ABOUT_BACK "< 戻る(&B)" diff --git a/reactos/dll/win32/shell32/lang/ko-KR.rc b/reactos/dll/win32/shell32/lang/ko-KR.rc index c4e06a0102a..48fc5df06d1 100644 --- a/reactos/dll/win32/shell32/lang/ko-KR.rc +++ b/reactos/dll/win32/shell32/lang/ko-KR.rc @@ -372,10 +372,10 @@ BEGIN LTEXT "Choose the program you want to use to open this file:", -1, 44, 12, 211, 10 LTEXT "File: ", 14001, 44, 25, 188, 10 GROUPBOX "&Programs", -1, 7, 42, 249, 187 - LISTBOX 14002, 16 ,57, 230, 130, LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP, WS_EX_STATICEDGE + CONTROL "Programs", 14002, WC_TREEVIEW, WS_BORDER | WS_TABSTOP | TVS_SHOWSELALWAYS, 16 ,57, 230, 130 AUTOCHECKBOX "&Always use the selected program to open this kind of file", 14003, 20, 193, 225, 10 PUSHBUTTON "&Browse...", 14004, 198, 207, 50, 14 - PUSHBUTTON "OK", 14005, 150, 236, 50, 14 + DEFPUSHBUTTON "OK", 14005, 150, 236, 50, 14 PUSHBUTTON "Cancel", 14006, 206, 236, 50, 14 END @@ -713,8 +713,11 @@ BEGIN IDS_DRIVE_CDROM "CDROM" IDS_DRIVE_NETWORK "Network Disk" + /* Open With */ IDS_OPEN_WITH "Open With" IDS_OPEN_WITH_CHOOSE "Choose Program..." + IDS_OPEN_WITH_RECOMMENDED "Recommended Programs:" + IDS_OPEN_WITH_OTHER "Other Programs:" IDS_SHELL_ABOUT_AUTHORS "&Authors" IDS_SHELL_ABOUT_BACK "< &Back" diff --git a/reactos/dll/win32/shell32/lang/nl-NL.rc b/reactos/dll/win32/shell32/lang/nl-NL.rc index 019f4f23331..b4b5410880e 100644 --- a/reactos/dll/win32/shell32/lang/nl-NL.rc +++ b/reactos/dll/win32/shell32/lang/nl-NL.rc @@ -372,10 +372,10 @@ BEGIN LTEXT "Choose the program you want to use to open this file:", -1, 44, 12, 211, 10 LTEXT "File: ", 14001, 44, 25, 188, 10 GROUPBOX "&Programs", -1, 7, 42, 249, 187 - LISTBOX 14002, 16 ,57, 230, 130, LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP, WS_EX_STATICEDGE + CONTROL "Programs", 14002, WC_TREEVIEW, WS_BORDER | WS_TABSTOP | TVS_SHOWSELALWAYS, 16 ,57, 230, 130 AUTOCHECKBOX "&Always use the selected program to open this kind of file", 14003, 20, 193, 225, 10 PUSHBUTTON "&Browse...", 14004, 198, 207, 50, 14 - PUSHBUTTON "OK", 14005, 150, 236, 50, 14 + DEFPUSHBUTTON "OK", 14005, 150, 236, 50, 14 PUSHBUTTON "Cancel", 14006, 206, 236, 50, 14 END @@ -713,12 +713,15 @@ BEGIN IDS_DRIVE_CDROM "CDROM" IDS_DRIVE_NETWORK "Network Disk" + /* Open With */ IDS_OPEN_WITH "Open With" IDS_OPEN_WITH_CHOOSE "Choose Program..." + IDS_OPEN_WITH_RECOMMENDED "Recommended Programs:" + IDS_OPEN_WITH_OTHER "Other Programs:" IDS_SHELL_ABOUT_AUTHORS "&Authors" IDS_SHELL_ABOUT_BACK "< &Back" - FCIDM_SHVIEW_NEW "New" + FCIDM_SHVIEW_NEW "New" FCIDM_SHVIEW_NEWFOLDER "New &Folder" FCIDM_SHVIEW_NEWLINK "New &Link" IDS_FOLDER_OPTIONS "Folder Options" diff --git a/reactos/dll/win32/shell32/lang/no-NO.rc b/reactos/dll/win32/shell32/lang/no-NO.rc index 49d11c7f38a..898520b0737 100644 --- a/reactos/dll/win32/shell32/lang/no-NO.rc +++ b/reactos/dll/win32/shell32/lang/no-NO.rc @@ -373,10 +373,10 @@ BEGIN LTEXT "Velg programmet du vil bruke for å åpne denne filen:", -1, 44, 12, 211, 10 LTEXT "Fil: ", 14001, 44, 25, 188, 10 GROUPBOX "&Program", -1, 7, 42, 249, 187 - LISTBOX 14002, 16 ,57, 230, 130, LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP, WS_EX_STATICEDGE + CONTROL "Programs", 14002, WC_TREEVIEW, WS_BORDER | WS_TABSTOP | TVS_SHOWSELALWAYS, 16 ,57, 230, 130 AUTOCHECKBOX "&Alltid bruk valgte program for å åpne denne filtypen", 14003, 20, 193, 225, 10 PUSHBUTTON "&Utforsk...", 14004, 198, 207, 50, 14 - PUSHBUTTON "OK", 14005, 150, 236, 50, 14 + DEFPUSHBUTTON "OK", 14005, 150, 236, 50, 14 PUSHBUTTON "Avbryt", 14006, 206, 236, 50, 14 END @@ -716,8 +716,11 @@ BEGIN IDS_DRIVE_CDROM "CD stasjon" IDS_DRIVE_NETWORK "Nettverk disk" + /* Open With */ IDS_OPEN_WITH "Åpne med" IDS_OPEN_WITH_CHOOSE "Velg program..." + IDS_OPEN_WITH_RECOMMENDED "Recommended Programs:" + IDS_OPEN_WITH_OTHER "Other Programs:" IDS_SHELL_ABOUT_AUTHORS "&Forfatter" IDS_SHELL_ABOUT_BACK "< &Tilbake" diff --git a/reactos/dll/win32/shell32/lang/pl-PL.rc b/reactos/dll/win32/shell32/lang/pl-PL.rc index 0f6c0af1dbd..a7e72fdb819 100644 --- a/reactos/dll/win32/shell32/lang/pl-PL.rc +++ b/reactos/dll/win32/shell32/lang/pl-PL.rc @@ -380,10 +380,10 @@ BEGIN LTEXT "Wybierz program, którego chcesz użyć do otwarcia tego pliku:", -1, 44, 12, 211, 10 LTEXT "Plik: ", 14001, 44, 25, 188, 10 GROUPBOX "&Programy", -1, 7, 42, 249, 187 - LISTBOX 14002, 16 ,57, 230, 130, LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP, WS_EX_STATICEDGE + CONTROL "Programs", 14002, WC_TREEVIEW, WS_BORDER | WS_TABSTOP | TVS_SHOWSELALWAYS, 16 ,57, 230, 130 AUTOCHECKBOX "&Zawsze używaj danego programu do otwierania tego typu plików", 14003, 20, 193, 225, 10 - PUSHBUTTON "&Przeglądaj", 14004, 198, 207, 50, 14 - PUSHBUTTON "OK", 14005, 150, 236, 50, 14 + PUSHBUTTON "&Przeglądaj...", 14004, 198, 207, 50, 14 + DEFPUSHBUTTON "OK", 14005, 150, 236, 50, 14 PUSHBUTTON "Anuluj", 14006, 206, 236, 50, 14 END @@ -721,8 +721,11 @@ BEGIN IDS_DRIVE_CDROM "CDROM" IDS_DRIVE_NETWORK "Dysk sieciowy" + /* Open With */ IDS_OPEN_WITH "Otwórz za pomocą" IDS_OPEN_WITH_CHOOSE "Wybierz program..." + IDS_OPEN_WITH_RECOMMENDED "Zalecane programy:" + IDS_OPEN_WITH_OTHER "Inne programy:" IDS_SHELL_ABOUT_AUTHORS "&Autorzy" IDS_SHELL_ABOUT_BACK "< &Wstecz" diff --git a/reactos/dll/win32/shell32/lang/pt-BR.rc b/reactos/dll/win32/shell32/lang/pt-BR.rc index 0ea85c687dc..24f318bd39f 100644 --- a/reactos/dll/win32/shell32/lang/pt-BR.rc +++ b/reactos/dll/win32/shell32/lang/pt-BR.rc @@ -374,10 +374,10 @@ BEGIN LTEXT "Choose the program you want to use to open this file:", -1, 44, 12, 211, 10 LTEXT "File: ", 14001, 44, 25, 188, 10 GROUPBOX "&Programs", -1, 7, 42, 249, 187 - LISTBOX 14002, 16 ,57, 230, 130, LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP, WS_EX_STATICEDGE + CONTROL "Programs", 14002, WC_TREEVIEW, WS_BORDER | WS_TABSTOP | TVS_SHOWSELALWAYS, 16 ,57, 230, 130 AUTOCHECKBOX "&Always use the selected program to open this kind of file", 14003, 20, 193, 225, 10 PUSHBUTTON "&Browse...", 14004, 198, 207, 50, 14 - PUSHBUTTON "OK", 14005, 150, 236, 50, 14 + DEFPUSHBUTTON "OK", 14005, 150, 236, 50, 14 PUSHBUTTON "Cancel", 14006, 206, 236, 50, 14 END @@ -715,8 +715,11 @@ BEGIN IDS_DRIVE_CDROM "CDROM" IDS_DRIVE_NETWORK "Network Disk" + /* Open With */ IDS_OPEN_WITH "Open With" IDS_OPEN_WITH_CHOOSE "Choose Program..." + IDS_OPEN_WITH_RECOMMENDED "Recommended Programs:" + IDS_OPEN_WITH_OTHER "Other Programs:" IDS_SHELL_ABOUT_AUTHORS "&Authors" IDS_SHELL_ABOUT_BACK "< &Back" diff --git a/reactos/dll/win32/shell32/lang/pt-PT.rc b/reactos/dll/win32/shell32/lang/pt-PT.rc index 4973a2a151d..28432fbb563 100644 --- a/reactos/dll/win32/shell32/lang/pt-PT.rc +++ b/reactos/dll/win32/shell32/lang/pt-PT.rc @@ -375,10 +375,10 @@ BEGIN LTEXT "Escolha o programa que quer utilizar para abrir este ficheiro:", -1, 44, 12, 211, 10 LTEXT "Ficheiro: ", 14001, 44, 25, 188, 10 GROUPBOX "&Programas", -1, 7, 42, 249, 187 - LISTBOX 14002, 16 ,57, 230, 130, LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP, WS_EX_STATICEDGE + CONTROL "Programs", 14002, WC_TREEVIEW, WS_BORDER | WS_TABSTOP | TVS_SHOWSELALWAYS, 16 ,57, 230, 130 AUTOCHECKBOX "&Utilizar sempre o programa seleccionado para abrir este tipo de ficheiros", 14003, 20, 193, 225, 10 PUSHBUTTON "&Seleccione...", 14004, 198, 207, 50, 14 - PUSHBUTTON "OK", 14005, 150, 236, 50, 14 + DEFPUSHBUTTON "OK", 14005, 150, 236, 50, 14 PUSHBUTTON "Cancelar", 14006, 206, 236, 50, 14 END @@ -716,8 +716,11 @@ BEGIN IDS_DRIVE_CDROM "CDROM" IDS_DRIVE_NETWORK "Disco de Rede" + /* Open With */ IDS_OPEN_WITH "Abre com..." IDS_OPEN_WITH_CHOOSE "Escolha Programa..." + IDS_OPEN_WITH_RECOMMENDED "Recommended Programs:" + IDS_OPEN_WITH_OTHER "Other Programs:" IDS_SHELL_ABOUT_AUTHORS "&Autores" IDS_SHELL_ABOUT_BACK "< &Trás" diff --git a/reactos/dll/win32/shell32/lang/ro-RO.rc b/reactos/dll/win32/shell32/lang/ro-RO.rc index 3a0a04a2a3b..a717c558046 100644 --- a/reactos/dll/win32/shell32/lang/ro-RO.rc +++ b/reactos/dll/win32/shell32/lang/ro-RO.rc @@ -732,8 +732,11 @@ BEGIN IDS_DRIVE_CDROM "CD-ROM" IDS_DRIVE_NETWORK "Disc din rețea" + /* Open With */ IDS_OPEN_WITH "Deschide cu" IDS_OPEN_WITH_CHOOSE "Alegere program…" + IDS_OPEN_WITH_RECOMMENDED "Recommended Programs:" + IDS_OPEN_WITH_OTHER "Other Programs:" IDS_SHELL_ABOUT_AUTHORS "&Autori" IDS_SHELL_ABOUT_BACK "< Îna&poi" diff --git a/reactos/dll/win32/shell32/lang/ru-RU.rc b/reactos/dll/win32/shell32/lang/ru-RU.rc index 3b28c85788d..9a740dae8bf 100644 --- a/reactos/dll/win32/shell32/lang/ru-RU.rc +++ b/reactos/dll/win32/shell32/lang/ru-RU.rc @@ -371,10 +371,10 @@ BEGIN LTEXT "Выберите программу для открытия этого файла.", -1, 44, 12, 211, 10 LTEXT "Файл: ", 14001, 44, 25, 188, 10 GROUPBOX "Программы", -1, 7, 42, 249, 187 - LISTBOX 14002, 16 ,57, 230, 130, LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP, WS_EX_STATICEDGE + CONTROL "Programs", 14002, WC_TREEVIEW, WS_BORDER | WS_TABSTOP | TVS_SHOWSELALWAYS, 16 ,57, 230, 130 AUTOCHECKBOX "&Использовать ее для всех файлов такого типа", 14003, 20, 193, 225, 10 PUSHBUTTON "&Обзор...", 14004, 198, 207, 50, 14 - PUSHBUTTON "OK", 14005, 150, 236, 50, 14 + DEFPUSHBUTTON "OK", 14005, 150, 236, 50, 14 PUSHBUTTON "Отмена", 14006, 206, 236, 50, 14 END @@ -714,6 +714,8 @@ BEGIN IDS_OPEN_WITH "Открыть с помощью" IDS_OPEN_WITH_CHOOSE "Выбрать программу..." + IDS_OPEN_WITH_RECOMMENDED "Recommended Programs:" + IDS_OPEN_WITH_OTHER "Other Programs:" IDS_SHELL_ABOUT_AUTHORS "&Авторы" IDS_SHELL_ABOUT_BACK "< &Назад" diff --git a/reactos/dll/win32/shell32/lang/sk-SK.rc b/reactos/dll/win32/shell32/lang/sk-SK.rc index 57f95b46715..d296f5abe4c 100644 --- a/reactos/dll/win32/shell32/lang/sk-SK.rc +++ b/reactos/dll/win32/shell32/lang/sk-SK.rc @@ -378,10 +378,10 @@ BEGIN LTEXT "Vyberte program, v ktorom sa má otvoriť tento súbor:", -1, 44, 12, 211, 10 LTEXT "Súbor: ", 14001, 44, 25, 188, 10 GROUPBOX "&Programy", -1, 7, 42, 249, 187 - LISTBOX 14002, 16 ,57, 230, 130, LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP, WS_EX_STATICEDGE + CONTROL "Programs", 14002, WC_TREEVIEW, WS_BORDER | WS_TABSTOP | TVS_SHOWSELALWAYS, 16 ,57, 230, 130 AUTOCHECKBOX "N&a otvorenie týchto súborov vždy použiť vybratý program", 14003, 20, 193, 225, 10 PUSHBUTTON "&Prehľadávať...", 14004, 198, 207, 50, 14 - PUSHBUTTON "OK", 14005, 150, 236, 50, 14 + DEFPUSHBUTTON "OK", 14005, 150, 236, 50, 14 PUSHBUTTON "Zrušiť", 14006, 206, 236, 50, 14 END @@ -719,8 +719,11 @@ BEGIN IDS_DRIVE_CDROM "Jednotka CD" IDS_DRIVE_NETWORK "Sieťový disk" + /* Open With */ IDS_OPEN_WITH "Otvoriť v progra&me" IDS_OPEN_WITH_CHOOSE "&Vybrať program..." + IDS_OPEN_WITH_RECOMMENDED "Recommended Programs:" + IDS_OPEN_WITH_OTHER "Other Programs:" IDS_SHELL_ABOUT_AUTHORS "&Autori" IDS_SHELL_ABOUT_BACK "< &Späť" diff --git a/reactos/dll/win32/shell32/lang/sl-SI.rc b/reactos/dll/win32/shell32/lang/sl-SI.rc index ab8cff8344c..1388d1cb491 100644 --- a/reactos/dll/win32/shell32/lang/sl-SI.rc +++ b/reactos/dll/win32/shell32/lang/sl-SI.rc @@ -372,10 +372,10 @@ BEGIN LTEXT "Choose the program you want to use to open this file:", -1, 44, 12, 211, 10 LTEXT "File: ", 14001, 44, 25, 188, 10 GROUPBOX "&Programs", -1, 7, 42, 249, 187 - LISTBOX 14002, 16 ,57, 230, 130, LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP, WS_EX_STATICEDGE + CONTROL "Programs", 14002, WC_TREEVIEW, WS_BORDER | WS_TABSTOP | TVS_SHOWSELALWAYS, 16 ,57, 230, 130 AUTOCHECKBOX "&Always use the selected program to open this kind of file", 14003, 20, 193, 225, 10 PUSHBUTTON "&Browse...", 14004, 198, 207, 50, 14 - PUSHBUTTON "OK", 14005, 150, 236, 50, 14 + DEFPUSHBUTTON "OK", 14005, 150, 236, 50, 14 PUSHBUTTON "Cancel", 14006, 206, 236, 50, 14 END @@ -713,8 +713,11 @@ BEGIN IDS_DRIVE_CDROM "CDROM" IDS_DRIVE_NETWORK "Network Disk" + /* Open With */ IDS_OPEN_WITH "Open With" IDS_OPEN_WITH_CHOOSE "Select Program" + IDS_OPEN_WITH_RECOMMENDED "Recommended Programs:" + IDS_OPEN_WITH_OTHER "Other Programs:" IDS_SHELL_ABOUT_AUTHORS "&Authors" IDS_SHELL_ABOUT_BACK "< &Back" diff --git a/reactos/dll/win32/shell32/lang/sv-SE.rc b/reactos/dll/win32/shell32/lang/sv-SE.rc index 60d5dd8082e..4bcfbcd42b3 100644 --- a/reactos/dll/win32/shell32/lang/sv-SE.rc +++ b/reactos/dll/win32/shell32/lang/sv-SE.rc @@ -372,10 +372,10 @@ BEGIN LTEXT "Choose the program you want to use to open this file:", -1, 44, 12, 211, 10 LTEXT "File: ", 14001, 44, 25, 188, 10 GROUPBOX "&Programs", -1, 7, 42, 249, 187 - LISTBOX 14002, 16 ,57, 230, 130, LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP, WS_EX_STATICEDGE + CONTROL "Programs", 14002, WC_TREEVIEW, WS_BORDER | WS_TABSTOP | TVS_SHOWSELALWAYS, 16 ,57, 230, 130 AUTOCHECKBOX "&Always use the selected program to open this kind of file", 14003, 20, 193, 225, 10 PUSHBUTTON "&Browse...", 14004, 198, 207, 50, 14 - PUSHBUTTON "OK", 14005, 150, 236, 50, 14 + DEFPUSHBUTTON "OK", 14005, 150, 236, 50, 14 PUSHBUTTON "Cancel", 14006, 206, 236, 50, 14 END @@ -713,8 +713,11 @@ BEGIN IDS_DRIVE_CDROM "CDROM" IDS_DRIVE_NETWORK "Network Disk" + /* Open With */ IDS_OPEN_WITH "Open With" IDS_OPEN_WITH_CHOOSE "Select Program" + IDS_OPEN_WITH_RECOMMENDED "Recommended Programs:" + IDS_OPEN_WITH_OTHER "Other Programs:" IDS_SHELL_ABOUT_AUTHORS "&Authors" IDS_SHELL_ABOUT_BACK "< &Back" diff --git a/reactos/dll/win32/shell32/lang/tr-TR.rc b/reactos/dll/win32/shell32/lang/tr-TR.rc index 88010d34680..364a11458a9 100644 --- a/reactos/dll/win32/shell32/lang/tr-TR.rc +++ b/reactos/dll/win32/shell32/lang/tr-TR.rc @@ -372,10 +372,10 @@ BEGIN LTEXT "Choose the program you want to use to open this file:", -1, 44, 12, 211, 10 LTEXT "File: ", 14001, 44, 25, 188, 10 GROUPBOX "&Programs", -1, 7, 42, 249, 187 - LISTBOX 14002, 16 ,57, 230, 130, LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP, WS_EX_STATICEDGE + CONTROL "Programs", 14002, WC_TREEVIEW, WS_BORDER | WS_TABSTOP | TVS_SHOWSELALWAYS, 16 ,57, 230, 130 AUTOCHECKBOX "&Always use the selected program to open this kind of file", 14003, 20, 193, 225, 10 PUSHBUTTON "&Browse...", 14004, 198, 207, 50, 14 - PUSHBUTTON "OK", 14005, 150, 236, 50, 14 + DEFPUSHBUTTON "OK", 14005, 150, 236, 50, 14 PUSHBUTTON "Cancel", 14006, 206, 236, 50, 14 END @@ -713,8 +713,11 @@ BEGIN IDS_DRIVE_CDROM "CDROM" IDS_DRIVE_NETWORK "Network Disk" + /* Open With */ IDS_OPEN_WITH "Open With" IDS_OPEN_WITH_CHOOSE "Select Program" + IDS_OPEN_WITH_RECOMMENDED "Recommended Programs:" + IDS_OPEN_WITH_OTHER "Other Programs:" IDS_SHELL_ABOUT_AUTHORS "&Authors" IDS_SHELL_ABOUT_BACK "< &Back" diff --git a/reactos/dll/win32/shell32/lang/uk-UA.rc b/reactos/dll/win32/shell32/lang/uk-UA.rc index 4aa556cf41d..0727ba0a287 100644 --- a/reactos/dll/win32/shell32/lang/uk-UA.rc +++ b/reactos/dll/win32/shell32/lang/uk-UA.rc @@ -374,10 +374,10 @@ BEGIN LTEXT "Виберіть програму, за допомогою якої слід відкрити цей файл.", -1, 44, 12, 234, 10 LTEXT "Файл: ", 14001, 44, 25, 188, 10 GROUPBOX "&Програми", -1, 7, 42, 249, 187 - LISTBOX 14002, 16 ,57, 230, 130, LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP, WS_EX_STATICEDGE + CONTROL "Programs", 14002, WC_TREEVIEW, WS_BORDER | WS_TABSTOP | TVS_SHOWSELALWAYS, 16 ,57, 230, 130 AUTOCHECKBOX "Завжд&и використовувати цю програму для файлів цього типу", 14003, 20, 193, 225, 10 PUSHBUTTON "О&гляд...", 14004, 198, 207, 50, 14 - PUSHBUTTON "OK", 14005, 150, 236, 50, 14 + DEFPUSHBUTTON "OK", 14005, 150, 236, 50, 14 PUSHBUTTON "Скасувати", 14006, 206, 236, 50, 14 END @@ -726,8 +726,11 @@ BEGIN IDS_DRIVE_CDROM "CDROM" IDS_DRIVE_NETWORK "Мережний диск" + /* Open With */ IDS_OPEN_WITH "Відкрити за допомогою" IDS_OPEN_WITH_CHOOSE "Вибрати програму..." + IDS_OPEN_WITH_RECOMMENDED "Recommended Programs:" + IDS_OPEN_WITH_OTHER "Other Programs:" IDS_SHELL_ABOUT_AUTHORS "&Автори" IDS_SHELL_ABOUT_BACK "< &Назад" diff --git a/reactos/dll/win32/shell32/lang/zh-CN.rc b/reactos/dll/win32/shell32/lang/zh-CN.rc index 70e51fe7521..4ce1c69a845 100644 --- a/reactos/dll/win32/shell32/lang/zh-CN.rc +++ b/reactos/dll/win32/shell32/lang/zh-CN.rc @@ -361,7 +361,7 @@ BEGIN LTEXT "Choose the program you want to use to open this file:", -1, 44, 12, 211, 10 LTEXT "File: ", 14001, 44, 25, 188, 10 GROUPBOX "&Programs", -1, 7, 42, 249, 187 - LISTBOX 14002, 16 ,57, 230, 130, LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP, WS_EX_STATICEDGE + CONTROL "Programs", 14002, WC_TREEVIEW, WS_BORDER | WS_TABSTOP | TVS_SHOWSELALWAYS, 16 ,57, 230, 130 AUTOCHECKBOX "&Always use the selected program to open this kind of file", 14003, 20, 193, 225, 10 PUSHBUTTON "&Browse...", 14004, 198, 207, 50, 14 PUSHBUTTON "确定", 14005, 150, 236, 50, 14 @@ -702,8 +702,11 @@ BEGIN IDS_DRIVE_CDROM "CDROM" IDS_DRIVE_NETWORK "Network Disk" + /* Open With */ IDS_OPEN_WITH "打开方式" IDS_OPEN_WITH_CHOOSE "选择程序" + IDS_OPEN_WITH_RECOMMENDED "Recommended Programs:" + IDS_OPEN_WITH_OTHER "Other Programs:" IDS_SHELL_ABOUT_AUTHORS "&Authors" IDS_SHELL_ABOUT_BACK "< &Back" diff --git a/reactos/dll/win32/shell32/lang/zh-TW.rc b/reactos/dll/win32/shell32/lang/zh-TW.rc index 436bf140450..98a30a774dd 100644 --- a/reactos/dll/win32/shell32/lang/zh-TW.rc +++ b/reactos/dll/win32/shell32/lang/zh-TW.rc @@ -372,10 +372,10 @@ BEGIN LTEXT "Choose the program you want to use to open this file:", -1, 44, 12, 211, 10 LTEXT "File: ", 14001, 44, 25, 188, 10 GROUPBOX "&Programs", -1, 7, 42, 249, 187 - LISTBOX 14002, 16 ,57, 230, 130, LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP, WS_EX_STATICEDGE + CONTROL "Programs", 14002, WC_TREEVIEW, WS_BORDER | WS_TABSTOP | TVS_SHOWSELALWAYS, 16 ,57, 230, 130 AUTOCHECKBOX "&Always use the selected program to open this kind of file", 14003, 20, 193, 225, 10 PUSHBUTTON "&Browse...", 14004, 198, 207, 50, 14 - PUSHBUTTON "OK", 14005, 150, 236, 50, 14 + DEFPUSHBUTTON "OK", 14005, 150, 236, 50, 14 PUSHBUTTON "Cancel", 14006, 206, 236, 50, 14 END @@ -713,8 +713,11 @@ BEGIN IDS_DRIVE_CDROM "CDROM" IDS_DRIVE_NETWORK "Network Disk" + /* Open With */ IDS_OPEN_WITH "Open With" IDS_OPEN_WITH_CHOOSE "Select Program" + IDS_OPEN_WITH_RECOMMENDED "Recommended Programs:" + IDS_OPEN_WITH_OTHER "Other Programs:" IDS_SHELL_ABOUT_AUTHORS "&Authors" IDS_SHELL_ABOUT_BACK "< &Back" diff --git a/reactos/dll/win32/shell32/openwithmenu.cpp b/reactos/dll/win32/shell32/openwithmenu.cpp index 98e4bc6f433..95591408025 100644 --- a/reactos/dll/win32/shell32/openwithmenu.cpp +++ b/reactos/dll/win32/shell32/openwithmenu.cpp @@ -21,92 +21,1059 @@ #include -WINE_DEFAULT_DEBUG_CHANNEL (shell); +WINE_DEFAULT_DEBUG_CHANNEL(shell); -/// -/// [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\policies\system] -/// "NoInternetOpenWith"=dword:00000001 -/// +// +// [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\policies\system] +// "NoInternetOpenWith"=dword:00000001 +// -// TODO -// implement duplicate checks in list box -// implement duplicate checks for MRU! -// implement owner drawn menu - -typedef struct +class COpenWithList { - BOOL bMenu; - HMENU hMenu; - HWND hDlgCtrl; - BOOL bNoOpen; - UINT idCmd; -} OPEN_WITH_CONTEXT, *POPEN_WITH_CONTEXT; + public: + struct SApp + { + WCHAR wszFilename[MAX_PATH]; + WCHAR wszCmd[MAX_PATH]; + //WCHAR wszManufacturer[256]; + WCHAR wszName[256]; + BOOL bHidden; + BOOL bRecommended; + BOOL bMRUList; + HICON hIcon; + }; -#define MANUFACTURER_NAME_SIZE 100 + COpenWithList(); + ~COpenWithList(); -typedef struct + BOOL Load(); + SApp *Add(LPCWSTR pwszPath); + static BOOL SaveApp(SApp *pApp); + SApp *Find(LPCWSTR pwszFilename); + static LPCWSTR GetName(SApp *pApp); + static HICON GetIcon(SApp *pApp); + static BOOL Execute(SApp *pApp, LPCWSTR pwszFilePath); + static BOOL IsHidden(SApp *pApp); + BOOL LoadRecommended(LPCWSTR pwszFilePath); + BOOL SetDefaultHandler(SApp *pApp, LPCWSTR pwszFilename); + + inline SApp *GetList() { return m_pApp; } + inline UINT GetCount() { return m_cApp; } + inline UINT GetRecommendedCount() { return m_cRecommended; } + + private: + typedef struct _LANGANDCODEPAGE + { + WORD lang; + WORD code; + } LANGANDCODEPAGE, *LPLANGANDCODEPAGE; + + SApp *m_pApp; + UINT m_cApp, m_cRecommended; + BOOL m_bNoOpen; + + SApp *AddInternal(LPCWSTR pwszFilename); + static BOOL LoadInfo(SApp *pApp); + static VOID GetPathFromCmd(LPWSTR pwszAppPath, LPCWSTR pwszCmd); + BOOL LoadProgIdList(HKEY hKey, LPCWSTR pwszExt); + static HANDLE OpenMRUList(HKEY hKey); + BOOL LoadMRUList(HKEY hKey); + BOOL LoadAppList(HKEY hKey); + VOID LoadFromProgIdKey(HKEY hKey, LPCWSTR pwszExt); + VOID LoadRecommendedFromHKCR(LPCWSTR pwszExt); + VOID LoadRecommendedFromHKCU(LPCWSTR pwszExt); + static BOOL AddAppToMRUList(SApp *pApp, LPCWSTR pwszFilename); + + inline VOID SetRecommended(SApp *pApp) + { + if (!pApp->bRecommended) + ++m_cRecommended; + pApp->bRecommended = TRUE; + } +}; + +COpenWithList::COpenWithList(): + m_pApp(NULL), m_cApp(0), m_cRecommended(0), m_bNoOpen(FALSE) {} + +COpenWithList::~COpenWithList() { - HICON hIcon; - WCHAR wszAppPath[MAX_PATH]; - WCHAR wszManufacturer[MANUFACTURER_NAME_SIZE]; -} OPEN_ITEM_CONTEXT, *POPEN_ITEM_CONTEXT; + for (UINT i = 0; i < m_cApp; ++i) + if (m_pApp[i].hIcon) + DestroyIcon(m_pApp[i].hIcon); -typedef struct _LANGANDCODEPAGE_ + HeapFree(GetProcessHeap(), 0, m_pApp); +} + +BOOL COpenWithList::Load() { - WORD lang; - WORD code; -} LANGANDCODEPAGE, *LPLANGANDCODEPAGE; + HKEY hKey; + WCHAR wszName[256], wszBuf[100];; + DWORD i = 0, cchName, dwSize; + SApp *pApp; -static HANDLE OpenMRUList(HKEY hKey); + if (RegOpenKeyEx(HKEY_CLASSES_ROOT, L"Applications", 0, KEY_READ, &hKey) != ERROR_SUCCESS) + { + ERR("RegOpenKeyEx HKCR\\Applications failed!\n"); + return FALSE; + } -static VOID LoadItemFromHKCU(POPEN_WITH_CONTEXT pContext, LPCWSTR pwszExt); -static VOID LoadItemFromHKCR(POPEN_WITH_CONTEXT pContext, LPCWSTR pwszExt); -static VOID InsertOpenWithItem(POPEN_WITH_CONTEXT pContext, LPCWSTR pwszAppName); -static VOID FreeMenuItemContext(HMENU hMenu); + while (TRUE) + { + cchName = _countof(wszName); + if (RegEnumKeyEx(hKey, i++, wszName, &cchName, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) + break; + + pApp = AddInternal(wszName); + + if (pApp) + { + StringCbPrintfW(wszBuf, sizeof(wszBuf), L"%s\\shell\\open\\command", wszName); + dwSize = sizeof(pApp->wszCmd); + if (RegGetValueW(hKey, wszBuf, L"", RRF_RT_REG_SZ, NULL, pApp->wszCmd, &dwSize) != ERROR_SUCCESS) + { + ERR("Failed to add app %ls\n", wszName); + pApp->bHidden = TRUE; + } + else + TRACE("App added %ls\n", pApp->wszCmd); + } + else + ERR("AddInternal failed\n"); + } + + RegCloseKey(hKey); + return TRUE; +} + +COpenWithList::SApp *COpenWithList::Add(LPCWSTR pwszPath) +{ + SApp *pApp = AddInternal(PathFindFileNameW(pwszPath)); + + if (pApp) + { + StringCbPrintfW(pApp->wszCmd, sizeof(pApp->wszCmd), L"\"%s\" %%1", pwszPath); + SaveApp(pApp); + } + + return pApp; +} + +BOOL COpenWithList::SaveApp(SApp *pApp) +{ + WCHAR wszBuf[256]; + HKEY hKey; + + StringCbPrintfW(wszBuf, sizeof(wszBuf), L"Applications\\%s\\shell\\open\\command", pApp->wszFilename); + if (RegCreateKeyEx(HKEY_CLASSES_ROOT, wszBuf, 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL) != ERROR_SUCCESS) + { + ERR("RegOpenKeyEx failed\n"); + return FALSE; + } + + if (RegSetValueEx(hKey, L"", 0, REG_SZ, (PBYTE)pApp->wszCmd, (wcslen(pApp->wszCmd)+1)*sizeof(WCHAR)) != ERROR_SUCCESS) + ERR("Cannot add app to registry\n"); + + RegCloseKey(hKey); + return TRUE; +} + +COpenWithList::SApp *COpenWithList::Find(LPCWSTR pwszFilename) +{ + for (UINT i = 0; i < m_cApp; ++i) + if (wcsicmp(m_pApp[i].wszFilename, pwszFilename) == 0) + return &m_pApp[i]; + return NULL; +} + +LPCWSTR COpenWithList::GetName(SApp *pApp) +{ + if (!pApp->wszName[0]) + { + if (!LoadInfo(pApp)) + { + WARN("Failed to load %ls info\n", pApp->wszFilename); + StringCbCopyW(pApp->wszName, sizeof(pApp->wszName), pApp->wszFilename); + } + } + + TRACE("%ls name: %ls\n", pApp->wszFilename, pApp->wszName); + return pApp->wszName; +} + +HICON COpenWithList::GetIcon(SApp *pApp) +{ + if (!pApp->hIcon) + { + WCHAR wszPath[MAX_PATH]; + + GetPathFromCmd(wszPath, pApp->wszCmd); + pApp->hIcon = ExtractIconW(shell32_hInstance, wszPath, 0); + } + + TRACE("%ls icon: %p\n", pApp->wszFilename, pApp->hIcon); + + return pApp->hIcon; +} + +BOOL COpenWithList::Execute(COpenWithList::SApp *pApp, LPCWSTR pwszFilePath) +{ + STARTUPINFOW si; + PROCESS_INFORMATION pi; + WCHAR wszBuf[MAX_PATH * 2 + 8], *pszEnd = wszBuf; + size_t cchRemaining = _countof(wszBuf); + + /* setup path with argument */ + ZeroMemory(&si, sizeof(STARTUPINFOW)); + si.cb = sizeof(STARTUPINFOW); + + /* Build the command line */ + for (UINT i = 0; pApp->wszCmd[i] && cchRemaining > 1; ++i) + { + if (pApp->wszCmd[i] != '%') + { + *(pszEnd++) = pApp->wszCmd[i]; + --cchRemaining; + } + else if (pApp->wszCmd[++i] == '1') + StringCchCopyExW(pszEnd, cchRemaining, pwszFilePath, &pszEnd, &cchRemaining, 0); + } + /* NULL-terminate the command string */ + if (cchRemaining > 0) + *pszEnd = L'\0'; + + /* Start the application now */ + TRACE("Starting process %ls\n", wszBuf); + if (!CreateProcessW(NULL, wszBuf, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) + { + ERR("CreateProcessW %ls failed\n", wszBuf); + return FALSE; + } + + /* Add app to registry if it wasnt there before */ + SaveApp(pApp); + if (!pApp->bMRUList) + AddAppToMRUList(pApp, pwszFilePath); + + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + return TRUE; +} + +BOOL COpenWithList::IsHidden(SApp *pApp) +{ + WCHAR wszBuf[100]; + DWORD dwSize = 0; + + if (pApp->bHidden) + return pApp->bHidden; + + if (FAILED(StringCbPrintfW(wszBuf, sizeof(wszBuf), L"Applications\\%s", pApp->wszFilename))) + { + ERR("insufficient buffer\n"); + return FALSE; + } + + if (RegGetValueW(HKEY_CLASSES_ROOT, wszBuf, L"NoOpenWith", RRF_RT_REG_SZ, NULL, NULL, &dwSize) != ERROR_SUCCESS) + return FALSE; + + pApp->bHidden = TRUE; + return TRUE; +} + +COpenWithList::SApp *COpenWithList::AddInternal(LPCWSTR pwszFilename) +{ + /* Check for duplicate */ + SApp *pApp = Find(pwszFilename); + if (pApp) + return pApp; + + /* Create new item */ + if (!m_pApp) + m_pApp = (SApp*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(m_pApp[0])); + else + m_pApp = (SApp*)HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, m_pApp, (m_cApp + 1)*sizeof(m_pApp[0])); + if (!m_pApp) + { + ERR("Allocation failed\n"); + return NULL; + } + + pApp = &m_pApp[m_cApp++]; + wcscpy(pApp->wszFilename, pwszFilename); + return pApp; +} + +BOOL COpenWithList::LoadInfo(COpenWithList::SApp *pApp) +{ + UINT cbSize, cchLen; + LPVOID pBuf; + WORD wLang = 0, wCode = 0; + LPLANGANDCODEPAGE lpLangCode; + WCHAR wszBuf[100]; + WCHAR *pResult; + WCHAR wszPath[MAX_PATH]; + + GetPathFromCmd(wszPath, pApp->wszCmd); + TRACE("LoadInfo %ls\n", wszPath); + + /* query version info size */ + cbSize = GetFileVersionInfoSizeW(wszPath, NULL); + if (!cbSize) + { + ERR("GetFileVersionInfoSizeW %ls failed: %lu\n", wszPath, GetLastError()); + return FALSE; + } + + /* allocate buffer */ + pBuf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbSize + 200); + if (!pBuf) + { + ERR("HeapAlloc failed\n"); + return FALSE; + } + + /* query version info */ + if (!GetFileVersionInfoW(wszPath, 0, cbSize, pBuf)) + { + ERR("GetFileVersionInfoW %ls failed: %lu\n", wszPath, GetLastError()); + HeapFree(GetProcessHeap(), 0, pBuf); + return FALSE; + } + + /* query lang code */ + if (VerQueryValueW(pBuf, L"VarFileInfo\\Translation", (LPVOID*)&lpLangCode, &cbSize)) + { + /* FIXME: find language from current locale / if not available, + * default to english + * for now default to first available language + */ + wLang = lpLangCode->lang; + wCode = lpLangCode->code; + } + + /* Query name */ + swprintf(wszBuf, L"\\StringFileInfo\\%04x%04x\\FileDescription", wLang, wCode); + if (VerQueryValueW(pBuf, wszBuf, (LPVOID *)&pResult, &cchLen)) + StringCchCopyNW(pApp->wszName, _countof(pApp->wszName), pResult, cchLen); + else + ERR("Cannot get app name\n"); + + /* Query manufacturer */ + /*swprintf(wszBuf, L"\\StringFileInfo\\%04x%04x\\CompanyName", wLang, wCode); + + if (VerQueryValueW(pBuf, wszBuf, (LPVOID *)&pResult, &cchLen)) + StringCchCopyNW(pApp->wszManufacturer, _countof(pApp->wszManufacturer), pResult, cchLen);*/ + HeapFree(GetProcessHeap(), 0, pBuf); + return TRUE; +} + +VOID COpenWithList::GetPathFromCmd(LPWSTR pwszAppPath, LPCWSTR pwszCmd) +{ + WCHAR wszBuf[MAX_PATH], *pwszDest = wszBuf; + + /* Remove arguments */ + if (pwszCmd[0] == '"') + { + for(LPCWSTR pwszSrc = pwszCmd + 1; *pwszSrc && *pwszSrc != '"'; ++pwszSrc) + *(pwszDest++) = *pwszSrc; + } + else + { + for(LPCWSTR pwszSrc = pwszCmd; *pwszSrc && *pwszSrc != ' '; ++pwszSrc) + *(pwszDest++) = *pwszSrc; + } + + *pwszDest = 0; + + /* Expand evn vers and optionally search for path */ + ExpandEnvironmentStrings(wszBuf, pwszAppPath, MAX_PATH); + if (!PathFileExists(pwszAppPath)) + SearchPath(NULL, pwszAppPath, NULL, MAX_PATH, pwszAppPath, NULL); +} + +BOOL COpenWithList::LoadRecommended(LPCWSTR pwszFilePath) +{ + LPCWSTR pwszExt; + + pwszExt = PathFindExtensionW(pwszFilePath); + if (!pwszExt[0]) + return FALSE; + + /* load programs directly associated from HKCU */ + LoadRecommendedFromHKCU(pwszExt); + + /* load programs associated from HKCR\Extension */ + LoadRecommendedFromHKCR(pwszExt); + + return TRUE; +} + +BOOL COpenWithList::LoadProgIdList(HKEY hKey, LPCWSTR pwszExt) +{ + HKEY hSubkey, hSubkey2; + WCHAR wszProgId[256]; + DWORD i = 0, cchProgId; + + if (RegOpenKeyExW(hKey, L"OpenWithProgIDs", 0, KEY_READ, &hSubkey) != ERROR_SUCCESS) + return FALSE; + + while (TRUE) + { + /* Enumerate values - value name is ProgId */ + cchProgId = _countof(wszProgId); + if (RegEnumValue(hSubkey, i++, wszProgId, &cchProgId, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) + break; + + /* If ProgId exists load it */ + if (RegOpenKeyExW(HKEY_CLASSES_ROOT, wszProgId, 0, KEY_READ, &hSubkey2) == ERROR_SUCCESS) + { + LoadFromProgIdKey(hSubkey2, pwszExt); + RegCloseKey(hSubkey2); + } + } + + RegCloseKey(hSubkey); + return TRUE; +} + +HANDLE COpenWithList::OpenMRUList(HKEY hKey) +{ + CREATEMRULISTW Info; + + /* Initialize mru list info */ + Info.cbSize = sizeof(Info); + Info.nMaxItems = 32; + Info.dwFlags = MRU_STRING; + Info.hKey = hKey; + Info.lpszSubKey = L"OpenWithList"; + Info.lpfnCompare = NULL; + + return CreateMRUListW(&Info); +} + +BOOL COpenWithList::LoadMRUList(HKEY hKey) +{ + HANDLE hList; + int nItem, nCount, nResult; + WCHAR wszAppFilename[MAX_PATH]; + + /* Open MRU list */ + hList = OpenMRUList(hKey); + if (!hList) + { + TRACE("OpenMRUList failed\n"); + return FALSE; + } + + /* Get list count */ + nCount = EnumMRUListW(hList, -1, NULL, 0); + + for(nItem = 0; nItem < nCount; nItem++) + { + nResult = EnumMRUListW(hList, nItem, wszAppFilename, _countof(wszAppFilename)); + if (nResult <= 0) + continue; + + /* Insert item */ + SApp *pApp = Find(wszAppFilename); + + TRACE("Recommended app %ls: %p\n", wszAppFilename, pApp); + if (pApp) + { + pApp->bMRUList = TRUE; + SetRecommended(pApp); + } + } + + /* Free the MRU list */ + FreeMRUList(hList); + return TRUE; +} + +BOOL COpenWithList::LoadAppList(HKEY hKey) +{ + WCHAR wszAppFilename[MAX_PATH]; + HKEY hSubkey; + DWORD i = 0, cchAppFilename; + + if (RegOpenKeyExW(hKey, L"OpenWithList", 0, KEY_READ, &hSubkey) != ERROR_SUCCESS) + return FALSE; + + while (TRUE) + { + /* Enum registry keys - each of them is app name */ + cchAppFilename = _countof(wszAppFilename); + if (RegEnumKeyExW(hSubkey, i++, wszAppFilename, &cchAppFilename, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) + break; + + /* Set application as recommended */ + SApp *pApp = Find(wszAppFilename); + + TRACE("Recommended app %ls: %p\n", wszAppFilename, pApp); + if (pApp) + SetRecommended(pApp); + } + + RegCloseKey(hSubkey); + return TRUE; +} + +VOID COpenWithList::LoadFromProgIdKey(HKEY hKey, LPCWSTR pwszExt) +{ + WCHAR wszCmd[MAX_PATH], wszPath[MAX_PATH]; + DWORD dwSize = 0; + + /* Check if NoOpen value exists */ + if (RegGetValueW(hKey, NULL, L"NoOpen", RRF_RT_REG_SZ, NULL, NULL, &dwSize) == ERROR_SUCCESS) + { + /* Display warning dialog */ + m_bNoOpen = TRUE; + } + + /* Check if there is a directly available execute key */ + dwSize = sizeof(wszCmd); + if (RegGetValueW(hKey, L"shell\\open\\command", NULL, RRF_RT_REG_SZ, NULL, (PVOID)wszCmd, &dwSize) == ERROR_SUCCESS) + { + /* Erase extra arguments */ + GetPathFromCmd(wszPath, wszCmd); + + /* Add application */ + SApp *pApp = AddInternal(PathFindFileNameW(wszPath)); + TRACE("Add app %ls: %p\n", wszPath, pApp); + + if (pApp) + { + StringCbCopyW(pApp->wszCmd, sizeof(pApp->wszCmd), wszCmd); + SetRecommended(pApp); + if (!pApp->bMRUList) + AddAppToMRUList(pApp, pwszExt); + } + } +} + +VOID COpenWithList::LoadRecommendedFromHKCR(LPCWSTR pwszExt) +{ + HKEY hKey, hSubkey; + WCHAR wszBuf[MAX_PATH], wszBuf2[MAX_PATH]; + DWORD dwSize; + + /* Check if extension exists */ + if (RegOpenKeyExW(HKEY_CLASSES_ROOT, pwszExt, 0, KEY_READ, &hKey) != ERROR_SUCCESS) + { + /* Load items from SystemFileAssociations\Ext key */ + StringCbPrintfW(wszBuf, sizeof(wszBuf), L"SystemFileAssociations\\%s", pwszExt); + if (RegOpenKeyExW(HKEY_CLASSES_ROOT, wszBuf, 0, KEY_READ, &hKey) != ERROR_SUCCESS) + return; + } + + /* Load programs referenced from HKCR\ProgId */ + dwSize = sizeof(wszBuf); + if (RegGetValueW(hKey, NULL, L"", RRF_RT_REG_SZ, NULL, wszBuf, &dwSize) == ERROR_SUCCESS && + RegOpenKeyExW(HKEY_CLASSES_ROOT, wszBuf, 0, KEY_READ, &hSubkey) == ERROR_SUCCESS) + { + LoadFromProgIdKey(hSubkey, pwszExt); + RegCloseKey(hSubkey); + } + else + LoadFromProgIdKey(hKey, pwszExt); + + /* Load items from HKCR\Ext\OpenWithList */ + LoadAppList(hKey); + + /* Load items from HKCR\Ext\OpenWithProgIDs */ + if (RegOpenKeyExW(hKey, L"OpenWithProgIDs", 0, KEY_READ, &hSubkey) == ERROR_SUCCESS) + { + LoadProgIdList(hSubkey, pwszExt); + RegCloseKey(hSubkey); + } + + /* Load additional items from referenced PerceivedType */ + dwSize = sizeof(wszBuf); + if (RegGetValueW(hKey, NULL, L"PerceivedType", RRF_RT_REG_SZ, NULL, wszBuf, &dwSize) == ERROR_SUCCESS) + { + RegCloseKey(hKey); + + StringCbPrintfW(wszBuf2, sizeof(wszBuf2), L"SystemFileAssociations\\%s", wszBuf); + if (RegOpenKeyExW(HKEY_CLASSES_ROOT, wszBuf2, 0, KEY_READ | KEY_WRITE, &hSubkey) == ERROR_SUCCESS) + { + /* Load from OpenWithList key */ + LoadAppList(hSubkey); + RegCloseKey(hSubkey); + } + } + + /* Close the key */ + RegCloseKey(hKey); +} + +VOID COpenWithList::LoadRecommendedFromHKCU(LPCWSTR pwszExt) +{ + WCHAR wszBuf[MAX_PATH]; + HKEY hKey; + + StringCbPrintfW(wszBuf, sizeof(wszBuf), + L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\%s", + pwszExt); + if (RegOpenKeyExW(HKEY_CURRENT_USER, wszBuf, 0, KEY_READ, &hKey) == ERROR_SUCCESS) + { + /* Load MRU and ProgId lists */ + LoadMRUList(hKey); + LoadProgIdList(hKey, pwszExt); + + /* Handle "Aplication" value */ + DWORD cbBuf = sizeof(wszBuf); + if (RegGetValueW(hKey, NULL, L"Application", RRF_RT_REG_SZ, NULL, wszBuf, &cbBuf) == ERROR_SUCCESS) + { + SApp *pApp = Find(wszBuf); + if (pApp) + SetRecommended(pApp); + } + + /* Close the key */ + RegCloseKey(hKey); + } +} + +BOOL COpenWithList::AddAppToMRUList(SApp *pApp, LPCWSTR pwszFilename) +{ + WCHAR wszBuf[100]; + LPCWSTR pwszExt; + HKEY hKey; + HANDLE hList; + + /* Get file extension */ + pwszExt = PathFindExtensionW(pwszFilename); + if (!pwszExt[0]) + return FALSE; + + /* Build registry key */ + if (FAILED(StringCbPrintfW(wszBuf, sizeof(wszBuf), + L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\%s", + pwszExt))) + { + ERR("insufficient buffer\n"); + return FALSE; + } + + /* Open base key for this file extension */ + if (RegCreateKeyExW(HKEY_CURRENT_USER, wszBuf, 0, NULL, 0, KEY_WRITE | KEY_READ, NULL, &hKey, NULL) != ERROR_SUCCESS) + return FALSE; + + /* Open MRU list */ + hList = OpenMRUList(hKey); + if (hList) + { + /* Insert the entry */ + AddMRUStringW(hList, pApp->wszFilename); + + /* Close MRU list */ + FreeMRUList(hList); + } + + RegCloseKey(hKey); + return TRUE; +} + +BOOL COpenWithList::SetDefaultHandler(SApp *pApp, LPCWSTR pwszFilename) +{ + HKEY hKey, hSrcKey, hDestKey; + DWORD dwDisposition; + WCHAR wszBuf[256]; + + TRACE("SetDefaultHandler %ls %ls", pApp->wszFilename, pwszFilename); + + /* Extract file extension */ + LPCWSTR pwszExt = PathFindExtensionW(pwszFilename); + if (!pwszExt[0] || !pwszExt[1]) + return FALSE; + + /* Create file extension key */ + if (RegCreateKeyExW(HKEY_CLASSES_ROOT, pwszExt, 0, NULL, 0, KEY_READ|KEY_WRITE, NULL, &hKey, &dwDisposition) != ERROR_SUCCESS) + { + ERR("Cannot open ext key"); + return FALSE; + } + + if (dwDisposition == REG_CREATED_NEW_KEY) + { + /* A new entry was created create the prog key id */ + StringCbPrintfW(wszBuf, sizeof(wszBuf), L"%s_auto_file", pwszExt + 1); + if (RegSetValueExW(hKey, L"", 0, REG_SZ, (const BYTE*)wszBuf, (wcslen(wszBuf) + 1) * sizeof(WCHAR)) != ERROR_SUCCESS) + { + RegCloseKey(hKey); + ERR("RegSetValueExW failed\n"); + return FALSE; + } + } + else + { + /* Entry already exists fetch prog key id */ + DWORD dwSize = sizeof(wszBuf); + if (RegGetValueW(hKey, NULL, L"", RRF_RT_REG_SZ, NULL, wszBuf, &dwSize) != ERROR_SUCCESS) + { + ERR("RegGetValueW failed: %lu\n", GetLastError()); + RegCloseKey(hKey); + return FALSE; + } + } + + /* Close file extension key */ + RegCloseKey(hKey); + + /* Create prog id key */ + if (RegCreateKeyExW(HKEY_CLASSES_ROOT, wszBuf, 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL) != ERROR_SUCCESS) + { + ERR("RegCreateKeyExW failed\n"); + return FALSE; + } + + /* Check if there already verbs existing for that app */ + StringCbPrintfW(wszBuf, sizeof(wszBuf), L"Applications\\%s\\shell", pApp->wszFilename); + if (RegOpenKeyExW(HKEY_CLASSES_ROOT, wszBuf, 0, KEY_READ, &hSrcKey) != ERROR_SUCCESS) + { + ERR("RegOpenKeyExW %ls failed\n", wszBuf); + RegCloseKey(hKey); + return FALSE; + } + + /* Open destination key */ + if (RegCreateKeyExW(hKey, L"shell", 0, NULL, 0, KEY_WRITE, NULL, &hDestKey, NULL) != ERROR_SUCCESS) + { + ERR("RegCreateKeyExW failed\n"); + RegCloseKey(hSrcKey); + RegCloseKey(hKey); + return FALSE; + } + + /* Copy static verbs from Classes\Applications key */ + LONG Result = RegCopyTreeW(hSrcKey, NULL, hDestKey); + RegCloseKey(hDestKey); + RegCloseKey(hSrcKey); + RegCloseKey(hKey); + + if (Result != ERROR_SUCCESS) + { + ERR("RegCopyTreeW failed\n"); + return FALSE; + } + + return TRUE; +} + +class COpenWithDialog +{ + public: + COpenWithDialog(const OPENASINFO *pInfo, COpenWithList *pAppList); + ~COpenWithDialog(); + static INT_PTR CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); + + private: + VOID Init(HWND hwnd); + VOID AddApp(COpenWithList::SApp *pApp, BOOL bSelected); + VOID Browse(); + VOID Accept(); + COpenWithList::SApp *GetCurrentApp(); + + const OPENASINFO *m_pInfo; + COpenWithList *m_pAppList; + BOOL m_bListAllocated; + HWND m_hDialog, m_hTreeView; + HTREEITEM m_hRecommend; + HTREEITEM m_hOther; + HIMAGELIST m_hImgList; +}; + +COpenWithDialog::COpenWithDialog(const OPENASINFO *pInfo, COpenWithList *pAppList = NULL): + m_pInfo(pInfo), m_pAppList(pAppList), m_hImgList(NULL) +{ + if (!m_pAppList) + { + m_pAppList = new COpenWithList; + m_bListAllocated = TRUE; + } + else + m_bListAllocated = FALSE; +} + +COpenWithDialog::~COpenWithDialog() +{ + if (m_bListAllocated && m_pAppList) + delete m_pAppList; + if (m_hImgList) + ImageList_Destroy(m_hImgList); +} + +VOID COpenWithDialog::AddApp(COpenWithList::SApp *pApp, BOOL bSelected) +{ + LPCWSTR pwszName = m_pAppList->GetName(pApp); + HICON hIcon = m_pAppList->GetIcon(pApp); + + TRACE("AddApp Cmd %ls Name %ls\n", pApp->wszCmd, pwszName); + + /* Add item to the list */ + TVINSERTSTRUCT tvins; + + if (pApp->bRecommended) + tvins.hParent = tvins.hInsertAfter = m_hRecommend; + else + tvins.hParent = tvins.hInsertAfter = m_hOther; + + tvins.item.mask = TVIF_TEXT|TVIF_PARAM; + tvins.item.pszText = (LPWSTR)pwszName; + tvins.item.lParam = (LPARAM)pApp; + + if (hIcon) + { + tvins.item.mask |= TVIF_IMAGE | TVIF_SELECTEDIMAGE; + tvins.item.iImage = tvins.item.iSelectedImage = ImageList_AddIcon(m_hImgList, hIcon); + } + + HTREEITEM hItem = TreeView_InsertItem(m_hTreeView, &tvins); + + if (bSelected) + TreeView_SelectItem(m_hTreeView, hItem); +} + +VOID COpenWithDialog::Browse() +{ + WCHAR wszTitle[64]; + WCHAR wszFilter[256]; + WCHAR wszPath[MAX_PATH]; + OPENFILENAMEW ofn; + + /* Initialize OPENFILENAMEW structure */ + ZeroMemory(&ofn, sizeof(OPENFILENAMEW)); + ofn.lStructSize = sizeof(OPENFILENAMEW); + ofn.hInstance = shell32_hInstance; + ofn.hwndOwner = m_hDialog; + ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; + ofn.nMaxFile = (sizeof(wszPath) / sizeof(WCHAR)); + ofn.lpstrFile = wszPath; + + /* Init title */ + if (LoadStringW(shell32_hInstance, IDS_OPEN_WITH, wszTitle, sizeof(wszTitle) / sizeof(WCHAR))) + { + ofn.lpstrTitle = wszTitle; + ofn.nMaxFileTitle = wcslen(wszTitle); + } + + /* Init the filter string */ + if (LoadStringW(shell32_hInstance, IDS_OPEN_WITH_FILTER, wszFilter, sizeof(wszFilter) / sizeof(WCHAR))) + ofn.lpstrFilter = wszFilter; + ZeroMemory(wszPath, sizeof(wszPath)); + + /* Create OpenFile dialog */ + if (!GetOpenFileNameW(&ofn)) + return; + + /* Setup context for insert proc */ + COpenWithList::SApp *pApp = m_pAppList->Add(wszPath); + AddApp(pApp, TRUE); +} + +COpenWithList::SApp *COpenWithDialog::GetCurrentApp() +{ + TVITEM tvi; + tvi.hItem = TreeView_GetSelection(m_hTreeView); + if (!tvi.hItem) + return NULL; + + tvi.mask = TVIF_PARAM; + if (!TreeView_GetItem(m_hTreeView, &tvi)) + return NULL; + + return (COpenWithList::SApp*)tvi.lParam; +} + +VOID COpenWithDialog::Init(HWND hwnd) +{ + TRACE("COpenWithDialog::Init hwnd %p\n", hwnd); + + m_hDialog = hwnd; + SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR)this); + + /* Handle register checkbox */ + HWND hRegisterCheckbox = GetDlgItem(hwnd, 14003); + if (!(m_pInfo->oaifInFlags & OAIF_ALLOW_REGISTRATION)) + EnableWindow(hRegisterCheckbox, FALSE); + if (m_pInfo->oaifInFlags & OAIF_FORCE_REGISTRATION) + SendMessage(hRegisterCheckbox, BM_SETCHECK, BST_CHECKED, 0); + if (m_pInfo->oaifInFlags & OAIF_HIDE_REGISTRATION) + ShowWindow(hRegisterCheckbox, SW_HIDE); + + if (m_pInfo->pcszFile) + { + WCHAR wszBuf[MAX_PATH]; + UINT cchBuf; + + /* Add filename to label */ + cchBuf = GetDlgItemTextW(hwnd, 14001, wszBuf, _countof(wszBuf)); + StringCchCopyW(wszBuf + cchBuf, _countof(wszBuf) - cchBuf, m_pInfo->pcszFile); + SetDlgItemTextW(hwnd, 14001, wszBuf); + + /* Load applications from registry */ + m_pAppList->Load(); + m_pAppList->LoadRecommended(m_pInfo->pcszFile); + + /* Init treeview */ + m_hTreeView = GetDlgItem(hwnd, 14002); + m_hImgList = ImageList_Create(16, 16, 0, m_pAppList->GetCount() + 1, m_pAppList->GetCount() + 1); + TreeView_SetImageList(m_hTreeView, m_hImgList, TVSIL_NORMAL); + + /* If there are some recommendations add parent nodes: Recommended and Others */ + UINT cRecommended = m_pAppList->GetRecommendedCount(); + if (cRecommended > 0) + { + TVINSERTSTRUCT tvins; + HICON hFolderIcon; + + tvins.hParent = tvins.hInsertAfter = TVI_ROOT; + tvins.item.mask = TVIF_TEXT|TVIF_STATE|TVIF_IMAGE|TVIF_SELECTEDIMAGE; + tvins.item.pszText = (LPWSTR)wszBuf; + tvins.item.state = tvins.item.stateMask = TVIS_EXPANDED; + hFolderIcon = (HICON)LoadImage(shell32_hInstance, MAKEINTRESOURCE(IDI_SHELL_FOLDER), IMAGE_ICON, 0, 0, 0); + tvins.item.iImage = tvins.item.iSelectedImage = ImageList_AddIcon(m_hImgList, hFolderIcon); + + LoadStringW(shell32_hInstance, IDS_OPEN_WITH_RECOMMENDED, wszBuf, _countof(wszBuf)); + m_hRecommend = TreeView_InsertItem(m_hTreeView, &tvins); + + LoadStringW(shell32_hInstance, IDS_OPEN_WITH_OTHER, wszBuf, _countof(wszBuf)); + m_hOther = TreeView_InsertItem(m_hTreeView, &tvins); + } + else + m_hRecommend = m_hOther = TVI_ROOT; + + /* Add all applications */ + BOOL bNoAppSelected = TRUE; + COpenWithList::SApp *pAppList = m_pAppList->GetList(); + for (UINT i = 0; i < m_pAppList->GetCount(); ++i) + { + if (!COpenWithList::IsHidden(&pAppList[i])) + { + if (bNoAppSelected && (pAppList[i].bRecommended || !cRecommended)) + { + AddApp(&pAppList[i], TRUE); + bNoAppSelected = FALSE; + } + else + AddApp(&pAppList[i], FALSE); + } + } + } +} + +VOID COpenWithDialog::Accept() +{ + COpenWithList::SApp *pApp = GetCurrentApp(); + if (pApp) + { + /* Set programm as default handler */ + if (SendDlgItemMessage(m_hDialog, 14003, BM_GETCHECK, 0, 0) == BST_CHECKED) + m_pAppList->SetDefaultHandler(pApp, m_pInfo->pcszFile); + + /* Execute program */ + if (m_pInfo->oaifInFlags & OAIF_EXEC) + m_pAppList->Execute(pApp, m_pInfo->pcszFile); + + DestroyWindow(m_hDialog); + } +} + +INT_PTR CALLBACK COpenWithDialog::DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + COpenWithDialog *pThis = (COpenWithDialog*)GetWindowLongPtr(hwndDlg, DWLP_USER); + + switch(uMsg) + { + case WM_INITDIALOG: + { + COpenWithDialog *pThis = (COpenWithDialog*)lParam; + + pThis->Init(hwndDlg); + return TRUE; + } + case WM_COMMAND: + switch(LOWORD(wParam)) + { + case 14004: /* browse */ + { + pThis->Browse(); + return TRUE; + } + case 14005: /* ok */ + { + pThis->Accept(); + return TRUE; + } + case 14006: /* cancel */ + DestroyWindow(hwndDlg); + return TRUE; + default: + break; + } + break; + case WM_NOTIFY: + switch (((LPNMHDR)lParam)->code) + { + case TVN_SELCHANGED: + EnableWindow(GetDlgItem(hwndDlg, 14005), pThis->GetCurrentApp() ? TRUE : FALSE); + break; + case NM_DBLCLK: + case NM_RETURN: + pThis->Accept(); + break; + } + break; + case WM_CLOSE: + DestroyWindow(hwndDlg); + return TRUE; + default: + break; + } + return FALSE; +} COpenWithMenu::COpenWithMenu() { m_idCmdFirst = 0; m_idCmdLast = 0; + m_pAppList = new COpenWithList; } COpenWithMenu::~COpenWithMenu() { - TRACE("Destroying IContextMenu(%p)\n", this); + TRACE("Destroying COpenWithMenu(%p)\n", this); + if (m_hSubMenu) - FreeMenuItemContext(m_hSubMenu); -} - -static VOID -FreeMenuItemContext(HMENU hMenu) -{ - INT Count, Index; - MENUITEMINFOW mii; - - /* get item count */ - Count = GetMenuItemCount(hMenu); - if (Count == -1) - return; - - /* setup menuitem info */ - ZeroMemory(&mii, sizeof(mii)); - mii.cbSize = sizeof(mii); - mii.fMask = MIIM_DATA | MIIM_FTYPE | MIIM_CHECKMARKS; - - for(Index = 0; Index < Count; Index++) { - if (GetMenuItemInfoW(hMenu, Index, TRUE, &mii)) + INT Count, Index; + MENUITEMINFOW mii; + + /* get item count */ + Count = GetMenuItemCount(m_hSubMenu); + if (Count == -1) + return; + + /* setup menuitem info */ + ZeroMemory(&mii, sizeof(mii)); + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_DATA | MIIM_FTYPE | MIIM_CHECKMARKS; + + for(Index = 0; Index < Count; Index++) { - if (mii.dwItemData) - HeapFree(GetProcessHeap(), 0, (LPVOID)mii.dwItemData); - if (mii.hbmpChecked) - DeleteObject(mii.hbmpChecked); + if (GetMenuItemInfoW(m_hSubMenu, Index, TRUE, &mii)) + { + if (mii.hbmpChecked) + DeleteObject(mii.hbmpChecked); + } } } + + if (m_pAppList) + delete m_pAppList; } -static HBITMAP -IconToBitmap(HICON hIcon) +HBITMAP COpenWithMenu::IconToBitmap(HICON hIcon) { HDC hdc, hdcScr; HBITMAP hbm, hbmOld; @@ -120,7 +1087,7 @@ IconToBitmap(HICON hIcon) hbmOld = (HBITMAP)SelectObject(hdc, hbm); FillRect(hdc, &rc, (HBRUSH)(COLOR_MENU + 1)); - if(!DrawIconEx(hdc, 0, 0, hIcon, rc.right, rc.bottom, 0, NULL, DI_NORMAL)) + if (!DrawIconEx(hdc, 0, 0, hIcon, rc.right, rc.bottom, 0, NULL, DI_NORMAL)) ERR("DrawIcon failed: %x\n", GetLastError()); SelectObject(hdc, hbmOld); @@ -129,22 +1096,19 @@ IconToBitmap(HICON hIcon) return hbm; } -static VOID -AddChooseProgramItem(HMENU hMenu, UINT idCmd) +VOID COpenWithMenu::AddChooseProgramItem() { MENUITEMINFOW mii; WCHAR wszBuf[128]; - TRACE("hMenu %p idCmd %u\n", hMenu, idCmd); - ZeroMemory(&mii, sizeof(mii)); mii.cbSize = sizeof(mii); mii.fMask = MIIM_TYPE | MIIM_ID; mii.fType = MFT_SEPARATOR; mii.wID = -1; - InsertMenuItemW(hMenu, -1, TRUE, &mii); + InsertMenuItemW(m_hSubMenu, -1, TRUE, &mii); - if (!LoadStringW(shell32_hInstance, IDS_OPEN_WITH_CHOOSE, wszBuf, sizeof(wszBuf) / sizeof(WCHAR))) + if (!LoadStringW(shell32_hInstance, IDS_OPEN_WITH_CHOOSE, wszBuf, _countof(wszBuf))) { ERR("Failed to load string\n"); return; @@ -153,37 +1117,37 @@ AddChooseProgramItem(HMENU hMenu, UINT idCmd) mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE; mii.fType = MFT_STRING; mii.fState = MFS_ENABLED; - mii.wID = idCmd; + mii.wID = m_idCmdLast; mii.dwTypeData = (LPWSTR)wszBuf; mii.cch = wcslen(wszBuf); - InsertMenuItemW(hMenu, -1, TRUE, &mii); + InsertMenuItemW(m_hSubMenu, -1, TRUE, &mii); } -static VOID -LoadOpenWithItems(POPEN_WITH_CONTEXT pContext, LPCWSTR szName) +VOID COpenWithMenu::AddApp(PVOID pApp) { - const WCHAR *pwszExt; - WCHAR wszPath[100]; - DWORD dwSize; + MENUITEMINFOW mii; + LPCWSTR pwszName = m_pAppList->GetName((COpenWithList::SApp*)pApp); - pwszExt = wcsrchr(szName, '.'); - if (!pwszExt) + ZeroMemory(&mii, sizeof(mii)); + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE | MIIM_DATA; + mii.fType = MFT_STRING; + mii.fState = MFS_ENABLED; + mii.wID = m_idCmdLast; + mii.dwTypeData = (LPWSTR)pwszName; + mii.cch = wcslen(mii.dwTypeData); + mii.dwItemData = (ULONG_PTR)pApp; + + HICON hIcon = m_pAppList->GetIcon((COpenWithList::SApp*)pApp); + if (hIcon) { - /* FIXME: show default list of available programs */ - return; + mii.fMask |= MIIM_CHECKMARKS; + mii.hbmpChecked = mii.hbmpUnchecked = IconToBitmap(hIcon); } - /* load programs directly associated from HKCU */ - LoadItemFromHKCU(pContext, pwszExt); - - /* load programs associated from HKCR\Extension */ - LoadItemFromHKCR(pContext, pwszExt); - - /* load programs referenced from HKCR\ProgId */ - dwSize = sizeof(wszPath); - if (RegGetValueW(HKEY_CLASSES_ROOT, pwszExt, NULL, RRF_RT_REG_SZ, NULL, wszPath, &dwSize) == ERROR_SUCCESS) - LoadItemFromHKCR(pContext, wszPath); + if (InsertMenuItemW(m_hSubMenu, -1, TRUE, &mii)) + m_idCmdLast++; } HRESULT WINAPI COpenWithMenu::QueryContextMenu( @@ -196,42 +1160,38 @@ HRESULT WINAPI COpenWithMenu::QueryContextMenu( MENUITEMINFOW mii; WCHAR wszBuf[100]; INT DefaultPos; - HMENU hSubMenu; - OPEN_WITH_CONTEXT Context; TRACE("hMenu %p indexMenu %u idFirst %u idLast %u uFlags %u\n", hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags); - if (!LoadStringW(shell32_hInstance, IDS_OPEN_WITH, wszBuf, sizeof(wszBuf) / sizeof(WCHAR))) + if (!LoadStringW(shell32_hInstance, IDS_OPEN_WITH, wszBuf, _countof(wszBuf))) { ERR("Failed to load string\n"); return E_FAIL; } - hSubMenu = CreatePopupMenu(); + /* Init cmd id */ + m_idCmdFirst = m_idCmdLast = idCmdFirst; - /* set up context */ - ZeroMemory(&Context, sizeof(OPEN_WITH_CONTEXT)); - Context.bMenu = TRUE; - Context.hMenu = hSubMenu; - Context.idCmd = idCmdFirst; + /* Load applications list */ + m_pAppList->Load(); + m_pAppList->LoadRecommended(m_wszPath); - /* load items */ - LoadOpenWithItems(&Context, m_wszPath); - if (Context.idCmd == idCmdFirst) + /* Create submenu only if the is some choice */ + if (m_pAppList->GetRecommendedCount() > 1) { - /* No items has been added */ - DestroyMenu(hSubMenu); - m_hSubMenu = NULL; - m_idCmdFirst = idCmdFirst; - m_idCmdLast = idCmdFirst; + m_hSubMenu = CreatePopupMenu(); + + for(unsigned i = 0; i < m_pAppList->GetCount(); ++i) + { + COpenWithList::SApp *pApp = m_pAppList->GetList() + i; + if (pApp->bRecommended) + AddApp(pApp); + } + + AddChooseProgramItem(); } else - { - AddChooseProgramItem(hSubMenu, Context.idCmd); - m_idCmdFirst = idCmdFirst; - m_idCmdLast = Context.idCmd; - m_hSubMenu = hSubMenu; - } + m_hSubMenu = NULL; DefaultPos = GetMenuDefaultItem(hMenu, TRUE, 0); @@ -257,435 +1217,7 @@ HRESULT WINAPI COpenWithMenu::QueryContextMenu( InsertMenuItemW(hMenu, DefaultPos + 1, TRUE, &mii); - return MAKE_HRESULT(SEVERITY_SUCCESS, 0, m_idCmdLast - idCmdFirst + 1); -} - -static VOID -FreeListItems(HWND hwndDlg) -{ - HWND hList; - LRESULT iIndex, iCount; - POPEN_ITEM_CONTEXT pContext; - - hList = GetDlgItem(hwndDlg, 14002); - iCount = SendMessageW(hList, LB_GETCOUNT, 0, 0); - if (iCount == LB_ERR) - return; - - for (iIndex = 0; iIndex < iCount; iIndex++) - { - pContext = (POPEN_ITEM_CONTEXT)SendMessageW(hList, LB_GETITEMDATA, iIndex, 0); - if (pContext) - { - DestroyIcon(pContext->hIcon); - SendMessageW(hList, LB_SETITEMDATA, iIndex, (LPARAM)0); - HeapFree(GetProcessHeap(), 0, pContext); - } - } -} - -static BOOL -IsAppHidden(LPCWSTR pwszFileName) -{ - WCHAR wszBuf[100]; - DWORD dwSize = 0; - LONG result; - - if (FAILED(StringCbPrintfW(wszBuf, sizeof(wszBuf), L"Applications\\%s", pwszFileName))) - { - ERR("insufficient buffer\n"); - return FALSE; - } - - result = RegGetValueW(HKEY_CLASSES_ROOT, wszBuf, L"NoOpenWith", RRF_RT_REG_SZ, NULL, NULL, &dwSize); - - TRACE("result %d wszBuf %s\n", result, wszBuf); - - if (result == ERROR_SUCCESS) - return TRUE; - else - return FALSE; -} - -static VOID -WriteStaticShellExtensionKey(HKEY hRootKey, LPCWSTR pwszVerb, LPCWSTR pwszFullPath) -{ - HKEY hShell; - WCHAR wszBuf[MAX_PATH]; - - /* construct verb reg path */ - if (FAILED(StringCbPrintfW(wszBuf, sizeof(wszBuf), L"shell\\%s\\command", pwszVerb))) - { - ERR("insufficient buffer\n"); - return; - } - - /* create verb reg key */ - if (RegCreateKeyExW(hRootKey, wszBuf, 0, NULL, 0, KEY_WRITE, NULL, &hShell, NULL) != ERROR_SUCCESS) - return; - - /* build command buffer */ - StringCbPrintfW(wszBuf, sizeof(wszBuf), L"%s %%1", pwszFullPath); - - RegSetValueExW(hShell, NULL, 0, REG_SZ, (const BYTE*)wszBuf, (wcslen(wszBuf) + 1) * sizeof(WCHAR)); - RegCloseKey(hShell); -} - -static VOID -StoreNewSettings(LPCWSTR pwszFileName, LPCWSTR pwszAppName) -{ - WCHAR wszBuf[100]; - LPCWSTR pwszExt; - HKEY hKey; - HANDLE hList; - - /* Get file extension */ - pwszExt = wcsrchr(pwszFileName, L'.'); - if (!pwszExt) - return; - - /* Build registry key */ - if (FAILED(StringCbPrintfW(wszBuf, sizeof(wszBuf), - L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\%s", - pwszExt))) - { - ERR("insufficient buffer\n"); - return; - } - - /* Open base key for this file extension */ - if (RegCreateKeyExW(HKEY_CURRENT_USER, wszBuf, 0, NULL, 0, KEY_WRITE | KEY_READ, NULL, &hKey, NULL) != ERROR_SUCCESS) - return; - - /* Open MRU list */ - hList = OpenMRUList(hKey); - if (hList) - { - /* Insert the entry */ - AddMRUStringW(hList, pwszAppName); - - /* Close MRU list */ - FreeMRUList(hList); - } - - RegCloseKey(hKey); -} - -static VOID -SetProgramAsDefaultHandler(LPCWSTR pwszFileName, LPCWSTR pwszAppName) -{ - HKEY hKey; - HKEY hAppKey; - DWORD dwDisposition; - WCHAR wszBuf[100]; - DWORD dwSize; - BOOL result; - LPCWSTR pwszExt; - LPCWSTR pwszAppFileName; - - /* Extract file extension */ - pwszExt = wcsrchr(pwszFileName, L'.'); - if (!pwszExt) - return; - - /* Create file extension key */ - if (RegCreateKeyExW(HKEY_CLASSES_ROOT, pwszExt, 0, NULL, 0, KEY_WRITE, NULL, &hKey, &dwDisposition) != ERROR_SUCCESS) - return; - - if (dwDisposition == REG_CREATED_NEW_KEY) - { - /* A new entry was created create the prog key id */ - StringCbPrintfW(wszBuf, sizeof(wszBuf), L"%s_auto_file", pwszExt + 1); - if (RegSetValueExW(hKey, NULL, 0, REG_SZ, (const BYTE*)wszBuf, (wcslen(wszBuf) + 1) * sizeof(WCHAR)) != ERROR_SUCCESS) - { - RegCloseKey(hKey); - return; - } - } - else - { - /* Entry already exists fetch prog key id */ - dwSize = sizeof(wszBuf); - if (RegGetValueW(hKey, NULL, NULL, RRF_RT_REG_SZ, NULL, wszBuf, &dwSize) != ERROR_SUCCESS) - { - RegCloseKey(hKey); - return; - } - } - - /* Close file extension key */ - RegCloseKey(hKey); - - /* Create prog id key */ - if (RegCreateKeyExW(HKEY_CLASSES_ROOT, wszBuf, 0, NULL, 0, KEY_WRITE, NULL, &hKey, &dwDisposition) != ERROR_SUCCESS) - return; - - /* Check if there already verbs existing for that app */ - pwszAppFileName = wcsrchr(pwszAppName, L'\\'); - StringCbPrintfW(wszBuf, sizeof(wszBuf), L"Classes\\Applications\\%s\\shell", pwszAppFileName); - if (RegOpenKeyExW(HKEY_CLASSES_ROOT, wszBuf, 0, KEY_READ, &hAppKey) == ERROR_SUCCESS) - { - /* Copy static verbs from Classes\Applications key */ - HKEY hDestKey; - if (RegCreateKeyExW(hKey, L"shell", 0, NULL, 0, KEY_WRITE, NULL, &hDestKey, &dwDisposition) == ERROR_SUCCESS) - { - result = RegCopyTreeW(hAppKey, NULL, hDestKey); - RegCloseKey(hDestKey); - if (result == ERROR_SUCCESS) - { - /* Copied all subkeys, we are done */ - RegCloseKey(hKey); - RegCloseKey(hAppKey); - return; - } - } - RegCloseKey(hAppKey); - } - - /* Write standard static shell extension */ - WriteStaticShellExtensionKey(hKey, L"open", pwszAppName); - RegCloseKey(hKey); -} - -static VOID -BrowseForApplication(HWND hwndDlg) -{ - WCHAR wszTitle[64]; - WCHAR wszFilter[256]; - WCHAR wszPath[MAX_PATH]; - OPENFILENAMEW ofn; - OPEN_WITH_CONTEXT Context; - INT iCount; - - /* Initialize OPENFILENAMEW structure */ - ZeroMemory(&ofn, sizeof(OPENFILENAMEW)); - ofn.lStructSize = sizeof(OPENFILENAMEW); - ofn.hInstance = shell32_hInstance; - ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; - ofn.nMaxFile = (sizeof(wszPath) / sizeof(WCHAR)); - ofn.lpstrFile = wszPath; - - /* Init title */ - if (LoadStringW(shell32_hInstance, IDS_OPEN_WITH, wszTitle, sizeof(wszTitle) / sizeof(WCHAR))) - { - ofn.lpstrTitle = wszTitle; - ofn.nMaxFileTitle = wcslen(wszTitle); - } - - /* Init the filter string */ - if (LoadStringW(shell32_hInstance, IDS_OPEN_WITH_FILTER, wszFilter, sizeof(wszFilter) / sizeof(WCHAR))) - ofn.lpstrFilter = wszFilter; - ZeroMemory(wszPath, sizeof(wszPath)); - - /* Create OpenFile dialog */ - if (!GetOpenFileNameW(&ofn)) - return; - - /* Setup context for insert proc */ - ZeroMemory(&Context, sizeof(OPEN_WITH_CONTEXT)); - Context.hDlgCtrl = GetDlgItem(hwndDlg, 14002); - iCount = SendMessage(Context.hDlgCtrl, LB_GETCOUNT, 0, 0); - InsertOpenWithItem(&Context, wszPath); - - /* Select new item */ - SendMessage(Context.hDlgCtrl, LB_SETCURSEL, iCount, 0); -} - -static POPEN_ITEM_CONTEXT -GetCurrentOpenItemContext(HWND hwndDlg) -{ - LRESULT result; - - /* get current item */ - result = SendDlgItemMessage(hwndDlg, 14002, LB_GETCURSEL, 0, 0); - if(result == LB_ERR) - return NULL; - - /* get item context */ - result = SendDlgItemMessage(hwndDlg, 14002, LB_GETITEMDATA, result, 0); - if (result == LB_ERR) - return NULL; - - return (POPEN_ITEM_CONTEXT)result; -} - -static VOID -ExecuteOpenItem(POPEN_ITEM_CONTEXT pItemContext, LPCWSTR pwszPath) -{ - STARTUPINFOW si; - PROCESS_INFORMATION pi; - WCHAR wszBuf[MAX_PATH * 2 + 8]; - - /* setup path with argument */ - ZeroMemory(&si, sizeof(STARTUPINFOW)); - si.cb = sizeof(STARTUPINFOW); - - /* Build the command line. Don't use applcation name as first parameter of - CreateProcessW, because it have to be an absolute path. */ - StringCbPrintfW(wszBuf, sizeof(wszBuf), L"\"%s\" \"%s\"", pItemContext->wszAppPath, pwszPath); - - /* Start the application now */ - TRACE("AppName %ls Path %ls\n", pItemContext->wszAppPath, pwszPath); - if (CreateProcessW(NULL, wszBuf, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) - { - CloseHandle(pi.hThread); - CloseHandle(pi.hProcess); - SHAddToRecentDocs(SHARD_PATHW, pwszPath); - } -} - -static INT_PTR CALLBACK -OpenWithProgrammDlg(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch(uMsg) - { - case WM_INITDIALOG: - { - OPENASINFO *poainfo; - - SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG)lParam); - poainfo = (OPENASINFO*)lParam; - if (!(poainfo->oaifInFlags & OAIF_ALLOW_REGISTRATION)) - EnableWindow(GetDlgItem(hwndDlg, 14003), FALSE); - if (poainfo->oaifInFlags & OAIF_FORCE_REGISTRATION) - SendDlgItemMessage(hwndDlg, 14003, BM_SETCHECK, BST_CHECKED, 0); - if (poainfo->oaifInFlags & OAIF_HIDE_REGISTRATION) - ShowWindow(GetDlgItem(hwndDlg, 14003), SW_HIDE); - if (poainfo->pcszFile) - { - WCHAR wszBuf[MAX_PATH]; - UINT cchBuf; - OPEN_WITH_CONTEXT Context; - - cchBuf = GetDlgItemTextW(hwndDlg, 14001, wszBuf, sizeof(wszBuf) / sizeof(wszBuf[0])); - StringCchCopyW(wszBuf, _countof(wszBuf) - cchBuf, poainfo->pcszFile); - SetDlgItemTextW(hwndDlg, 14001, wszBuf); - - ZeroMemory(&Context, sizeof(OPEN_WITH_CONTEXT)); - Context.hDlgCtrl = GetDlgItem(hwndDlg, 14002); - LoadOpenWithItems(&Context, poainfo->pcszFile); - - SendMessage(Context.hDlgCtrl, LB_SETCURSEL, 0, 0); - } - return TRUE; - } - case WM_MEASUREITEM: - { - LPMEASUREITEMSTRUCT lpmis = (LPMEASUREITEMSTRUCT)lParam; - lpmis->itemHeight = 64; - return TRUE; - } - case WM_COMMAND: - switch(LOWORD(wParam)) - { - case 14004: /* browse */ - BrowseForApplication(hwndDlg); - return TRUE; - case 14002: - if (HIWORD(wParam) == LBN_SELCHANGE) - InvalidateRect((HWND)lParam, NULL, TRUE); // FIXME USE UPDATE RECT - break; - case 14005: /* ok */ - { - POPEN_ITEM_CONTEXT pItemContext; - - pItemContext = GetCurrentOpenItemContext(hwndDlg); - if (pItemContext) - { - OPENASINFO *poainfo = (OPENASINFO*)GetWindowLongPtr(hwndDlg, DWLP_USER); - - /* store settings in HKCU path */ - StoreNewSettings(poainfo->pcszFile, pItemContext->wszAppPath); - - if (SendDlgItemMessage(hwndDlg, 14003, BM_GETCHECK, 0, 0) == BST_CHECKED) - { - /* set programm as default handler */ - SetProgramAsDefaultHandler(poainfo->pcszFile, pItemContext->wszAppPath); - } - - if (poainfo->oaifInFlags & OAIF_EXEC) - ExecuteOpenItem(pItemContext, poainfo->pcszFile); - } - FreeListItems(hwndDlg); - DestroyWindow(hwndDlg); - return TRUE; - } - case 14006: /* cancel */ - FreeListItems(hwndDlg); - DestroyWindow(hwndDlg); - return TRUE; - default: - break; - } - break; - case WM_DRAWITEM: - { - LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT)lParam; - TEXTMETRIC mt; - COLORREF preColor, preBkColor; - LONG cyOffset; - POPEN_ITEM_CONTEXT pItemContext; - INT Index; - WCHAR wszBuf[MAX_PATH]; - - if ((int)lpdis->itemID == -1) - break; - - switch (lpdis->itemAction) - { - case ODA_SELECT: - case ODA_DRAWENTIRE: - Index = SendMessageW(lpdis->hwndItem, LB_GETCURSEL, 0, 0); - pItemContext = (POPEN_ITEM_CONTEXT)SendMessage(lpdis->hwndItem, LB_GETITEMDATA, lpdis->itemID, (LPARAM) 0); - - if ((int)lpdis->itemID == Index) - { - /* paint focused item with standard background colour */ - HBRUSH hBrush; - hBrush = CreateSolidBrush(RGB(46, 104, 160)); - FillRect(lpdis->hDC, &lpdis->rcItem, hBrush); - DeleteObject(hBrush); - preBkColor = SetBkColor(lpdis->hDC, RGB(46, 104, 160)); - } - else - { - /* paint non focused item with white background */ - HBRUSH hBrush; - hBrush = CreateSolidBrush(RGB(255, 255, 255)); - FillRect(lpdis->hDC, &lpdis->rcItem, hBrush); - DeleteObject(hBrush); - preBkColor = SetBkColor(lpdis->hDC, RGB(255, 255, 255)); - } - - SendMessageW(lpdis->hwndItem, LB_GETTEXT, lpdis->itemID, (LPARAM)wszBuf); - /* paint the icon */ - DrawIconEx(lpdis->hDC, lpdis->rcItem.left, lpdis->rcItem.top, pItemContext->hIcon, 0, 0, 0, NULL, DI_NORMAL); - /* get text size */ - GetTextMetrics(lpdis->hDC, &mt); - /* paint app name */ - cyOffset = lpdis->rcItem.top + mt.tmHeight / 2; - TextOutW(lpdis->hDC, 45, cyOffset, wszBuf, wcslen(wszBuf)); - /* paint manufacturer description */ - cyOffset += mt.tmHeight + 2; - preColor = SetTextColor(lpdis->hDC, RGB(192, 192, 192)); - if (pItemContext->wszManufacturer[0]) - TextOutW(lpdis->hDC, 45, cyOffset, pItemContext->wszManufacturer, wcslen(pItemContext->wszManufacturer)); - else - TextOutW(lpdis->hDC, 45, cyOffset, pItemContext->wszAppPath, wcslen(pItemContext->wszAppPath)); - SetTextColor(lpdis->hDC, preColor); - SetBkColor(lpdis->hDC, preBkColor); - break; - } - break; - } - case WM_CLOSE: - FreeListItems(hwndDlg); - DestroyWindow(hwndDlg); - return TRUE; - default: - break; - } - return FALSE; + return MAKE_HRESULT(SEVERITY_SUCCESS, 0, m_idCmdLast - m_idCmdFirst + 1); } HRESULT WINAPI @@ -700,9 +1232,12 @@ COpenWithMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpici) if (m_idCmdFirst + LOWORD(lpici->lpVerb) == m_idCmdLast) { OPENASINFO info; + LPCWSTR pwszExt = PathFindExtensionW(m_wszPath); info.pcszFile = m_wszPath; - info.oaifInFlags = OAIF_ALLOW_REGISTRATION | OAIF_REGISTER_EXT | OAIF_EXEC; + info.oaifInFlags = OAIF_EXEC; + if (pwszExt[0]) + info.oaifInFlags |= OAIF_REGISTER_EXT | OAIF_ALLOW_REGISTRATION; info.pcszClass = NULL; hr = SHOpenWithDialog(lpici->hwnd, &info); } @@ -717,8 +1252,8 @@ COpenWithMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpici) if (GetMenuItemInfoW(m_hSubMenu, LOWORD(lpici->lpVerb), TRUE, &mii) && mii.dwItemData) { /* launch item with specified app */ - POPEN_ITEM_CONTEXT pItemContext = (POPEN_ITEM_CONTEXT)mii.dwItemData; - ExecuteOpenItem(pItemContext, m_wszPath); + COpenWithList::SApp *pApp = (COpenWithList::SApp*)mii.dwItemData; + COpenWithList::Execute(pApp, m_wszPath); hr = S_OK; } } @@ -747,259 +1282,6 @@ HRESULT WINAPI COpenWithMenu::HandleMenuMsg( return E_NOTIMPL; } -static VOID -LoadFileInfo(LPCWSTR pwszAppPath, POPEN_ITEM_CONTEXT pContext, LPWSTR pwszAppName, unsigned cchAppName) -{ - UINT cbSize; - LPVOID pBuf; - WORD wLang = 0, wCode = 0; - LPLANGANDCODEPAGE lpLangCode; - WCHAR wszBuf[100]; - WCHAR *pResult; - - /* Clear manufacturer */ - pContext->wszManufacturer[0] = 0; - - /* query version info size */ - cbSize = GetFileVersionInfoSizeW(pwszAppPath, NULL); - if (!cbSize) - return; - - /* allocate buffer */ - pBuf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbSize); - if (!pBuf) - return; - - /* query version info */ - if(!GetFileVersionInfoW(pwszAppPath, 0, cbSize, pBuf)) - { - HeapFree(GetProcessHeap(), 0, pBuf); - return; - } - - /* query lang code */ - if(VerQueryValueW(pBuf, L"VarFileInfo\\Translation", (LPVOID*)&lpLangCode, &cbSize)) - { - /* FIXME: find language from current locale / if not available, - * default to english - * for now default to first available language - */ - wLang = lpLangCode->lang; - wCode = lpLangCode->code; - } - - /* Query name */ - swprintf(wszBuf, L"\\StringFileInfo\\%04x%04x\\FileDescription", wLang, wCode); - if (VerQueryValueW(pBuf, wszBuf, (LPVOID *)&pResult, &cbSize)) - StringCchCopyNW(pwszAppName, cchAppName, pResult, cbSize); - - /* Query manufacturer */ - swprintf(wszBuf, L"\\StringFileInfo\\%04x%04x\\CompanyName", wLang, wCode); - - if (VerQueryValueW(pBuf, wszBuf, (LPVOID *)&pResult, &cbSize)) - StringCbCopyNW(pContext->wszManufacturer, sizeof(pContext->wszManufacturer), pResult, cbSize); - HeapFree(GetProcessHeap(), 0, pBuf); -} - -static VOID -InsertOpenWithItem(POPEN_WITH_CONTEXT pContext, LPCWSTR pwszAppPath) -{ - POPEN_ITEM_CONTEXT pItemContext; - WCHAR wszAppName[256]; - - /* Allocate new item context */ - pItemContext = (OPEN_ITEM_CONTEXT *)HeapAlloc(GetProcessHeap(), 0, sizeof(OPEN_ITEM_CONTEXT)); - if (!pItemContext) - return; - - /* Store app path and icon */ - wcscpy(pItemContext->wszAppPath, pwszAppPath); - pItemContext->hIcon = ExtractIconW(shell32_hInstance, pwszAppPath, 0); - LoadFileInfo(pwszAppPath, pItemContext, wszAppName, _countof(wszAppName)); - - /* Add item to the list */ - if (pContext->bMenu) - { - MENUITEMINFOW mii; - - ZeroMemory(&mii, sizeof(mii)); - mii.cbSize = sizeof(mii); - mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE | MIIM_DATA | MIIM_CHECKMARKS; - mii.fType = MFT_STRING; //MFT_OWNERDRAW; - mii.fState = MFS_ENABLED; - mii.wID = pContext->idCmd; - mii.dwTypeData = wszAppName; - mii.cch = wcslen(wszAppName); - mii.dwItemData = (ULONG_PTR)pItemContext; - mii.hbmpChecked = mii.hbmpUnchecked = IconToBitmap(pItemContext->hIcon); - - if (InsertMenuItemW(pContext->hMenu, -1, TRUE, &mii)) - pContext->idCmd++; - } - else - { - LRESULT Index; - - Index = SendMessageW(pContext->hDlgCtrl, LB_ADDSTRING, 0, (LPARAM)wszAppName); - if (Index != LB_ERR) - SendMessageW(pContext->hDlgCtrl, LB_SETITEMDATA, Index, (LPARAM)pItemContext); - } -} - -static VOID -AddItemFromProgIDList(POPEN_WITH_CONTEXT pContext, HKEY hKey) -{ - FIXME("implement me :)))\n"); -} - -static HANDLE -OpenMRUList(HKEY hKey) -{ - CREATEMRULISTW Info; - - /* initialize mru list info */ - Info.cbSize = sizeof(Info); - Info.nMaxItems = 32; - Info.dwFlags = MRU_STRING; - Info.hKey = hKey; - Info.lpszSubKey = L"OpenWithList"; - Info.lpfnCompare = NULL; - - /* load list */ - return CreateMRUListW(&Info); -} - -static VOID -AddItemFromMRUList(POPEN_WITH_CONTEXT pContext, HKEY hKey) -{ - HANDLE hList; - int nItem, nCount, nResult; - WCHAR wszBuf[MAX_PATH]; - - /* open mru list */ - hList = OpenMRUList(hKey); - if (!hList) - { - ERR("OpenMRUList failed\n"); - return; - } - - /* get list count */ - nCount = EnumMRUListW(hList, -1, NULL, 0); - - for(nItem = 0; nItem < nCount; nItem++) - { - nResult = EnumMRUListW(hList, nItem, wszBuf, _countof(wszBuf)); - if (nResult <= 0) - continue; - - /* insert item */ - if (!IsAppHidden(wszBuf)) - InsertOpenWithItem(pContext, wszBuf); - } - - /* free the mru list */ - FreeMRUList(hList); -} - -static VOID -LoadItemFromHKCR(POPEN_WITH_CONTEXT pContext, LPCWSTR pwszExt) -{ - HKEY hKey; - HKEY hSubKey; - WCHAR wszBuf[MAX_PATH], wszBuf2[MAX_PATH]; - DWORD dwSize; - - /* Check if extension exists */ - if (RegOpenKeyExW(HKEY_CLASSES_ROOT, pwszExt, 0, KEY_READ, &hKey) != ERROR_SUCCESS) - return; - - if (RegGetValueW(hKey, NULL, L"NoOpen", RRF_RT_REG_SZ, NULL, NULL, &dwSize) == ERROR_SUCCESS) - { - /* Display warning dialog */ - pContext->bNoOpen = TRUE; - } - - /* Check if there is a directly available execute key */ - dwSize = sizeof(wszBuf); - if (RegGetValueW(hKey, L"shell\\open\\command", NULL, RRF_RT_REG_SZ, NULL, (PVOID)wszBuf, &dwSize) == ERROR_SUCCESS) - { - WCHAR *pwszSpace = wcsrchr(wszBuf, L' '); - if (pwszSpace) - { - /* Erase %1 or extra arguments */ - *pwszSpace = 0; // FIXME: what about '"' - } - if(!IsAppHidden(wszBuf)) - InsertOpenWithItem(pContext, wszBuf); - } - - /* Load items from HKCR\Ext\OpenWithList */ - if (RegOpenKeyExW(hKey, L"OpenWithList", 0, KEY_READ, &hSubKey) == ERROR_SUCCESS) - { - AddItemFromMRUList(pContext, hKey); - RegCloseKey(hSubKey); - } - - /* Load items from HKCR\Ext\OpenWithProgIDs */ - if (RegOpenKeyExW(hKey, L"OpenWithProgIDs", 0, KEY_READ, &hSubKey) == ERROR_SUCCESS) - { - AddItemFromProgIDList(pContext, hSubKey); - RegCloseKey(hSubKey); - } - - /* Load items from SystemFileAssociations\Ext key */ - StringCbPrintfW(wszBuf, sizeof(wszBuf), L"SystemFileAssociations\\%s", pwszExt); - if (RegOpenKeyExW(HKEY_CLASSES_ROOT, wszBuf, 0, KEY_READ, &hSubKey) == ERROR_SUCCESS) - { - AddItemFromMRUList(pContext, hSubKey); - RegCloseKey(hSubKey); - } - - /* Load additional items from referenced PerceivedType*/ - dwSize = sizeof(wszBuf); - if (RegGetValueW(hKey, NULL, L"PerceivedType", RRF_RT_REG_SZ, NULL, wszBuf, &dwSize) != ERROR_SUCCESS) - { - RegCloseKey(hKey); - return; - } - RegCloseKey(hKey); - - StringCbPrintfW(wszBuf2, sizeof(wszBuf2), L"SystemFileAssociations\\%s", wszBuf); - if (RegOpenKeyExW(HKEY_CLASSES_ROOT, wszBuf2, 0, KEY_READ | KEY_WRITE, &hSubKey) == ERROR_SUCCESS) - { - AddItemFromMRUList(pContext, hSubKey); - RegCloseKey(hSubKey); - } -} - -static VOID -LoadItemFromHKCU(POPEN_WITH_CONTEXT pContext, LPCWSTR pwszExt) -{ - WCHAR wszBuf[MAX_PATH]; - HKEY hKey; - - /* Handle ProgId lists first */ - StringCbPrintfW(wszBuf, sizeof(wszBuf), - L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\%s\\OpenWithProgIDs", - pwszExt); - if (RegOpenKeyExW(HKEY_CURRENT_USER, wszBuf, 0, KEY_READ, &hKey) == ERROR_SUCCESS) - { - AddItemFromProgIDList(pContext, hKey); - RegCloseKey(hKey); - } - - /* Now handle MRU lists */ - StringCbPrintfW(wszBuf, sizeof(wszBuf), - L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\%s", - pwszExt); - if (RegOpenKeyExW(HKEY_CURRENT_USER, wszBuf, 0, KEY_READ, &hKey) == ERROR_SUCCESS) - { - AddItemFromMRUList(pContext, hKey); - RegCloseKey(hKey); - } -} - HRESULT WINAPI COpenWithMenu::Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdtobj, @@ -1013,7 +1295,7 @@ COpenWithMenu::Initialize(LPCITEMIDLIST pidlFolder, LPCITEMIDLIST pidlChild; LPCITEMIDLIST pidl; LPCWSTR pwszExt; - + TRACE("This %p\n", this); if (pdtobj == NULL) @@ -1029,7 +1311,7 @@ COpenWithMenu::Initialize(LPCITEMIDLIST pidlFolder, if (FAILED(hr)) { - ERR("IDataObject_GetData failed with 0x%x\n", hr); + ERR("pdtobj->GetData failed with 0x%x\n", hr); return hr; } @@ -1049,50 +1331,54 @@ COpenWithMenu::Initialize(LPCITEMIDLIST pidlFolder, ERR("no mem\n"); return E_OUTOFMEMORY; } - if (_ILIsDesktop(pidlChild) || _ILIsMyDocuments(pidlChild) || _ILIsControlPanel(pidlChild) || - _ILIsNetHood(pidlChild) || _ILIsBitBucket(pidlChild) || _ILIsDrive(pidlChild) || - _ILIsCPanelStruct(pidlChild) || _ILIsFolder(pidlChild) || _ILIsMyComputer(pidlChild)) + if (!_ILIsValue(pidlChild)) { - TRACE("pidl is a folder\n"); + TRACE("pidl is not a file\n"); SHFree((void*)pidl); return E_FAIL; } if (!SHGetPathFromIDListW(pidl, m_wszPath)) { - IID *iid = _ILGetGUIDPointer(pidl); SHFree((void*)pidl); - ERR("SHGetPathFromIDListW failed %s\n", iid ? shdebugstr_guid(iid) : ""); + ERR("SHGetPathFromIDListW failed\n"); return E_FAIL; } SHFree((void*)pidl); TRACE("szPath %s\n", debugstr_w(m_wszPath)); - pwszExt = wcsrchr(m_wszPath, L'.'); - if (pwszExt) + pwszExt = PathFindExtensionW(m_wszPath); + if (!_wcsicmp(pwszExt, L".exe") || !_wcsicmp(pwszExt, L".com") || + !_wcsicmp(pwszExt, L".scr") || !_wcsicmp(pwszExt, L".bat") || + !_wcsicmp(pwszExt, L".cmd") || !_wcsicmp(pwszExt, L".lnk")) { - if (!_wcsicmp(pwszExt, L".exe") || !_wcsicmp(pwszExt, L".lnk")) - { - TRACE("file is a executable or shortcut\n"); - return E_FAIL; - } + TRACE("file is a executable or shortcut\n"); + return E_FAIL; } return S_OK; } HRESULT WINAPI -SHOpenWithDialog(HWND hwndParent, - const OPENASINFO *poainfo) +SHOpenWithDialog(HWND hwndParent, const OPENASINFO *poainfo) { MSG msg; HWND hwnd; + COpenWithDialog *pDialog; + + TRACE("SHOpenWithDialog hwndParent %p poainfo %p\n", hwndParent, poainfo); + + InitCommonControls(); if (poainfo->pcszClass == NULL && poainfo->pcszFile == NULL) return E_FAIL; - hwnd = CreateDialogParam(shell32_hInstance, MAKEINTRESOURCE(OPEN_WITH_PROGRAMM_DLG), hwndParent, OpenWithProgrammDlg, (LPARAM)poainfo); + pDialog = new COpenWithDialog(poainfo); + if (!pDialog) + return E_OUTOFMEMORY; + + hwnd = CreateDialogParam(shell32_hInstance, MAKEINTRESOURCE(OPEN_WITH_PROGRAMM_DLG), hwndParent, COpenWithDialog::DialogProc, (LPARAM)pDialog); if (hwnd == NULL) { ERR("Failed to create dialog\n"); @@ -1110,5 +1396,7 @@ SHOpenWithDialog(HWND hwndParent, } } + delete pDialog; + return S_OK; } diff --git a/reactos/dll/win32/shell32/openwithmenu.h b/reactos/dll/win32/shell32/openwithmenu.h index ceaa415a6e1..e378227d6ea 100644 --- a/reactos/dll/win32/shell32/openwithmenu.h +++ b/reactos/dll/win32/shell32/openwithmenu.h @@ -22,6 +22,8 @@ #ifndef _SHE_OCMENU_H_ #define _SHE_OCMENU_H_ +class COpenWithList; + class COpenWithMenu : public CComCoClass, public CComObjectRootEx, @@ -32,6 +34,11 @@ class COpenWithMenu : UINT m_idCmdFirst, m_idCmdLast; WCHAR m_wszPath[MAX_PATH]; HMENU m_hSubMenu; + COpenWithList *m_pAppList; + + HBITMAP IconToBitmap(HICON hIcon); + VOID AddChooseProgramItem(); + VOID AddApp(PVOID pApp); public: COpenWithMenu(); diff --git a/reactos/dll/win32/shell32/shresdef.h b/reactos/dll/win32/shell32/shresdef.h index 634c4de48aa..349f4340010 100644 --- a/reactos/dll/win32/shell32/shresdef.h +++ b/reactos/dll/win32/shell32/shresdef.h @@ -137,6 +137,8 @@ #define IDS_FILE_DETAILS 175 #define IDS_FILE_DETAILSADV 176 #define IDS_BYTES_FORMAT 177 +#define IDS_OPEN_WITH_RECOMMENDED 178 +#define IDS_OPEN_WITH_OTHER 179 #define IDS_RUNDLG_ERROR 180 #define IDS_RUNDLG_BROWSE_ERROR 181