Как я могу использовать обычный диалог «Сохранить как» из VBScript?

Я хотел бы, чтобы мой VBScript отображал диалоговое окно Windows «Сохранить как», но я не мог понять, как это сделать.

Используя этот код:

Dim sfd
Set sfd = CreateObject("UserAccounts.CommonDialog")
sfd.ShowOpen

Я могу получить диалоговое окно «Открыть», но для этого объекта нет ShowSave метода (как, похоже, для аналогичного объекта в Visual Basic без сценария).

Я искал StackOverflow и искал в Google "[vbscript] save dialog" (и с "Windows Script Host"), но я нашел только темы о доступе к общим диалогам с веб-страниц и решение для диалогового окна BrowseForFolder и ничего особенного о вызове диалогового окна Save .

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


person JayK    schedule 08.12.2010    source источник
comment
UserAccounts.CommonDialog работает только в Windows XP. Он не будет работать под Windows Vista или более поздней версии. Это актуально для вас?   -  person Cody Gray    schedule 08.12.2010
comment
Ну ... на данный момент нет, но, наверное, лучше было бы решение, рассчитанное на будущее. Спасибо за подсказку.   -  person JayK    schedule 08.12.2010
comment
+1 за отличный вопрос. Чем больше я это гуглю, тем больше похоже, что универсального решения действительно нет. Все, что есть, будет работать только в Windows XP (не более ранних или более поздних версиях) и / или имеет внешние зависимости. Некоторые примеры даже открывают Internet Explorer и используют его диалоговое окно, будучи скрытым, что мне кажется очень плохой идеей. Также нет возможности вызвать собственные API Win32 из VBScript, поэтому я почти готов сделать вывод, что решения нет. Возможна ли внешняя зависимость (например, файл DLL, который необходимо включить в сценарий) или использование скомпилированного языка, такого как VB 6?   -  person Cody Gray    schedule 08.12.2010
comment
В конце концов, язык и форма исполняемого файла не важны, поэтому я определенно мог бы переписать сценарий. Теоретически возможно все, что не требует установки дополнительного программного обеспечения на целевой машине, за исключением стандартных компонентов Windows, но поскольку сценарий выполняет только простую задачу, было бы неплохо избежать особых зависимостей и вспомогательных файлов.   -  person JayK    schedule 08.12.2010
comment
На ›social.technet .microsoft.com / Forums / en-US / ITCG / thread / описан способ, как заставить UserAccounts.CommonDialog работать под Windows Vista и 7. Однако не тестировал его.   -  person Nubok    schedule 14.12.2010
comment
@Nubok: Предлагаемое решение фактически не использует UserAccounts.CommonDialog. Вместо этого он использует MSComDlg.CommonDialog из comdlg32.dll, который вам придется загрузить и зарегистрировать самостоятельно, если на вашем компьютере не установлена ​​Visual Studio (маловероятный сценарий для клиентов). Последний ответ также указывает на то, что все еще могут быть проблемы с подходом с использованием VBScript.   -  person Cody Gray    schedule 15.12.2010


Ответы (8)


Я могу с уверенностью сказать, что не существует решения для отображения диалогового окна «Сохранить как» из VBScript в версиях Windows, отличных от XP, без использования некоторых внешних зависимостей, которые вы должны установить и зарегистрировать самостоятельно. Помимо очевидного вмешательство, которое это вызывает в отношении простого развертывания вашего скрипта с помощью перетаскивания, оно также вызывает целый ряд других проблем, связанных с безопасностью и разрешениями, в частности, обход UAC на машине клиента для установки и регистрации зависимости DLL.

Решения, которые были предложены до сих пор, основаны либо на DLL-файле, который случайно включен в Windows XP, вызове диалогового окна «Сохранить как» из панели управления учетными записями пользователей Windows XP и / или установке программного обеспечения только для него. чтобы оставить MSComDlg DLL после ее удаления, которую затем можно будет использовать из VBScript. Ни одно из этих решений на самом деле не удовлетворяет вышеуказанным требованиям, и ни один из предоставленных ответов даже не рассматривает возможные препятствия безопасности, которые могут возникнуть с их предлагаемыми решениями, как я упоминал выше.

И поскольку вы не можете напрямую обращаться к Windows API (который очень удобно включает в себя именно такое диалоговое окно «Сохранить как») из VBScript (не только потому, что это может представлять угрозу безопасности, но и из-за слабости VBScript [отсутствие ?] печатая), что в значительной степени оставляет любого, кто хочет это сделать, в холоде. Кроме того, невозможность выполнять вызовы API также исключает использование любых хаков, таких как вызов SetWindowText , чтобы изменить заголовок диалогового окна "Открыть", как предлагается в вопросе.

Я понимаю, что это не тот ответ, которого все хотели. Это даже не тот ответ, которого я хотел. Но увы, это правильный ответ.

При этом есть несколько возможных обходных путей:

  1. Если вы склоняетесь к принятию любого из уже предложенных ответов, вы уже решили ввести внешнюю зависимость от файла DLL в свое развертывание VBScript. После того, как вы совершили такой скачок, зачем беспокоиться о заимствовании или ином захвате библиотеки DLL из другого источника? Просто сделай один раз сам. Обернуть собственные общие функции диалога, предоставляемые Windows API, в ActiveX DLL с помощью Visual Basic 6, который затем может быть вызван вашим VBScript, тривиально. Риски минимальны, поскольку можно ожидать, что практически в любой современной версии Windows уже установлена ​​среда выполнения Visual Basic, а поскольку вы, вероятно, уже знаете VBScript, создание кода в VB 6 не должно быть очень сложной задачей. Вы можете включить любые настраиваемые функции, которые захотите, и, что наиболее важно, вы получите полный контроль. Вам не придется беспокоиться о том, что деинсталляторы других приложений удалят DLL, которая требуется вашему скрипту, вам не придется возиться с установкой и удалением какого-то случайного устаревшего приложения, и вам не придется просто скрещивать пальцы и надеяться. Мы, программисты, знаем, что это никогда не лучший вариант.

    И да, я рекомендую фактически обернуть общие функции диалога, предоставляемые Windows API, вместо того, чтобы полагаться на общий диалог OCX (comdlg32.ocx), предоставляемый Visual Basic. У него есть свои проблемы в Windows 7, и он не даст вам великолепных новых диалогов, которые теперь предоставляют более поздние версии Windows. Отличная статья, объясняющая все, что вам нужно знать об API-интерфейсах Open и Save Common Dialog и о том, как их использовать в VB 6, - это доступен здесь, в VBnet. Конечно, если вы действительно хотите сделать все возможное, есть множество интересных вещей, которые вы можете сделать с помощью обычных диалогов, все они задокументированы (с кодом!) здесь, в VB Accelerator.

  2. Но теперь, когда я убедил вас всех написать ActiveX DLL в VB 6, который объединяет общие функциональные возможности диалогов для использования в вашем VBScript, я должен задать вопрос: зачем на этом останавливаться? После того, как вы перешли к написанию некоторого кода на VB 6, почему бы не переместить весь код в VB 6? Конечно, это мертвый язык и все такое, но VBScript тоже не слишком активен. Как я упоминал ранее, разница в синтаксисе практически равна нулю, и кривая обучения для разработчика VBScript настолько мелкая, как и следовало ожидать. Кроме того, вы получаете все преимущества полноценной среды IDE, статической типизации, (немного) лучшей обработки ошибок, бла-бла-бла. Ах да, и возможность выполнять прямые вызовы функций Windows API. Единственное реальное преимущество VBScript - его повсеместность, но прошло лет с тех пор, как вы могли найти компьютер без установленной среды выполнения VB. Не говоря уже о том, что если вы пишете приложение, для которого требуются общие диалоговые окна, вы, вероятно, участвуете в диалоге со своими пользователями: возможности форм полного VB могут в этом оказаться полезными. точка. Но, возможно, самым большим и самым важным преимуществом выбора этого пути является то, что вы избавляетесь от необходимости регистрировать (или включать) внешнюю вспомогательную DLL - простое приложение VB 6 будет работать только с EXE на любом компьютере, на котором запущен VB. -time установлен, который включен, по крайней мере, до Windows 7.

  3. И, наконец, на случай, если вы в какой-то степени взволнованы переходом от скромного VBScript к полнофункциональному VB 6, я чувствую себя обязанным добавить еще один гаечный ключ в уравнение: почему бы не перейти полностью на такой язык, как VB .СЕТЬ? Опять же, благодаря .NET Framework в VB.NET предлагаются всевозможные новые функции, но достойному разработчику VB / VBScript не потребуется больше нескольких недель, чтобы начать чувствовать себя комфортно при написании приложений на VB.NET. . У них, вероятно, не будет полного понимания .NET Framework, и они, конечно, не разработают хорошие методы объектно-ориентированного проектирования, но, по крайней мере, они будут двигаться в правильном направлении. Практически все, что вы можете сделать в VBScript (или даже VB 6), вы можете сделать в VB.NET. И в целом это требует еще меньше суеты, чем раньше, благодаря огромной функциональности, предоставляемой .NET Framework. Недостатком, конечно же, является то, что ваше приложение теперь требует, чтобы на компьютере пользователя была установлена ​​.NET Framework, что не так широко распространено, как среда выполнения VB 6 (хотя сейчас это гораздо чаще, чем даже несколько лет назад). тому назад).

Итак, я слышал, вы говорили, что это не те обходные пути, которые вы надеялись услышать? Да, я тоже. Я не тот парень, который говорит людям бросить все и выучить новый язык. Если VBScript продолжает работать на вас, действуйте. Но если вы находитесь в той точке, где вы начинаете напрягаться из-за его ограничений, вероятно, пора сделать прыжок.

person Cody Gray    schedule 19.12.2010
comment
Я лично не думаю, что рекомендовать VB 6 - хорошая идея, поскольку он был удален и не рекомендуется (то есть больше никаких исправлений безопасности). - person Nubok; 19.12.2010
comment
@Nubok: Да, согласен. Я как бы обратился к этому, особенно в третьем предложении. Но опять же, подумайте о человеке, которому адресован этот совет. Они уже используют VBScript, поэтому преимущество перехода на VB 6 заключается не в обновлении их кода, а в простом горизонтальном шаге, который дает им дополнительные технологии с почти нулевыми затратами. Кроме того, Microsoft решительно позиционирует платформу .NET (и тем более теперь с PowerShell) как устаревший VBScript - если вы сейчас не считаете его устаревшим, вы не станете рассматривать и VB 6 таким же. - person Cody Gray; 19.12.2010
comment
@Code Gray Я не совсем согласен. Хотя - как я уже заметил - обновлений безопасности для VB 6 не будет, согласно en .wikipedia.org / wiki / Active_Scripting # Deprecation Активные сценарии все еще поддерживаются группой инженеров Microsoft. - person Nubok; 20.12.2010
comment
В любом случае я обычно больше увлекаюсь C # ... Когда я использую VBScript, я просто хочу избежать накладных расходов на создание проектов и т. Д. Я надеялся, что есть быстрый способ добавить это диалоговое окно для сценария, поскольку это стандартная функция (Windows API) . Но поскольку, как вы объяснили, общего решения не существует, я буду жить без него. Спасибо. - person JayK; 21.12.2010

Секрет использования общего диалогового окна VBScript (или VBA или JScript, если на то пошло) заключается в том, что на вашем компьютере должна быть установлена ​​его лицензия. Некоторые инструменты разработки, такие как Visual Basic 6, устанавливают лицензию, но она также устанавливается с помощью бесплатного редактора справки Microsoft HTML Help Editor (это довольно старое приложение). Интересно то, что если вы установите, а затем удалите редактор HTML-справки, лицензия Common Dialog License останется на месте. По этой причине я считаю, что лицензия находится в свободном доступе, и поэтому в свой ответ я буду включать запись реестра, которую она создает здесь:

В HKLM\Software\CLASSES\Licenses\4D553650-6ABE-11cf-8ADB-00AA00C00905 установите для записи (Default) значение gfjmrfkfifkmkfffrlmmgmhmnlulkmfmqkqj.

После этого вы можете создавать эти диалоги из VBScript, используя следующий код:

Set objDialog = CreateObject("MSComDlg.CommonDialog")

Чтобы запустить диалог сохранения файла, используйте метод ShowSave, как в этом коде:

objDialog.ShowSave

Конечно, у этого объекта есть множество других методов и свойств, и вы, вероятно, захотите настроить соответствующие свойства перед запуском диалога. Например, вы можете установить фильтр файлов, чтобы в диалоговом окне отображались только определенные расширения файлов. Здесь есть хорошая ссылка на элемент управления на сайте MSDN: http://msdn.microsoft.com/en-us/library/aa259661%28v=vs.60%29.aspx.

Надеюсь это поможет. Дайте знать, если у вас появятся вопросы.

person oddacorn    schedule 16.12.2010
comment
К сожалению, на моей машине это не сработало. Мне не удалось создать объект MSComDlg.CommonDialog после установки этого ключа реестра. Я полагаю, что предварительные условия для его использования можно найти в других комментариях на этой странице (может быть, вы или sbd. Else могли бы добавить их к этому ответу?). Но даже если бы это было так, обычно нужно было бы подтвердить или проверить этот ключ реестра, который будет установлен перед созданием диалогового окна. Поправьте меня, если я ошибаюсь, пожалуйста. Тем не менее, спасибо за ваше расследование! - person JayK; 21.12.2010
comment
У меня такая же проблема, хотя я сделал то, что вы предложили в реестре. Он показывает мне сообщение об ошибке, в котором говорится, что компонент ActiveX не может создать объект: MSComDlg.CommonDialog. Мой компьютер - это Windows 7 на случай, если это может иметь какое-то отношение к этому (даже если я в этом сомневаюсь). - person Donald Duck; 23.05.2015

Если у вас есть некоторая степень контроля над системами, в которых вы будете его развертывать, и вы можете быть достаточно уверены, что в них установлена ​​справка Visual Studio или Microsoft HTML Help, вы можете использовать следующий код. :

function filedialog(filt, def, title, save)
    set dialog = CreateObject("MSComDlg.CommonDialog")
    dialog.MaxFileSize = 256
    if filt = "" then
        dialog.Filter = "All Files (*.*)|*.*"
    else
        dialog.Filter = filt
    end if
    dialog.FilterIndex = 1
    dialog.DialogTitle = title
    dialog.InitDir = CreateObject("WScript.Shell").SpecialFolders("MyDocuments")
    dialog.FileName = ""
    if save = true then
        dialog.DefaultExt = def
        dialog.Flags = &H800 + &H4
        discard = dialog.ShowSave()
    else
        dialog.Flags = &H1000 + &H4 + &H800
        discard = dialog.ShowOpen()
    end if
    filedialog = dialog.FileName
end function

Кроме того, адаптировав один из других ответов на этот вопрос в код VBScript (спасибо @oddacorn!), Вы должны добавить эту функцию, если вы не достаточно уверены, что у ваших пользователей будет VS или HTML-справка. Вызовите эту функцию при запуске программы. Не волнуйтесь, если у вас уже есть ключ; в этом случае это не имеет никакого эффекта. Это должно работать со стандартной учетной записью пользователя без прав администратора.

'Make the MSComDlg.CommonDialog class available for use. Required for filedialog function.
function registerComDlg
    Set objRegistry = GetObject("winmgmts:\\.\root\default:StdRegProv")
    objRegistry.CreateKey &H80000001, "Software\CLASSES\Licenses\4D553650-6ABE-11cf-8ADB-00AA00C00905"
    objRegistry.SetStringValue &H80000001, "Software\CLASSES\Licenses\4D553650-6ABE-11cf-8ADB-00AA00C00905", "", "gfjmrfkfifkmkfffrlmmgmhmnlulkmfmqkqj"
end function

Обратите внимание, что я адаптировал функцию filedialog из «Просмотр исходного кода» кода VBScript в HTML здесь; в современных веб-браузерах кажется, что HTML, который они используют для рендеринга образцов кода, отображается некорректно (проверено в IE 8 и Chrome). Но, к счастью, код все еще находится в View Source.

Я обнаружил одну вещь, которая была критичной для того, чтобы эта работа работала в Windows 7 (SP1, полностью пропатчен); вы должны установить dialog.MaxFileSize = 256, иначе вы получите ошибку во время выполнения.

То есть следующий код не работает в Windows 7 SP1, но, вероятно, работает в более старых версиях Windows:

Set x = CreateObject("MSComDlg.CommonDialog")
x.ShowSave
person allquixotic    schedule 01.08.2013

На http://blogs.msdn.com/b/gstemp/archive/2004/02/18/75600.aspx есть способ показать, как отобразить диалоговое окно «Сохранить как» из VBScript.

Обратите внимание, что согласно http://www.eggheadcafe.com/software/aspnet/29155097/safrcfiledlg-has-been-deprecated-by-microsoft.aspx Корпорация Майкрософт не рекомендует использовать SAFRCFileDlg.

person Nubok    schedule 13.12.2010
comment
Да, но более чем устарел. Файл DLL не входит ни в одну из версий Windows, кроме XP, так что это вряд ли готовое решение. Вы можете просто написать простую оболочку вокруг стандартного диалогового окна Win32 на C ++ или даже на C # / VB.NET и включить ее в свой сценарий, если вы собираетесь иметь внешние зависимости, такие как библиотеки DLL. - person Cody Gray; 15.12.2010

Я только что создал оболочку, связал ее с веб-сайтом asp, заставил веб-сайт прочитать направленный тег, в который я загрузил местоположение файла, и страница asp открывает диалоговое окно файла непосредственно в этом местоположении файла, с именем файла, также определенным через направленные теги. После сохранения оболочка исчезает.

Если это ограничение прямых тегов веб-сайта, например (blah.com/temp.aspx?x=0&y=2&z=3)

хранить информацию в базе данных SQL или в плоских файлах, существует масса обходных путей, но сказанное выше верно. VBS не будет сокращать его внутренне.

person Rich    schedule 11.11.2011

После долгих поисков я нашел jsShell - компонент оболочки на jsware.net . ZIP-файл содержит jsShell.dll 176 КБ, vbscript для регистрации dll в основном regsvr32.exe jsShell.dll, демонстрационные сценарии и понятную документацию.

Библиотека DLL хорошо работает в Windows 7 и предоставляет несколько полезных методов, в том числе диалоговое окно «Открыть / сохранить»:

Dim jsS, sFileName
jsS = CreateObject("jsShell.Ops")
' Save as dialog
sFileName = jsS.SaveDlg("<title>", "exe") ' Example: Filter by exe files
sFileName = jsS.SaveDlg("<title>", "")    ' Example: No extension filter
' Open dialog
' Example: Filter by exe, initial dir at C:\
sFileName = jsS.OpenDlg("<title>", "exe", "C:\")

Если файл не выбран, sFileName - пустая строка.

person Rob W    schedule 09.06.2012

Я только что нашел решение на этом сайте. Оно полностью прокомментировано и хорошо работает в Windows 10.

Вот код, который возвращает папку в виде строки (я пробовал в трех разных стартовых папках):

Option Explicit

WScript.Echo BrowseFolder( "C:\Program Files", True )
WScript.Echo BrowseFolder( "My Computer", False )
WScript.Echo BrowseFolder( "", False )


Function BrowseFolder( myStartLocation, blnSimpleDialog )
' This function generates a Browse Folder dialog
' and returns the selected folder as a string.
'
' Arguments:
' myStartLocation   [string]  start folder for dialog, or "My Computer", or
'                             empty string to open in "Desktop\My Documents"
' blnSimpleDialog   [boolean] if False, an additional text field will be
'                             displayed where the folder can be selected
'                             by typing the fully qualified path
'
' Returns:          [string]  the fully qualified path to the selected folder
'
' Based on the Hey Scripting Guys article
' "How Can I Show Users a Dialog Box That Only Lets Them Select Folders?"
' http://www.microsoft.com/technet/scriptcenter/resources/qanda/jun05/hey0617.mspx
'
' Function written by Rob van der Woude
' http://www.robvanderwoude.com
    Const MY_COMPUTER   = &H11&
    Const WINDOW_HANDLE = 0 ' Must ALWAYS be 0

    Dim numOptions, objFolder, objFolderItem
    Dim objPath, objShell, strPath, strPrompt

    ' Set the options for the dialog window
    strPrompt = "Select a folder:"
    If blnSimpleDialog = True Then
        numOptions = 0      ' Simple dialog
    Else
        numOptions = &H10&  ' Additional text field to type folder path
    End If

    ' Create a Windows Shell object
    Set objShell = CreateObject( "Shell.Application" )

    ' If specified, convert "My Computer" to a valid
    ' path for the Windows Shell's BrowseFolder method
    If UCase( myStartLocation ) = "MY COMPUTER" Then
        Set objFolder = objShell.Namespace( MY_COMPUTER )
        Set objFolderItem = objFolder.Self
        strPath = objFolderItem.Path
    Else
        strPath = myStartLocation
    End If

    Set objFolder = objShell.BrowseForFolder( WINDOW_HANDLE, strPrompt, _
                                              numOptions, strPath )

    ' Quit if no folder was selected
    If objFolder Is Nothing Then
        BrowseFolder = ""
        Exit Function
    End If

    ' Retrieve the path of the selected folder
    Set objFolderItem = objFolder.Self
    objPath = objFolderItem.Path

    ' Return the path of the selected folder
    BrowseFolder = objPath
End Function
person Alex Casal    schedule 22.04.2019
comment
Добро пожаловать в Stack Overflow, Alex Casal. Хотя эта ссылка может дать ответ на вопрос, лучше включить сюда основные части ответа и предоставить ссылку для справки. Ответы, которые представляют собой не более чем ссылку, могут быть удалены. - person Shree; 22.04.2019
comment
Это не отвечает на вопрос, поскольку предлагает диалоговое окно «Обзор папки», а не диалоговое окно «Сохранить как». Последний позволяет выбрать имя файла. Диалог в ответе нет. - person JayK; 22.04.2019

person    schedule
comment
Конечно, если бы вы действительно читали другие ответы на этот вопрос, вы бы знали, что это не решение. Он ограничен только Windows XP, операционной системой 10-летней давности, которую большинство людей больше не используют. Это ни обратная, ни прямая совместимость, довольно бесполезный подход, который явно не удовлетворяет требованиям спрашивающего. В следующий раз попробуйте более внимательно прочитать вопрос и рассмотреть другие ответы, прежде чем копировать и вставлять код, который вы найдете в другом месте в Интернете. - person Cody Gray; 06.05.2011