Page 1 of 2 12 LastLast
Results 1 to 40 of 63

Thread: Redirect Process Input/Output with Windows API

  1. #1

    Thread Starter
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Redirect Process Input/Output with Windows API

    If you ever have a situation where you cannot use the built-in Process class to launch a process (like if you need to launch the process with a specific access token for example) but you need to be able to redirect the input and output (StdIn and StdOut) of the process to your own program then this should help you out. This only really applies if you are wanting to launch and interact with console applications because GUI applications dont tend to ever look at StdIn or StdOut.
    It is not very straight forward and took me ages to get it working so I would certainly advise people to try and use the built in Process class and its redirection abilities wherever possible rather than using this method... but as mentioned above, unfortunately there are some scenarios where this is not possible.

    Ive attached the project files for a demo application I've written that lets you launch a process, send text input to it, and read its output in a background thread. I have added loads of comments to it but feel free to ask if you have any questions about how it works.
    See end of post for attached project files, but here's an example of what it does:



    So as you can see in the example above, I've launched command prompt (hidden) and sent the command "dir" to it (which makes it list all files and folders in the current folder) then sent the command "exit" which makes the command prompt terminate itself, and the program realises and shows an appropriate message.


    There are a few quirks, which are as follows:
    --- On Windows XP some characters in the output do not get displayed correctly - no idea why this is, as I had the same issue on Windows 7 but then I changed the encoding of the text to the encoding that command prompt uses (cp850) rather than ASCII and that sorted it out on Windows 7 but made no difference on XP. Its only some special characters so most people probably wont ever notice this.
    --- Telnet does not want to work at all, even though every other program I've tried does.
    --- On Windows XP the output for some commands doesnt have line breaks where it should - ipconfig is the main one I've had issues with. Its still usable, just a bit harder to read because everything is on one line (wrapped). Again this is not an issue on Windows 7.


    This code uses the following Windows APIs:
    CreatePipe
    ReadFile (for reading the pipe, not a file )
    WriteFile (same as above)
    CloseHandle
    DuplicateHandle
    CreateProcess
    PeekNamedPipe
    WaitForMultipleObjects
    which have of course all been added to my Windows API library that I'm writing see here for more details - http://www.vbforums.com/showthread.php?p=3813700

    Project files for redirection demo attached below.
    Attached Files Attached Files
    Last edited by chris128; Jun 12th, 2010 at 05:01 PM.
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


  2. #2
    Stack Overflow mod​erator
    Join Date
    May 2008
    Location
    British Columbia, Canada
    Posts
    2,824

    Re: Redirect Process Input/Output with Windows API

    When wouldn't you be able to use the built-in class? Just wondering.

  3. #3

    Thread Starter
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Re: Redirect Process Input/Output with Windows API

    When you want to use an access token (http://msdn.microsoft.com/en-us/libr...(v=VS.85).aspx) to launch the process as a specific user without having to provide the user's username and password (its not as unsecure as it sounds lol)
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


  4. #4
    Addicted Member
    Join Date
    Oct 2009
    Location
    Oshawa
    Posts
    214

    Re: Redirect Process Input/Output with Windows API

    Alright Chris, I'm back and I'm going to redirect the input/output through a named pipe over the network I'll let you know how it goes.

  5. #5

    Thread Starter
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Re: Redirect Process Input/Output with Windows API

    Cool almost a year ago exactly since I posed this thread lol I've been doing some work recently with launching processes in the user's session from a service on Windows 7 (as services run in their own session in Vista/Win7 and therefore any programs they launch will not be seen by the user). You may well already have a feature like that working (or might not be interested in the user seeing the new process) but if it helps I've put some of the code on my blog here: http://cjwdev.wordpress.com/2011/06/...-on-windows-7/

    Let me know if it looks like it might be useful to you and I'll send you the source code for an app I wrote recently that uses this, as the code on the blog is just a basic example that doesn't deal with setting up the user's environmental variables for the new process and doesn't close all of the handles that need closing.
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


  6. #6
    Addicted Member
    Join Date
    Oct 2009
    Location
    Oshawa
    Posts
    214

    Re: Redirect Process Input/Output with Windows API

    I've had the remote execution going for about a year now but they were solely interactive processes although the nice thing is that I could pull the security token from the Explorer process and launch the application as the currently logged in user which is one feature that isn't included in most tools. Probably a security risk for corporations to some extent seeing as with that token I could impersonate and decrypt any data I want access to but it's pretty interesting.

    I spent the last 2 days figuring out how to incorporate your example into mine. After a ton of research and trial/error it seems that the only possible way to re-direct the standard output/input through a named pipe is to first create a standard pipe and associate the handles the way you have to the process. First you need to create a server pipe on the client side of the application. As the output is being obtained from the process, you can connect to it from the server side and provide the output. I now have this working both ways for the input and output. I'm about half way done compiling a library that I have absolutely no problem with sharing with everyone which will allow you to call a single static function to create a new process remotely. There are 2 events so far which indicate when standard output has been received and when process details have been received by the client end of the named pipe so that you can hook onto those events and output them to a textbox or whatever you want.

    I still need to add in the code to launch the application as the SYSTEM account and as the currently logged in user because I decided to completely re-do this tool in C# instead of VB as I found that my level of understanding this API has considerably increased since switching languages.

    I will be sure to update you as soon as possible. This is my main focus now because I need to incorporate this function into another large application I’ve developed.

  7. #7

    Thread Starter
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Re: Redirect Process Input/Output with Windows API

    thanks for the update, look forward to seeing the finished library. By the way you don't have to grab the access token from explorer, you can just use WTSQueryUserToken and pass in the user's session ID (which you can get from WTSGetActiveConsoleSessionId). I haven't seen your code but all the other examples I've seen online where people get the token from explorer they then have to mess around duplicating the handle and doing various other things, so personally I find this method to be neater but hey if your code is working fine as it is then probably no point changing it.
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


  8. #8
    Banned
    Join Date
    Mar 2009
    Posts
    764

    Re: Redirect Process Input/Output with Windows API

    what is telnet (mentioned in post #1) ?

  9. #9
    Addicted Member
    Join Date
    Oct 2009
    Location
    Oshawa
    Posts
    214

    Re: Redirect Process Input/Output with Windows API

    I'm actually going to try out those 2 methods you have mentioned instead because I've been hearing that some virtual Windows environments have several explorer.exe processes running on the same machine which would definately cause a problem. I'd prefer to obtain the access token another way so that this tool can be used in these scenarios as well.

    The finished library will contain the remote server executable embeded as a resource. The client will make a copy of the executable on the remote systems Admin$ share, create and start a new service using WMI, start a command pipe server loop to accept process start commands to obtain process information and StdIn commands to redirect to the process itself. The client just has a single loop to send out the required process information and then it creates a new named pipe server to receive StdOut data along with process start and termination return values. So I'm hoping that once this is complete, anyone can just import my library and call a function like

    public static Create(string Username, string Password, string Domain, string Process, string Arguements, bool StartInteractive, bool PromptUser, bool WaitForProcessExit)

    and then hook onto these 2 events

    private delegate void StdInData_Received(object sender, StdInData_Received_EventArgs e);
    public static event StdInData_Received StdInData_Received_Event;

    private delegate void ProcessInfo_Received(object sender, ProcessInfo_Received_EventArgs e);
    public static event ProcessInfo_Received ProcessInfo_Received_Event;


    and receive the string data from the custom event arguement class making it easy to update a textbox or whatever and nothing to really customize other than your interface.

    Afterwards the server notifies the client to stop processing and the client will stop and remove the service and delete the server executable. I also coded it so that it will accept a maximum of 10 connections to the named pipe server in order to run several processes remotely on the same machine at a time. The server just keeps track of the processes in an array and communicates the index back to the client. When the client sends commands back it states which part of the array contains the process it is working with. When a process exits, it loops through all of the other process arrays and notifies each client that the array has been resized and what the new index is for it's processing. But now that I think of it, I forgot to make the client re-create it's server pipe with the new index number. I haven't had too much time to test everything yet because I did most of this all from scratch in less than a days worth of time. Also having to port from VB to C# can be annoying because of some of the syntax. In your example you have a line when sending commands to the StdIn Pipe that uses something like String & VbCrLf & VbCr. Well I got stuck for probably an hour because of it. LoL. C# it was String + "\r\n\r";

  10. #10

    Thread Starter
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Re: Redirect Process Input/Output with Windows API

    haha yeah its always the stupid little things that take a long time :P

    As for the multiple explorer.exe processes, that will only happen if multiple people are logged on (which can happen easily on Windows 7 as it now supports fast user switching even on a domain, or on any server running Terminal Services). So you need to think about how you want to handle that situation - if your app is supposed to launch a process interactively so that the logged on user can see it, what should it do if multiple people are logged on? Should it just launch it for the person logged on to the console session (which is usually the person physically sat at the machine using it, but in the case of terminal servers this will often be no one as only admins would ever log on to the console session), or should it launch the process once for every logged on user, or should it just fail because it is impossible to know which session to launch the process in? The method I outlined in that blog post will just launch the process in the console session. I'll post the source code for my app that uses this technique in another post in a sec. I've only tested it on Windows 7 though as all of our machines at work are now Windows 7, so no idea if it will work on XP correctly.

    Oh and also I would loose the WMI stuff - a lot of places don't allow WMI through their workstations firewalls plus WMI is generally considered quite slow (and in my experience unreliable). You could just use the CreateService API (its in my Windows API Library if you are interested) as I believe that only requires the same ports to be open in the firewall that would already need to be open for you to get to the ADMIN$ share. Test it out though obviously, as it may also require the Remote Registry service to be running, which it isnt by default in Windows 7 (but you can easily start the service remotely from your code if not). Which brings me on to my next point...

    Make sure you test this on XP and Windows 7 if you are going to be offering this to the developer community to use, as there are major differences between the two when talking about services and you will probably find you need to do things slightly differently depending on which OS the code is running on.
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


  11. #11

    Thread Starter
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Re: Redirect Process Input/Output with Windows API

    Here's the code for the app I wrote that is purely designed to launch a specified process in the desktop session of the logged on user (the console session user):

    vb.net Code:
    1. Imports Cjwdev.WindowsApi
    2.  
    3. Module MainModule
    4.  
    5.     Private Sub ShowUsage()
    6.         Console.WriteLine("Launches a process in the currently logged on user's desktop session (and" & vbNewLine & "security context) when called from a Windows service running as Local System" & vbNewLine & vbNewLine & _
    7.                           "StartInConsoleSession.exe [/W] cmdpath arguments" & vbNewLine & vbNewLine & _
    8.                           "  cmdpath" & vbTab & vbTab & "The full path to the executable file to be launched" & vbNewLine & _
    9.                           "  arguments" & vbTab & vbTab & "The arguments to pass to the executable file specified" & vbNewLine & vbTab & vbTab & vbTab & "in cmdpath. If any arguments contain spaces then they" & vbNewLine & vbTab & vbTab & vbTab & "must be enclosed in speech marks" & vbNewLine & _
    10.                           "  /W" & vbTab & vbTab & vbTab & "Wait for the launched process to exit before returning" & vbNewLine & vbNewLine & vbNewLine & _
    11.                           "EXAMPLES:" & vbNewLine & _
    12.                           "StartInConsoleSession.exe C:\Windows\System32\Notepad.exe ""C:\Some File.txt""" & vbNewLine & _
    13.                           "Launches Notepad and opens the file C:\Some File.txt" & vbNewLine & vbNewLine & _
    14.                           "StartInConsoleSession.exe /W C:\Windows\System32\cmd.exe" & vbNewLine & _
    15.                           "Launches command prompt and waits for it to exit before returning" & vbNewLine)
    16.     End Sub
    17.  
    18.  
    19.     Sub Main()
    20.         Console.WriteLine(vbNewLine & "StartInConsoleSession.exe" & vbNewLine & _
    21.                           "Version " & My.Application.Info.Version.ToString & vbNewLine & _
    22.                           "Developed by Chris Wright (cwright@cjwdev.co.uk)" & vbNewLine)
    23.  
    24.         'Check for valid command line arguments
    25.         If (My.Application.CommandLineArgs.Count < 1) OrElse (My.Application.CommandLineArgs.Count = 1 AndAlso String.Compare(My.Application.CommandLineArgs(0), "/w", True) = 0) Then
    26.             ShowUsage()
    27.             Exit Sub
    28.         End If
    29.  
    30.         Try
    31.             Dim CommandLine As String = String.Empty
    32.             Dim FirstArg As Integer = 0
    33.             Dim WaitForExit As Boolean = False
    34.  
    35.             'Build command line string for the process we will launch
    36.             'Check to see if the first argument is /w as this means we want to wait for the newly launched process to exit
    37.             If String.Compare(My.Application.CommandLineArgs(0), "/w", True) = 0 Then
    38.                 CommandLine = """" & My.Application.CommandLineArgs(1) & """"
    39.                 FirstArg = 2
    40.                 WaitForExit = True
    41.             Else
    42.                 CommandLine = """" & My.Application.CommandLineArgs(0) & """"
    43.                 FirstArg = 1
    44.             End If
    45.  
    46.             'Get all other arguments and add them to the final command line string
    47.             For i As Integer = FirstArg To My.Application.CommandLineArgs.Count - 1
    48.                 CommandLine &= " """ & My.Application.CommandLineArgs(i) & """"
    49.             Next
    50.  
    51.             'Attempt to launch the process in the currently logged on user's session
    52.             LaunchProcessInConsoleSession(CommandLine, WaitForExit)
    53.         Catch ex As Exception
    54.             Console.WriteLine("Unexpected error: " & ex.Message)
    55.         End Try
    56.     End Sub
    57.  
    58.     Private Sub LaunchProcessInConsoleSession(ByVal CommandLine As String, ByVal WaitForExit As Boolean)
    59.         Console.WriteLine("Command line = " & CommandLine & vbNewLine & "Wait for exit = " & WaitForExit.ToString)
    60.         Dim UserTokenHandle As IntPtr = IntPtr.Zero
    61.         Dim EnvironmentBlock As IntPtr = IntPtr.Zero
    62.         Dim ProcInfo As New ApiDefinitions.PROCESS_INFORMATION
    63.  
    64.         'Not much point in adding comments here, just read the Console.WriteLine strings
    65.         Try
    66.             Console.WriteLine("Attempting to get console session ID...")
    67.             Dim ConsoleSessionId As UInteger = ApiDefinitions.WTSGetActiveConsoleSessionId
    68.             Console.WriteLine("Console session ID = " & ConsoleSessionId)
    69.  
    70.             Console.WriteLine("Attempting to get handle to primary access token of console session user...")
    71.             Dim QueryTokenResult As Boolean = ApiDefinitions.WTSQueryUserToken(ConsoleSessionId, UserTokenHandle)
    72.             If QueryTokenResult AndAlso Not UserTokenHandle = IntPtr.Zero Then
    73.                 Console.WriteLine("Primary token handle successfully obtained")
    74.             Else
    75.                 Console.WriteLine("Failed to get handle to primary token, the last error reported was: " & New ComponentModel.Win32Exception().Message)
    76.                 Exit Sub
    77.             End If
    78.  
    79.             Console.WriteLine("Creating environmental variable block for user...")
    80.             Dim CreateEnvironmentResult As Boolean = ApiDefinitions.CreateEnvironmentBlock(EnvironmentBlock, UserTokenHandle, False)
    81.             If CreateEnvironmentResult AndAlso Not EnvironmentBlock = IntPtr.Zero Then
    82.                 Console.WriteLine("Successfully created environmental variable block")
    83.             Else
    84.                 Console.WriteLine("Failed to create environmental variable block for user, the last error reported was: " & New ComponentModel.Win32Exception().Message)
    85.                 Exit Sub
    86.             End If
    87.  
    88.             Dim StartInfo As New ApiDefinitions.STARTUPINFO
    89.             StartInfo.cb = CUInt(Runtime.InteropServices.Marshal.SizeOf(StartInfo))
    90.  
    91.             Console.WriteLine("Attempting to launch process...")
    92.             'Launch the new process, using the user's token we obtained from WTSQueryUserToken means it will be launched in their session and we pass in the
    93.             'environmental variable block we got from CreateEnvironmentBlock so that the new application gets all of the normal environmental variables that
    94.             'a process launched by that user would normally get. Also specify CREATE_NEW_CONSOLE so that command line applications will not inherit the console
    95.             'from this application (which will be running in another session so will not work correctly)
    96.             Dim CreateProcessResult As Boolean = ApiDefinitions.CreateProcessAsUser(UserTokenHandle, Nothing, CommandLine, IntPtr.Zero, IntPtr.Zero, False, ApiDefinitions.CREATE_UNICODE_ENVIRONMENT Or ApiDefinitions.CREATE_NEW_CONSOLE, EnvironmentBlock, Nothing, StartInfo, ProcInfo)
    97.             'Check the result and see if a process was actually launched
    98.             If CreateProcessResult AndAlso Not ProcInfo.dwProcessId = 0 Then
    99.                 Console.WriteLine("Process successfully launched in console session (Process ID = " & ProcInfo.dwProcessId & ")")
    100.             Else
    101.                 Console.WriteLine("Failed to launch process, the last error reported was: " & New ComponentModel.Win32Exception().Message)
    102.             End If
    103.         Finally
    104.             'Clean up, close handles
    105.             If Not UserTokenHandle = IntPtr.Zero Then
    106.                 ApiDefinitions.CloseHandle(UserTokenHandle)
    107.             End If
    108.             If Not ProcInfo.hProcess = IntPtr.Zero Then
    109.                 ApiDefinitions.CloseHandle(ProcInfo.hProcess)
    110.             End If
    111.             If Not ProcInfo.hThread = IntPtr.Zero Then
    112.                 ApiDefinitions.CloseHandle(ProcInfo.hThread)
    113.             End If
    114.             If Not EnvironmentBlock = IntPtr.Zero Then
    115.                 ApiDefinitions.DestroyEnvironmentBlock(EnvironmentBlock)
    116.             End If
    117.         End Try
    118.  
    119.         'Wait for the process to exit if that has been requested
    120.         If WaitForExit AndAlso Not ProcInfo.dwProcessId = 0 Then
    121.             Dim LaunchedProcess As Process = Nothing
    122.             Try
    123.                 LaunchedProcess = Process.GetProcessById(CInt(ProcInfo.dwProcessId))
    124.             Catch ex As ArgumentException
    125.                 Console.WriteLine("Process has terminated")
    126.             End Try
    127.             If Not LaunchedProcess Is Nothing Then
    128.                 Console.WriteLine("Waiting for process to exit...")
    129.                 LaunchedProcess.WaitForExit()
    130.                 Console.WriteLine("Process has terminated")
    131.             End If
    132.         End If
    133.  
    134.     End Sub
    135.  
    136.  
    137.  
    138. End Module
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


  12. #12
    Addicted Member
    Join Date
    Oct 2009
    Location
    Oshawa
    Posts
    214

    Re: Redirect Process Input/Output with Windows API

    Nice, I'm going to try that out once I get around to adding the option to launch as the current user into my tool. Thanks Chris. I can't wait to get this finished! lol. Need more time in a day.

  13. #13
    Addicted Member
    Join Date
    Oct 2009
    Location
    Oshawa
    Posts
    214

    Re: Redirect Process Input/Output with Windows API

    Hey Chris,

    I really need some help right now. I haven't tried your last posting yet because I'm having an issue with the named pipe.

    The client side application opens a server based "Response" pipe for new output from the server and process information.

    The server side just has the server based "Command Pipe" to accept new commands.

    If I run the server on a remote machine with the same account as the client, the communication back and forth between the 2 server pipes works perfectly. When I start the server on the remote machine as the SYSTEM account and host it as a service, when the server tries to reply back to the client's SERVER pipe, it get's the access denied message because the default security descriptor of the named pipe created on the client side is using defaults which doesn't include a remote machines SYSTEM account.

    I managed to create a new security descriptor and pass it to the SECURITY_ATTRIBUTES structure but when I call CreateNamedPipe it fails indicating that I am accessing protected memory.

    Code:
            [DllImport("kernel32.dll", SetLastError = true)]
            static extern IntPtr CreateNamedPipe(string lpName, uint dwOpenMode,
               uint dwPipeMode, uint nMaxInstances, uint nOutBufferSize, uint nInBufferSize,
               uint nDefaultTimeOut, SECURITY_ATTRIBUTES lpSecurityAttributes);
    The orginal API import set the lpSecurityAttributes type as an IntPtr and the creation of the pipe was fine. I changed it to the SECURITY_ATTRIBUTES type instead so I can pass the new security attributes with the custom security descriptor.

    Code:
    [DllImport("Advapi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = false)]         
            private static extern bool ConvertStringSecurityDescriptorToSecurityDescriptor([In] string StringSecurityDescriptor, [In] uint StringSDRevision, [Out] out IntPtr SecurityDescriptor, [Out] out int SecurityDescriptorSize); 
    
    private const string SECURITYDESCRIPTORSTRING = "O:WDG:WDD:(A;;FA;;;WD)";
    
                /////////////testing
                IntPtr securityDescriptorPtr = IntPtr.Zero;
                int securityDescriptorSize = 0;
    
                bool Result = ConvertStringSecurityDescriptorToSecurityDescriptor(SECURITYDESCRIPTORSTRING, 1, out securityDescriptorPtr, out securityDescriptorSize);
                
                SECURITY_ATTRIBUTES SA = new SECURITY_ATTRIBUTES();
                SA.nLength = Marshal.SizeOf(SA);
                SA.bInheritHandle = false;
                SA.lpSecurityDescriptor = securityDescriptorPtr;
                /////////////////////////
    
    
                //Create the command pipe handle.
                int PipeHandle = CreatePipe("\\\\.\\pipe\\nRPInPipe" + RemoteProcessIndex.ToString(), (uint)BUFFERSIZE, 10, SA);    
    
            private static int CreatePipe(string PipeName, uint BUFFERSIZE, uint MaxConnections, SECURITY_ATTRIBUTES SecurityAttributes)
            {
                uint openMode = (int)PIPE_ACCESS_DUPLEX | (uint)FILE_FLAG_WRITE_THROUGH;
                uint pipeMode = PIPE_WAIT | PIPE_TYPE_MESSAGE;
    
                return CreateNamedPipe(PipeName, openMode, pipeMode, MaxConnections, BUFFERSIZE, BUFFERSIZE, 10000, SecurityAttributes).ToInt32();
            }
    If I change the API import back to an IntPtr type for the securityattributes and pass IntPtr.zero, it will work fine to create the pipe but with the securityattributes that are useless for what I want to do.

    Do you know how to either create a new IntPtr to reference the SA structure that's being passed so I can use my original API or do you know why it is failing in the creation of the pipe when I pass the structure to it? Just so you know, the ConvertStringSecurityDescriptorToSecurityDescriptor is working fine and is returning the intptr to the security descriptor that was created.

    Please help, lol. I've been trying to figure this out for hours now.

  14. #14

    Thread Starter
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Re: Redirect Process Input/Output with Windows API

    I'm not great with C# so sorry if you are already doing this and I just can't see it, but it sounds like you need to pass that argument (the SECURITY_ATTRIBUTES one) in ByRef rather than ByVal. I can explain why if you want but just try it first and see if it fixes the problem

    EDIT: Just did some googling to see how you pass arguments ByRef in C# so I can give you an example of what I think you need to do now. Basically just change this line:

    Code:
     
    return CreateNamedPipe(PipeName, openMode, pipeMode, MaxConnections, BUFFERSIZE, BUFFERSIZE, 10000, SecurityAttributes).ToInt32();
    to this:

    Code:
    return CreateNamedPipe(PipeName, openMode, pipeMode, MaxConnections, BUFFERSIZE, BUFFERSIZE, 10000, ref SecurityAttributes).ToInt32();
    Last edited by chris128; Jun 23rd, 2011 at 03:21 PM.
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


  15. #15
    Addicted Member
    Join Date
    Oct 2009
    Location
    Oshawa
    Posts
    214

    Re: Redirect Process Input/Output with Windows API

    Hi Chris, I actually just figured it out. Now the only problem is my security descriptor string. I'll let you know as soon as possible.

  16. #16

    Thread Starter
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Re: Redirect Process Input/Output with Windows API

    Ah ok cool, was it what I said?

    Oh and I hope you realise you have proper hijacked this thread now haha
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


  17. #17
    Addicted Member
    Join Date
    Oct 2009
    Location
    Oshawa
    Posts
    214

    Re: Redirect Process Input/Output with Windows API

    LoL, sorry about the hi-jacking. I got it to work properly now. Communication is working perfectly between the 2 server pipes.

    First it was the structure for the SECURITY_ATTRIBUTES. Had to change it to a class like so.

    [StructLayout(LayoutKind.Sequential)]
    internal class SECURITY_ATTRIBUTES
    {
    public int nLength;
    public SafeLocalMemHandle lpSecurityDescriptor;
    public bool bInheritHandle;
    }

    I found a million examples of people having issues with this and had to combine info from a lot of them.

    the lpSecurityDescriptor was change from an intptr to a custom class type "SafeLocalMemHandle".

    Code:
            [SuppressUnmanagedCodeSecurity,
            HostProtection(SecurityAction.LinkDemand, MayLeakOnAbort = true)]
            internal sealed class SafeLocalMemHandle : SafeHandleZeroOrMinusOneIsInvalid
            {
                public SafeLocalMemHandle()
                    : base(true)
                {
                }
    
                public SafeLocalMemHandle(IntPtr preexistingHandle, bool ownsHandle)
                    : base(ownsHandle)
                {
                    base.SetHandle(preexistingHandle);
                }
    
                [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success),
                DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
                private static extern IntPtr LocalFree(IntPtr hMem);
    
                protected override bool ReleaseHandle()
                {
                    return (LocalFree(base.handle) == IntPtr.Zero);
                }
            }
    and also my API had to be changed for CreateNamedPipe

    Code:
            [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            public static extern IntPtr CreateNamedPipe(string pipeName,
                uint openMode, uint pipeMode, int maxInstances,
                int outBufferSize, int inBufferSize, uint defaultTimeout,
                SECURITY_ATTRIBUTES securityAttributes);
    Then my SECURITYDESCRIOPTORSTRING

    private const string SECURITYDESCRIPTORSTRING = "D:A;OICI;GRGW;;;WD)";


    And the API to convert the security descriptor string into a pointer.

    Code:
            [return: MarshalAs(UnmanagedType.Bool)]
            [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            public static extern bool ConvertStringSecurityDescriptorToSecurityDescriptor(
                string sddlSecurityDescriptor, int sddlRevision,
                out SafeLocalMemHandle pSecurityDescriptor,
                IntPtr securityDescriptorSize);

    Then the rest of the code worked.

    Code:
                SafeLocalMemHandle securityDescriptorPtr = null;
                
                bool Result = ConvertStringSecurityDescriptorToSecurityDescriptor(SECURITYDESCRIPTORSTRING, 1, out securityDescriptorPtr, IntPtr.Zero);
                
                SECURITY_ATTRIBUTES SA = new SECURITY_ATTRIBUTES();
                SA.nLength = Marshal.SizeOf(SA);
                SA.bInheritHandle = false;
                SA.lpSecurityDescriptor = securityDescriptorPtr;
                /////////////////////////
                
                //Create the command pipe handle.
                int PipeHandle = CreatePipe("\\\\.\\pipe\\nRPInPipe" + RemoteProcessIndex.ToString(), BUFFERSIZE, 10, SA);

  18. #18

    Thread Starter
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Re: Redirect Process Input/Output with Windows API

    You didn't need to make the structure a class you could just pass the structure in ByRef, has the same effect. The reason it didnt work as a structure originally is because the API expects a pointer to one of these structures, not the actual structure itself - which is why it works when you define the argument as IntPtr and not when you pass in the structure.

    Structures are "Value" Types and classes are "Reference" Types - meaning when you pass a structure around you are passing the actual data, but when you pass a class around you are passing in a pointer to the data. My suggestion of passing the structure in ByRef (or just "ref" in C#) means that it will pass in a pointer to the structure - and equally by changing it to be a class instead of a structure you have achieved the same thing, as classes always get a pointer to them passed in (if you were to pass in a class ByRef then you would be using a pointer to a pointer).

    You can't always use your method of just changing the structure to a class in every scenario, which is why I'm explaining all this

    Glad to hear it is all working anyway! I'm going to be making something very similar in the near future so I'm sure this will all come in handy
    Last edited by chris128; Jun 23rd, 2011 at 03:53 PM.
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


  19. #19
    Addicted Member
    Join Date
    Oct 2009
    Location
    Oshawa
    Posts
    214

    Re: Redirect Process Input/Output with Windows API

    Hi Chris,

    Actually, before I started messing around with everything, the only thing I did was try to pass the structure byref to the API function. This didn't work either. It may be though that the class for the SecurityDescriptor that I found is what was causing the problem. I don't know but I got it working, lol. Good to know about classes being entirely passed by reference and structures by value. I'm sure I read that already at some point but I forgot:P

    Now I've realized why I had 2 separate executables for the server side. The function CreateProcessWithLogonW doesn't work properly from a processes launched by the local SYSTEM account but obtaining the currently logged on users security token first and launching a second "server type" processes embedded into the original server allows you to call CreateProcessWithLogonW under that users account, no matter if they have admin rights or not, and allows you to launch an application as another domain user.

    If you have any suggestions for as to why I can't use this function under the SYSTEM account, please let me know. I'm not going to use that code provided to obtain the current users security token.

  20. #20

    Thread Starter
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Re: Redirect Process Input/Output with Windows API

    Don't use CreateProcessWithLogon then, use CreateProcessAsUser - this definitely works from a service running as Local System on Windows 7 as I used it the other day. No idea how well it works on XP though.
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


  21. #21
    Addicted Member
    Join Date
    Oct 2009
    Location
    Oshawa
    Posts
    214

    Re: Redirect Process Input/Output with Windows API

    Hi Chris,

    I tried your suggestion of using CreateProcessAsUser. It seems that it works perfectly fine to launch an interactive process on the remote desktop from the SYSTEM account but as soon as I try re-directing the standard output and input, etc, the process starts and then ends fairly quick with a startup code of 0 and an exit code of 0. The redirection of the output works perfectly fine use CreateProcess. Any ideas? I want to be able to launch the process interactive for use on the remote system and non-interactive, in which it re-directs the output to my named pipe back to the client. Very strange.

  22. #22

    Thread Starter
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Re: Redirect Process Input/Output with Windows API

    I think I recall having a similar problem when I was writing the code in the original post in this thread, I'm sure it was something to do with the handles to the named pipe being inherited (or not being inherited) by the child process. Sorry I can't give you anything more specific than that...

    EDIT:
    I think that's what this bit of the code was for:
    vb.net Code:
    1. 'Duplicate the "write end" handle for the input pipe and make the duplicated handle non inheritable
    2.         If Not WindowsAPIs.DuplicateHandle(New HandleRef(Me, Process.GetCurrentProcess.Handle), TmpWriteInputHandle, _
    3.                                New HandleRef(Me, Process.GetCurrentProcess.Handle), CurrentInputHandle, 0, False, WindowsAPIs.DUPLICATE_SAME_ACCESS) Then
    4.             Throw New System.ComponentModel.Win32Exception
    5.         End If
    6.  
    7.         'Duplicate the "read end" handle for the output pipe and make the duplicated handle non inheritable
    8.         If Not WindowsAPIs.DuplicateHandle(New HandleRef(Me, Process.GetCurrentProcess.Handle), TmpReadOutputHandle, _
    9.                                New HandleRef(Me, Process.GetCurrentProcess.Handle), CurrentOutputHandle, 0, False, WindowsAPIs.DUPLICATE_SAME_ACCESS) Then
    10.             Throw New System.ComponentModel.Win32Exception
    11.         End If
    12.  
    13.         'Close the original handles we got from CreatePipe before we start the process so that it does
    14.         'not inherit these handles.
    15.         TmpReadOutputHandle.Close()
    16.         TmpWriteInputHandle.Close()
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


  23. #23
    Addicted Member
    Join Date
    Oct 2009
    Location
    Oshawa
    Posts
    214

    Re: Redirect Process Input/Output with Windows API

    Hi Chris,

    I already have the duplication of the handles in place in the same manor. I'm going to try this actually and see if it works. Very strange because the same code works fine with just CreateProcess.

    1. use WTSGetActiveConsoleSessionId to get the ID of the current active Windows session at the console (i.e. the machine keyboard and display, as opposed to WTS sessions).

    2. use WTSQueryUserToken to get the token for that session.

    3. use DuplicateTokenEx(hToken,MAXIMUM_ALLOWED,NULL,SecurityIdentification,TokenPrimary, &hTokenDup) to duplicate that token.

    4. use CreateEnvironmentBlock to create an environment that you will be passing to the process.

    5. use CreateProcessAsUser with the duplicated token and the created environment. Actually, we use CreateProcessAsUserW, since the A version had some sort of bug on some older systems.

    6. Don't forget to CloseHandle on the various tokens, etc, and to DestroyEnvironmentBlock the environment.

  24. #24
    Addicted Member
    Join Date
    Oct 2009
    Location
    Oshawa
    Posts
    214

    Re: Redirect Process Input/Output with Windows API

    Hi Chris,

    After 3 days of messing around with this, I finally got CreateProcessAsUser to launch a process as another domain user under the system account and can perform this operation interactively and non-interactively.

    Code:
                        IntPtr hProcessToken = IntPtr.Zero;                                        
                        TOKEN_PRIVILEGES tp = new TOKEN_PRIVILEGES();
    
                        tp.Privileges = new LUID_AND_ATTRIBUTES[1];
                                          
                        Result = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, ref hProcessToken);
    
                        if (!Result | hProcessToken == IntPtr.Zero)
                            Console.WriteLine("OpenProcessToken Failed: " + Marshal.GetLastWin32Error());
    
                        Result = LookupPrivilegeValue(null, SE_TCB_NAME, ref tp.Privileges[0].Luid);
    
                        if (!Result)
                            Console.WriteLine("LookupPrivilegeValue Failed: " + Marshal.GetLastWin32Error());
    
                        tp.PrivilegeCount = 1;
                        tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    
                        Result = AdjustTokenPrivileges(hProcessToken, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
    
                        if (!Result)
                            Console.WriteLine("AdjustTokenPrivileges Failed: " + Marshal.GetLastWin32Error());
    
                        Result = LogonUser(p.Process.UserName.Split('\\')[1], p.Process.UserName.Split('\\')[0], p.Process.Password, (int)Logon32Type.Interactive, 0, out hProcessToken);
    
                        Result = CreateProcessAsUserW(hProcessToken, Process, string.Empty, SA, SA, true, (UInt32)32, IntPtr.Zero, System.IO.Directory.GetCurrentDirectory(), si, ref ProcessInfo);

  25. #25
    Addicted Member
    Join Date
    Oct 2009
    Location
    Oshawa
    Posts
    214

    Re: Redirect Process Input/Output with Windows API

    Hi Chris,

    And now I've finally got the option to launch the process as the currently logged in user working interactively and non-interactively.

    Code:
                        uint ConsoleSessionId = WTSGetActiveConsoleSessionId();                                     
                        
                        IntPtr lpBuffer = IntPtr.Zero;
                        int Count = 0 ;                    
                        //IntPtr i;
                                            
                        Result = WTSQueryUserToken(ConsoleSessionId, out UserToken);
                                            
                        if (!Result)
                            Console.WriteLine("WTSQueryUserToken Failed: " + Marshal.GetLastWin32Error());
    
                        //If no token obtained then no one is logged onto the console. Check for active remote desktop session.
                        if (UserToken == IntPtr.Zero)
                        {
                            Result = Convert.ToBoolean(WTSEnumerateSessions(IntPtr.Zero, 0, 1, ref lpBuffer, ref Count));
    
                            int dataSize = Marshal.SizeOf(typeof(WTS_SESSION_INFO));
    
                            Int64 current = (int)lpBuffer;
                                                    
                            if (Result)
                            {
                                for (int i = 0; i < Count; i++)
                                {
                                    WTS_SESSION_INFO session = (WTS_SESSION_INFO)Marshal.PtrToStructure((IntPtr)current, typeof(WTS_SESSION_INFO));
    
                                    current += dataSize;
    
                                    if (session.State == WTS_CONNECTSTATE_CLASS.WTSActive)
                                        Result = WTSQueryUserToken((uint)session.SessionID, out UserToken);
    
                                    if (!Result)
                                        Console.WriteLine("WTSQueryUserToken Failed: " + Marshal.GetLastWin32Error());                                
                                }
                                                                                    
                                WTSFreeMemory(lpBuffer);                                                      
                            }
    Now I can complete the easy stuff and soon I'll have a library available for use within anyone else's .Net application that functions just like PSEXEC on WinXP machines. I haven't had a chance to test on any newer OS's yet but this is working perfectly now without requiring the use of a second executable.

  26. #26

    Thread Starter
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Re: Redirect Process Input/Output with Windows API

    Cool, glad to hear you got it all working You may find you run into problems on Vista/Win7 though as services work a bit differently in that they all run in a dedicated isolated session (session 0). Let me know how it goes though
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


  27. #27
    Addicted Member
    Join Date
    Oct 2009
    Location
    Oshawa
    Posts
    214

    Re: Redirect Process Input/Output with Windows API

    This is the reason why I created a second executable to run with the server service to launch a new gui application as a different user. Now I have to do this again.

    http://stackoverflow.com/questions/2...ui-application

  28. #28

    Thread Starter
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Re: Redirect Process Input/Output with Windows API

    I dont see why you need a second executable though, I mean why launch that second executable instead of just launching whatever process that executable is going to launch directly? The way I see it you either do this:
    Service.exe -> [USER'S SESSION] -> Launcher.exe -> TargetProgram.exe
    or just do this:
    Service.exe -> [USER'S SESSION] -> TargetProgram.exe

    Unless I'm missing something... I know I managed to get the second approach working on Windows 7 without a problem. In fact launching a GUI app in the user's session directly from a service was easier than having the service launch a command line app that then launched the GUI app in the user's session because of console inheritance issues.
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


  29. #29
    Addicted Member
    Join Date
    Oct 2009
    Location
    Oshawa
    Posts
    214

    Re: Redirect Process Input/Output with Windows API

    Service.exe -> [CURRENTLY LOGGED IN USER's SESSION]-> TargetGUIApplication.exe works fine.

    Service.exe -> [LOGONUSER ALTERNATE CREDENTIALS]->TargetGUIApplication.exe does not work. It launches the program it shows up transparent and you can't use the GUI application.

    Service.exe -> [LOGONUSER ALTERNATE CREDENTIALS]->TargetConsoleApplication.exe works perfectly fine.

    It seems that Service processes running as SYSTEM can't properly launch GUI applications interactively so therefore I will have to do...

    Service.exe -> [CURRENTLY LOGGED IN USER's SESSION] -> Launcher.exe -> [LOGONUSER ALTERNATE CREDENTIALS] -> TargetGUIApplication.exe

  30. #30

    Thread Starter
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Re: Redirect Process Input/Output with Windows API

    Oh right, that seems odd... I might have a play around and see if I can get it working.
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


  31. #31
    Addicted Member
    Join Date
    Oct 2009
    Location
    Oshawa
    Posts
    214

    Re: Redirect Process Input/Output with Windows API

    Let me know if you do so I can eliminate this second server executable. LoL

  32. #32
    Addicted Member
    Join Date
    Oct 2009
    Location
    Oshawa
    Posts
    214

    Re: Redirect Process Input/Output with Windows API

    Hey Chris do you know off hand what character string would be used to send a return code to the stdin without specifying a command first. I currently use command + "\r\n" + "\r" but remOving the command prefix doesn't send a new carriage return.

  33. #33

    Thread Starter
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Re: Redirect Process Input/Output with Windows API

    Sorry I'm not quite sure what you mean - can you explain and give me some examples?
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


  34. #34
    Addicted Member
    Join Date
    Oct 2009
    Location
    Oshawa
    Posts
    214

    Re: Redirect Process Input/Output with Windows API

    Lol sorry I'm in training at work right now. In your examPle to redirect input and output, the writefile function to send input to the process has a carriage return and a line feed followed by another carriage return suffixing the string to send to the process.

  35. #35

    Thread Starter
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Re: Redirect Process Input/Output with Windows API

    Yeah but I don't get what you mean when you say "send a return code to stdin". If you want to send a number to it then just send it as a string - but I'm assuming you already know that so I think I'm missing something
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


  36. #36
    Addicted Member
    Join Date
    Oct 2009
    Location
    Oshawa
    Posts
    214

    Re: Redirect Process Input/Output with Windows API

    Ok, I'm back at my desk now. What I was trying to say is how can I send just a single carriage return to the stdin handle without any actual data.

    Code:
            public static void SendInput(string message, ref RemoteProcessPipes.CommandPipeData p)
            {
                if (p.CurrentProcessHandle != null && !p.stdIn.IsClosed)
                {
                    byte[] MessageBytes = Encoding.GetEncoding(850).GetBytes(message + "\r\n" + "\r");
                    uint BytesWriten = 0;
    
                    if (!WriteFile(p.stdIn, MessageBytes, (uint)MessageBytes.Length - 1, ref BytesWriten, 0))
                        OutPipe.Connect(@"\\" + p.ClientHostName + @"\pipe\nRPInPipe" + p.Index.ToString(), "There was a problem sending input to the process. The last error reported was: " + new System.ComponentModel.Win32Exception().Message);
    
                    p.ThreadSignal.Set();
                }
                else
                    OutPipe.Connect(@"\\" + p.ClientHostName + @"\pipe\nRPInPipe" + p.Index.ToString(), "No process to send input to");
            }
    as you can see, the message is converted into bytes with a \r\n ,"vbcrlf", + a \r, "vbcr", suffixing the message. What if I just want to send the carriage return only. For instance, if the remote process is using a Console.ReadLine(), waiting for a carriage return, I want to send just the "\r\n" + "\r" but it doesn't seem to work.

  37. #37

    Thread Starter
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Re: Redirect Process Input/Output with Windows API

    This works perfectly fine for me to make a program that is waiting for input (e.g console.readline) continue

    vb Code:
    1. Dim MessageBytes() As Byte = System.Text.Encoding.GetEncoding(850).GetBytes(vbCrLf & vbCr)

    This is what you get for switching to C#
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


  38. #38
    Addicted Member
    Join Date
    Oct 2009
    Location
    Oshawa
    Posts
    214

    Re: Redirect Process Input/Output with Windows API

    LoL, Ok, I'm gonna try to figure this one out then. Almost out of time for the day, lol. I switched to C# mostly because every job I look for out their in relation to programming are looking for C# .Net programmers. Not too many VB programmer positions around here. At least if I know both of them, and master 1 of them, I should be good

  39. #39

    Thread Starter
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Re: Redirect Process Input/Output with Windows API

    Yeah I was only joking lol I have the luxury of working for myself (when it comes to programming anyway) so I can use whatever language I want, but if I was thinking of going for a programming job I would certainly learn C#
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


  40. #40
    Addicted Member
    Join Date
    Oct 2009
    Location
    Oshawa
    Posts
    214

    Re: Redirect Process Input/Output with Windows API

    Ok, Chris, I'm stuck.

    Just so you know, I don't use ANY WMI API for the windows service component of this tool.

    The main problem is that after I create a service on a remote machine, I can't start it on a Windows 7 machine....This all works perfect on XP.

    The error during the startup process returns 1053, "The service did not respond to the start or control request in a timely fashion".

    It seems that the same error is reported when you try to start the same service using the windows management console.

    This is the code that starts the service...

    Code:
    	
    	[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    	private static extern bool StartService(IntPtr hService, Int32 dwNumServiceArgs, string lpServiceArgVectors);
    
    public static bool Start(IntPtr p_Service)
    	{
    		if (StartService(p_Service, 0, null) == true) {
    			return true;
    		} else {
    			Console.WriteLine("Error starting service: Error#" + Marshal.GetLastWin32Error().ToString());
    			return false;
    		}
    	}
    I'm assuming that this is more a problem with the service executable rather than the way I'm trying to start the process? Do you have any ideas because I've found way to many google results for this error without any solutions. Is it because the windows service is trying to be run with the interactive service option turned on?

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width