0

Я уже почти неделю боюсь этой проблемы. Мне нужно приложение vb6, которое запускается как служба для открытия файла. Мне не нужно ничего делать с файлом, мне просто нужно его открыть. Я попытался использовать ShellExecute и ShellExecuteEx, а также использовать CreateProcess, чтобы попытаться запустить файл из командной строки. Когда ни одна из этих реализаций не работала, я попытался вместо этого запустить другое приложение (используя CreateProcess) с единственной задачей открыть файл и затем закрыть его.VB6 - Как открыть файл из приложения, выполняемого как служба?

Эти решения все работают, когда приложение запускается нормально, но не когда оно запускается как служба. Крайне важно, чтобы приложение могло открывать файл во время работы в качестве службы, прямо или косвенно, просто должно быть способно вызвать его.

Я понимаю, что Windows заблокировала способность служб взаимодействовать с рабочим столом с Windows Vista, но я уверен, что должен быть способ запуска команды открытия файла из службы. Приложение, которое я разработал, может запустить pg_dump.exe (исполняемый файл резервной копии для баз данных postgres) из командной строки с помощью CreateProcess для резервного копирования файлов базы данных во время работы в качестве службы. Вот почему я, хотя запуск exe из службы для косвенного открытия файла, может работать. Однако по какой-то причине приложение запускает pg_dump.exe отлично, но не запускает исполняемый файл, который я создал. Мне интересно, будет ли exe, созданный мной, иметь какое-то присутствие на рабочем столе, и поэтому служба не хочет его запускать. Я изменил свойства основной формы во вторичном exe, чтобы форма не была видимой и не отображалась на панели задач, но что-то говорит мне, что этого недостаточно.

Вот мой CreateProcess код (я не пишу большую часть этого поэтому, пожалуйста, простите мое невежество):

Private Declare Function WaitForSingleObject Lib "KERNEL32" (ByVal _ 
    hHandle As Long, ByVal dwMilliseconds As Long) As Long 

Private Declare Function CloseHandle Lib "KERNEL32" _ 
    (ByVal hObject As Long) As Long 

Private Declare Function GetExitCodeProcess Lib "KERNEL32" _ 
    (ByVal hProcess As Long, lpExitCode As Long) As Long 

'create a new win process. 
Private Declare Function CreateProcessA Lib "KERNEL32" (ByVal _ 
    lpApplicationName As String, ByVal lpCommandLine As String, ByVal _ 
    lpProcessAttributes As Long, ByVal lpThreadAttributes As Long, _ 
    ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, _ 
    ByVal lpEnvironment As Long, ByVal lpCurrentDirectory As String, _ 
    lpStartupInfo As STARTUPINFO, lpProcessInformation As _ 
    PROCESS_INFORMATION) As Long 

'used by CreateProcess 
Private Type STARTUPINFO 
    cb As Long 
    lpReserved As String 
    lpDesktop As String 
    lpTitle As String 
    dwX As Long 
    dwY As Long 
    dwXSize As Long 
    dwYSize As Long 
    dwXCountChars As Long 
    dwYCountChars As Long 
    dwFillAttribute As Long 
    dwFlags As Long 
    wShowWindow As Integer 
    cbReserved2 As Integer 
    lpReserved2 As Long 
    hStdInput As Long 
    hStdOutput As Long 
    hStdError As Long 
End Type 

Private Type PROCESS_INFORMATION 
    hProcess As Long 
    hThread As Long 
    dwProcessID As Long 
    dwThreadID As Long 
End Type 

Const NORMAL_PRIORITY_CLASS = &H20& 
Const INFINITE = -1& 

Public Function ExecSynchronousCmd(cmdline As String) As Long 

    ' - Used to force a shelled command to run synchronously (code will 
    ' suspend where this function is called until shelled process 
    ' returns a return value) 
    ' - There is no time out - it will wait forever!! 
    ' - Function returns exit value for shelled process 

    Dim proc As PROCESS_INFORMATION 
    Dim start As STARTUPINFO 
    Dim ret As Long 

    'Initialize the STARTUPINFO structure: 
    start.cb = Len(start) 

    'Start the shelled application: 
    ret = CreateProcessA(vbNullString, cmdline$, 0&, 0&, 1&, _ 
     NORMAL_PRIORITY_CLASS, 0&, vbNullString, start, proc) 

    'Wait for the shelled application to finish: 
    ret = WaitForSingleObject(proc.hProcess, INFINITE) 
    Call GetExitCodeProcess(proc.hProcess, ret&) 
    Call CloseHandle(proc.hThread) 
    Call CloseHandle(proc.hProcess) 
    ExecSynchronousCmd = ret 

End Function 

Вот реализация для запуска pg_dump.exe, которая успешна при запуске ехе С обслуживания и создания резервных копий баз данных файлов:

i = ExecSynchronousCmd(Chr$(34) & "C:\Program Files (x86)\PostgreSQL\9.3\bin\pg_dump.exe" & Chr$(34) & _ 
       " -Ft " & _ 
       " -f " & Chr$(34) & tempName & Chr$(34) & _ 
       " -U " & s1 & _ 
       " -h " & s3 & _ 
       " -p " & s4 & _ 
       " " & sDB(0, x)) 

Вот такая же реализация, которая пытается запустить вторичный ехе, который попытается открыть файл в вопрос:

i = ExecSynchronousCmd(Chr$(34) & "C:\Program Files (x86)\GranDocsNP\GDNPOpener.exe" & Chr$(34)) 

Приведенный выше код не работает, когда приложение запускается как служба. Почему pg_dump.exe успешно работает, но мой собственный GDNPOpener.exe не работает?

Как я уже говорил выше, я также попытался использовать ShellExecute и ShellExecuteEx, чтобы открыть файл непосредственно из службы, которая не сработала. (Я использую ShellExecuteEx во вторичном exe (GDNPOpener.exe), чтобы открыть файл)

Если кто-нибудь знает, как исправить мой exe, чтобы мой сервис запустил его, я был бы очень благодарен за помощь! Если кто-нибудь знает какие-либо альтернативные способы открыть файл из службы, это тоже будет оценено, спасибо!

+0

Если я правильно понимаю, 'GNDPOpener.exe' - это ваш собственный код, как и сервис. Почему они являются отдельными приложениями? Почему бы вам просто не поместить код из «GNDPOpener.exe» непосредственно в службу? –

+0

Поскольку служба не хочет открывать файл напрямую. Поэтому я решил, что если я заставлю службу запустить другое приложение, возможно, это приложение сможет открыть файл, поскольку он НЕ работает как служба и не будет подвергаться тем же ограничениям. Тем не менее, не только служба не может открыть файл, но также не может запустить вторичное приложение (что странно, потому что, как я сказал в моем первоначальном вопросе, он, похоже, способен запустить pg_dump.exe fine) – user2437443

+1

Определить " откройте файл ", потому что я думаю, вы имеете в виду нечто совершенно иное, чем это действительно означает. Я предполагаю, что вы пытаетесь запустить какую-либо другую программу, которая делает что-то вроде чтения файла и отображает его на каком-то рабочем столе пользователя в другом сеансе (возможно, в сеансе 1), и этого вы не можете сделать. В противном случае, если вы действительно имеете в виду * open *, у вас проблема с файловой безопасностью. – Bob77

ответ

4

Вы не можете просто вызвать Shellexecute() в контексте процесса, выполняющегося как служба. Даже если это удается (никогда не тестировалось), запущенное приложение/документ все равно не будет отображаться на рабочем столе зарегистрированного пользователя, поскольку это два разных сеанса, изолированных друг от друга (если только вы не находитесь в Windows XP или Windows Server 2003, для них службы & приложения для консольного сеанса работают в сеансе 0, но служба по-прежнему должна быть помечена как интерактивная для взаимодействия с рабочим столом).

См. http://blogs.technet.com/b/askperf/archive/2007/04/27/application-compatibility-session-0-isolation.aspx или выполните поиск «Изоляция сеанса 0» для получения более подробной информации об этой концепции.

Для решения этой проблемы, у вас есть в основном два варианта: (! ** если я пропустил один, не стесняйтесь исправлять меня)

  1. Используйте маршрут клиент/сервер;

    например. Вы можете написать небольшую утилиту, которая будет запускаться в пользовательском пространстве (например, запущена при запуске сеанса) и связываться с вашей службой по некоторому выбору межпроцессного взаимодействия (IPC, именованные каналы, сопоставленная память и т. Д.). Затем ваша служба может попросить утилиту открывать файлы в контексте зарегистрированного пользователя (например, это будет утилита, которая вызывает ShellExecute()).

    Чтобы узнать, с чего начать, найдите примеры межпроцессных коммуникаций, написанных для VB6.

    ВАЖНО: Поскольку сервер (ваш сервис) и клиент (в пространстве пользователя утилиты) будут взаимодействовать между сеансами и под разными маркерами пользователя, обратите внимание на указания по дескрипторы безопасности, используемых и прав доступа, необходимых при создании и доступ к каналам связи (именованный канал и т. д.), чтобы не допустить, чтобы ваш клиент получил ошибки «отказались».

    ВНИМАНИЕ: Обычные предупреждения о безопасности, связанные с риском эскалации привилегий, применяются здесь. Поскольку вы в основном «открываете дверь» в свою службу, проявляйте особую осторожность, чтобы не допускать, чтобы какое-либо приложение-изгоев, представляющее ваш клиент/утилиту, чтобы контролировать ваш сервис (переполнение буфера и т. Д.) Или заставить его делать то, что он не должен делать ,

  2. Используйте специальные API для запуска процессов в разных сеансах;

    В зависимости от (1) работает ли ваш сервис под учетной записью LocalSystem или другой учетной записью администратора; (2) о том, хотите ли вы запустить документ/приложение в контексте зарегистрированного пользователя или вам не нужно создавать новый сеанс и (3) иметь ли у вас учетные данные пользователя (пользователь + пароль) или нет , существует несколько API-интерфейсов, которые позволяют службе связываться с рабочим столом или запускать приложение в контексте другого пользователя.

    Ознакомьтесь с API CreateProcessAsUser(), CreateProcessWithLogonW(), WTSQueryUserToken() и сопутствующими, или найдите примеры, используя их. Кроме того, следующая статья может быть полезной: Launching an interactive process from Windows Service in Windows Vista and later

Надеюсь, что ответьте на ваш вопрос! По крайней мере, это должно дать вам указания о том, что делать дальше.

+0

В вопросе о том, что OP хочет, чтобы приложение было видимым на рабочем столе входа в систему, не существует никаких указаний или даже, что в момент запуска приложения обязательно будет зарегистрирован любой пользователь. –

+0

Я не согласен, я думаю, это то, что он пытается сделать. Как минимум, он пытается позволить ОС запускать программу, связанную с типом файла из службы. Простой IPC отлично справится с этим, если он разворачивает второй исполняемый файл, который автоматически запускается в контексте зарегистрированного пользователя, чтобы поймать уведомление и выполнить команду. – tcarvin

Смежные вопросы