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

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

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

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

Я могу получить диалог открытия, но нет ShowSave метод для этого объекта (как и для аналогичного объекта в Visual Basic, не являющийся сценарием).

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

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

8 ответов

Решение

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

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

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

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

Тем не менее, вот несколько возможных обходных путей:

  1. Если вы склонны принять какой-либо из уже предложенных ответов, вы уже решили ввести внешнюю зависимость от файла DLL в свое развертывание VBScript. После того, как вы совершили этот скачок, зачем беспокоиться о "заимствовании" или хищении DLL из какого-либо другого источника? Просто сделай однажды себя. Это тривиально обернуть встроенные общие диалоговые функции, предоставляемые API-интерфейсом Windows, в библиотеку 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 and 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 установлен во время выполнения, который включен по крайней мере через 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 продолжает работать для вас, пойти на это. Но если вы находитесь в той точке, когда вы начинаете напрягаться при ее ограничениях, возможно, пришло время совершить скачок.

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

В 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.

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

Если у вас есть некоторый уровень контроля над системами, на которых вы будете его развертывать, и можете быть достаточно уверены, что на них установлена ​​либо 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 Help. Вызовите эту функцию при запуске программы. Не волнуйтесь, если у вас уже есть ключ; в этом случае это не имеет никакого эффекта. Это должно работать на стандартной учетной записи пользователя без прав администратора.

'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 из "View Source" кода 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

После долгих поисков я нашел 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 пустая строка

На 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 устарела Microsoft.

Private Sub cmdB1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles cmdB1.Click
    Dim objExec, strMSHTA, wshShell, SelectFile

    SelectFile = ""

    ' For use in HTAs as well as "plain" VBScript:
    strMSHTA = "mshta.exe ""about:" & "<" & "input type=file id=FILE>" _
             & "<" & "script>FILE.click();new ActiveXObject('Scripting.FileSystemObject')" _
             & ".GetStandardStream(1).WriteLine(FILE.value);close();resizeTo(0,0);" & "<" & "/script>"""

    wshShell = CreateObject("WScript.Shell")
    objExec = wshShell.Exec(strMSHTA)

    SelectFile = objExec.StdOut.ReadLine()
    Me.txtT0.Text = SelectFile
    objExec = Nothing
    wshShell = Nothing
    strMSHTA = Nothing
End Sub

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

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

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

Я только что нашел решение на этом сайте, оно полностью прокомментировано и хорошо работает в 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
Set objDialog = CreateObject( "SAFRCFileDlg.FileSave" )

' Note: If no path is specified, the "current" directory will
'       be the one remembered from the last "SAFRCFileDlg.FileOpen"
'       or "SAFRCFileDlg.FileSave" dialog!
objDialog.FileName = "test_save.vbs"
' Note: The FileType property is cosmetic only, it doesn't
'       automatically append the right file extension!
'       So make sure you type the extension yourself!
objDialog.FileType = "VBScript Script"
If objDialog.OpenFileSaveDlg Then
    WScript.Echo "objDialog.FileName = " & objDialog.FileName
End If
Другие вопросы по тегам