Reputation: 2330
In my program I need to open a file using an external application (Bentley MicroStation, if it's important). I need application with the opened file to be invisible to user (I will perform some operations over it).
The way to open a file using Process seems fine except for one thing - tests over "example.txt" or "example.doc" show that even when ProcessStartInfo property WindowStyle is set to Minimized or Hidden nevertheless you see the application with opened file.
So, how can I open file without showing my operations to user? Of course, it is possible to hide the app window afterwards, but that's not what I need...
Upd. I work with Bentley MicroStation XM edition. It has a splash screen that can be disabled.
The main problem: when starting MicroStation via Process and ProcessStartInfo with command line argument (name of file to open) and various settings like WindowsStyle (Hidden), UseShellExecute (false), CreateNoWindow (true) application window is present and visible. Simple test with win api WinExec with uCmdShow set to 0 (hidden) gives the same result.
Any solution for starting application in background mode is accepted. Thanks in advance.
Upvotes: 2
Views: 3157
Reputation: 1
If you want to hide the Microstation window, you have to create a Microstation app by mdl or .net addin, in which you can do your job, and which Microstation will load and run. then you can create a microstation in a non-graphic mode.
Upvotes: 0
Reputation: 221997
It seems to me the most simple way to implement your requirements is to start new process on the other windows desktop. Default process pesktop is "WinSta0\Default". With respect of CreateDesktop Function you can create new desktop for example with the name "MyDesktop" and then start proccess on the desktop.
Following code demonstrate the technique:
using System;
using System.Text;
using System.Runtime.InteropServices;
using System.ComponentModel;
namespace HiddenDesktop {
class Program {
static void Main (string[] args) {
string desktopName = "MyDesktop";
string appPath = @"%SystemRoot%\system32\cmd.exe";
string parameters = @"/c dir C:\ >%TEMP%\dir.txt";
IntPtr hDesktop = IntPtr.Zero;
NativeMethods.ProcessInformation processInfo = new NativeMethods.ProcessInformation ();
bool isSuccess;
try {
hDesktop = NativeMethods.CreateDesktop (desktopName, null, null, 0,
NativeMethods.ACCESS_MASK.MAXIMUM_ALLOWED, null);
if (hDesktop == IntPtr.Zero) {
DisplayLastErrorMessage ();
return;
}
NativeMethods.StartupInfo startupInfo = new NativeMethods.StartupInfo ();
NativeMethods.CreateProcessFlags dwCreationFlags = NativeMethods.CreateProcessFlags.NormalPriorityClass;
startupInfo.cb = Marshal.SizeOf (typeof (NativeMethods.StartupInfo));
startupInfo.lpDesktop = "WinSta0\\" + desktopName;
string currentDirectory = Environment.CurrentDirectory;
appPath = Environment.ExpandEnvironmentVariables (appPath);
//if (appPath.IndexOf (' ') != -1)
// appPath = '\"' + appPath + '\"';
StringBuilder sbParameters = new StringBuilder (3 + appPath.Length + parameters.Length);
if (appPath.IndexOf (' ') != -1) {
sbParameters.Append ('\"');
sbParameters.Append (appPath);
sbParameters.Append ('\"');
}
else
sbParameters.Append (appPath);
sbParameters.Append (' ');
sbParameters.Append (parameters);
// appPath - full path to the exe without having " if the file has blanks in the path
isSuccess = NativeMethods.CreateProcess (appPath,
sbParameters.ToString(), IntPtr.Zero, IntPtr.Zero, false, dwCreationFlags,
IntPtr.Zero, currentDirectory, ref startupInfo, out processInfo);
if (!isSuccess) {
DisplayLastErrorMessage ();
return;
}
NativeMethods.CloseHandle (processInfo.hThread);
processInfo.hThread = IntPtr.Zero;
if (NativeMethods.WaitForSingleObject (processInfo.hProcess, NativeMethods.Infinite) == NativeMethods.WaitObject0) {
Console.WriteLine ("the process is ended");
}
}
finally {
if (processInfo.hThread != IntPtr.Zero)
isSuccess = NativeMethods.CloseHandle (processInfo.hThread);
if (processInfo.hProcess != IntPtr.Zero)
isSuccess = NativeMethods.CloseHandle (processInfo.hProcess);
if (hDesktop != IntPtr.Zero)
isSuccess = NativeMethods.CloseDesktop (hDesktop);
}
}
static void DisplayLastErrorMessage () {
int errorCode = Marshal.GetLastWin32Error ();
Win32Exception error32 = new Win32Exception (errorCode);
Console.WriteLine ("Error {0}: {1}", errorCode, error32.Message);
}
}
internal static class NativeMethods {
internal const int NoError = 0;
internal const UInt32 Infinite = 0xFFFFFFFF;
internal const UInt32 WaitAbandoned = 0x00000080;
internal const UInt32 WaitObject0 = 0x00000000;
internal const UInt32 WaitTimeout = 0x00000102;
[Flags]
internal enum ACCESS_MASK : uint {
DELETE = 0x00010000,
READ_CONTROL = 0x00020000,
WRITE_DAC = 0x00040000,
WRITE_OWNER = 0x00080000,
SYNCHRONIZE = 0x00100000,
STANDARD_RIGHTS_REQUIRED = 0x000f0000,
STANDARD_RIGHTS_READ = 0x00020000,
STANDARD_RIGHTS_WRITE = 0x00020000,
STANDARD_RIGHTS_EXECUTE = 0x00020000,
STANDARD_RIGHTS_ALL = 0x001f0000,
SPECIFIC_RIGHTS_ALL = 0x0000ffff,
ACCESS_SYSTEM_SECURITY = 0x01000000,
MAXIMUM_ALLOWED = 0x02000000,
GENERIC_READ = 0x80000000,
GENERIC_WRITE = 0x40000000,
GENERIC_EXECUTE = 0x20000000,
GENERIC_ALL = 0x10000000,
DESKTOP_READOBJECTS = 0x00000001,
DESKTOP_CREATEWINDOW = 0x00000002,
DESKTOP_CREATEMENU = 0x00000004,
DESKTOP_HOOKCONTROL = 0x00000008,
DESKTOP_JOURNALRECORD = 0x00000010,
DESKTOP_JOURNALPLAYBACK = 0x00000020,
DESKTOP_ENUMERATE = 0x00000040,
DESKTOP_WRITEOBJECTS = 0x00000080,
DESKTOP_SWITCHDESKTOP = 0x00000100,
WINSTA_ENUMDESKTOPS = 0x00000001,
WINSTA_READATTRIBUTES = 0x00000002,
WINSTA_ACCESSCLIPBOARD = 0x00000004,
WINSTA_CREATEDESKTOP = 0x00000008,
WINSTA_WRITEATTRIBUTES = 0x00000010,
WINSTA_ACCESSGLOBALATOMS = 0x00000020,
WINSTA_EXITWINDOWS = 0x00000040,
WINSTA_ENUMERATE = 0x00000100,
WINSTA_READSCREEN = 0x00000200,
WINSTA_ALL_ACCESS = 0x0000037f
}
[StructLayout (LayoutKind.Sequential)]
public class SECURITY_ATTRIBUTES {
public int nLength;
public IntPtr lpSecurityDescriptor;
public int bInheritHandle;
}
[StructLayout (LayoutKind.Sequential)]
internal struct ProcessInformation {
internal IntPtr hProcess;
internal IntPtr hThread;
internal int dwProcessId;
internal int dwThreadId;
}
[StructLayout (LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct StartupInfo {
internal Int32 cb;
internal string lpReserved;
internal string lpDesktop;
internal string lpTitle;
internal Int32 dwX;
internal Int32 dwY;
internal Int32 dwXSize;
internal Int32 dwYSize;
internal Int32 dwXCountChars;
internal Int32 dwYCountChars;
internal Int32 dwFillAttribute;
internal Int32 dwFlags;
internal Int16 wShowWindow;
internal Int16 cbReserved2;
internal IntPtr lpReserved2;
internal IntPtr hStdInput;
internal IntPtr hStdOutput;
internal IntPtr hStdError;
}
[Flags]
internal enum CreateProcessFlags : uint {
DebugProcess = 0x00000001,
DebugOnlyThisProcess = 0x00000002,
CreateSuspended = 0x00000004,
DetachedProcess = 0x00000008,
CreateNewConsole = 0x00000010,
NormalPriorityClass = 0x00000020,
IdlePriorityClass = 0x00000040,
HighPriorityClass = 0x00000080,
RealtimePriorityClass = 0x00000100,
CreateNewProcessGroup = 0x00000200,
CreateUnicodeEnvironment = 0x00000400,
CreateSeparateWowVdm = 0x00000800,
CreateSharedWowVdm = 0x00001000,
CreateForcedos = 0x00002000,
BelowNormalPriorityClass = 0x00004000,
AboveNormalPriorityClass = 0x00008000,
InheritParentAffinity = 0x00010000,
InheritCallerPriority = 0x00020000, // Deprecated
CreateProtectedProcess = 0x00040000,
ExtendedStartupinfoPresent = 0x00080000,
ProcessModeBackgroundBegin = 0x00100000,
ProcessModeBackgroundEnd = 0x00200000,
CreateBreakawayFromJob = 0x01000000,
CreatePreserveCodeAuthzLevel = 0x02000000,
CreateDefaultErrorMode = 0x04000000,
CreateNoWindow = 0x08000000,
ProfileUser = 0x10000000,
ProfileKernel = 0x20000000,
ProfileServer = 0x40000000,
CreateIgnoreSystemDefault = 0x80000000,
}
[DllImport ("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern IntPtr CreateDesktop (
string desktopName,
string device, // must be null.
string deviceMode, // must be null,
int flags, // use 0
ACCESS_MASK accessMask,
SECURITY_ATTRIBUTES attributes);
[DllImport ("user32.dll", SetLastError = true)]
[return: MarshalAs (UnmanagedType.Bool)]
internal static extern bool CloseDesktop (IntPtr hDesktop);
[DllImport ("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[return: MarshalAs (UnmanagedType.Bool)]
internal static extern bool CreateProcess (string lpApplicationName, string lpCommandLine, IntPtr lpProcessAttributes, IntPtr lpThreadAttributes,
bool bInheritHandles, CreateProcessFlags dwCreationFlags, IntPtr lpEnvironment,
string lpCurrentDirectory, ref StartupInfo lpStartupInfo, out ProcessInformation lpProcessInformation);
[DllImport ("kernel32.dll", SetLastError = true)]
[return: MarshalAs (UnmanagedType.Bool)]
internal static extern bool CloseHandle (IntPtr hObject);
[DllImport ("kernel32.dll", SetLastError = true)]
internal static extern UInt32 WaitForSingleObject (IntPtr hHandle, UInt32 dwMilliseconds);
}
}
Upvotes: 3