Как я могу использовать общий диалог Сохранить как из VBScript? - PullRequest
17 голосов
/ 08 декабря 2010

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

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

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

Iможет получить диалоговое окно Open, но для этого объекта нет метода ShowSave (как, по-видимому, для аналогичного объекта в не скриптовом Visual Basic).

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

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

Ответы [ 9 ]

11 голосов
/ 16 декабря 2010

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

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

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

Set objDialog = CreateObject("MSComDlg.CommonDialog")

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

objDialog.ShowSave

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

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

7 голосов
/ 19 декабря 2010

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

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

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

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

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

  1. Если вы склонны принять какой-либо из уже предложенных ответов, вы уже решили ввести внешнюю зависимость от DLL-файла в ваше развертывание VBScript. После того, как вы совершили этот скачок, зачем беспокоиться о «заимствовании» или хищении DLL из какого-либо другого источника? Просто сделай однажды себя. Это тривиально, чтобы обернуть встроенные общие функции диалога, предоставляемые API Windows, в DLL ActiveX с помощью 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. Но теперь, когда я убедил вас всех написать DLL ActiveX в 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? Опять же, благодаря .NET Framework, в VB.NET предлагаются всевозможные новые функции, но для того, чтобы приличный разработчик VB / VBScript почувствовал себя комфортно при написании приложений на VB.NET, не потребуется более нескольких недель. , Вероятно, у них не будет полного понимания .NET Framework, и они, конечно, не разработают хорошие методы объектно-ориентированного проектирования, но, по крайней мере, они будут двигаться в правильном направлении. Почти все, что вы можете сделать в VBScript (или даже VB 6), вы можете сделать в VB.NET. И вообще, это требует еще меньше суеты, чем раньше, благодаря огромной функциональности .NET Framework. Недостатком, конечно же, является то, что вашему приложению теперь требуется установить .NET Framework на компьютер пользователя, что не так широко распространено, как во время выполнения VB 6 (хотя сейчас это происходит гораздо чаще, чем даже через несколько лет). назад).

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

4 голосов
/ 01 августа 2013

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

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 из "View Source" кода VBScript в HTML здесь ; в современных веб-браузерах кажется, что HTML, который они используют для визуализации образцов кода, отображается некорректно (протестировано в IE 8 и Chrome). Но, к счастью, код все еще есть в View Source.

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

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

Set x = CreateObject("MSComDlg.CommonDialog")
x.ShowSave
0 голосов
/ 22 апреля 2019

Я только что нашел решение в на этом сайте Он полностью прокомментирован и хорошо работает в 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
0 голосов
/ 25 сентября 2014
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
0 голосов
/ 09 июня 2012

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

0 голосов
/ 11 ноября 2011

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

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

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

0 голосов
/ 06 мая 2011
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
0 голосов
/ 14 декабря 2010

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

...