Windows Shell Automation InvokeVerb based on number instead of command string - c#

Normally shell automation InvokeVerb only accepts a string command, based on the documentation here: https://msdn.microsoft.com/en-us/library/ms723189(v=vs.85).aspx
However I noticed a cmd line EXE utility that accepts a number instead
http://www.technosys.net/products/utils/pintotaskbar
This is interesting because in Windows 10 "&Pin to taskbar" is removed from shell automation, despite being visible in the UI. ( https://connect.microsoft.com/PowerShell/feedback/details/1609288/pin-to-taskbar-no-longer-working-in-windows-10 )
However with this EXE passing the "number" 5386 as the command works.
I am interested to know what methods can be used to achieve this in either PowerShell/VBScript/.NET language or Win32 C/C++.
I understand this is almost certainly unsupported and likely to break any time as these numbers have changed between OS releases.
An example using the string version in PowerShell
$filepath = "C:\windows\system32\notepad.exe"
$path = Split-Path $FilePath
$shell= New-Object -com "Shell.Application"
$folder=$shell.Namespace($path)
$item = $folder.Parsename((split-path $FilePath -leaf))
$item.InvokeVerb("&Pin to taskbar")

The underlying shell context menu extension system actually works with numeric IDs natively; string verbs are an optional layer on top. However as you observe, command IDs are internal to a context menu extension and are not guaranteed to stay the same between versions (or even between invocations) - the whole point of verbs is that they allow commands to be invoked programatically irrespective of their ID.
In C/C++ you can invoke a command by its ID by casting the numeric ID as a string pointer (the rationale being that since all valid string pointers are higher than 65535, it's "safe" to pass a number as a string pointer as long as it fits into 16 bits, since the receiving API is able to correctly determine whether it is a "real string" or not).
Note that this is different from printing the number as a string, which is not correct. The MAKEINTRESOURCE macro exists for exactly this purpose.
E.g., a command with ID 1234 would be invoked using MAKEINTRESOURCE(1234) as the verb.

I ran into the same problem these days, in a Windows Script Host based script.
Invoking the verb with the localized string didn't work as it used to.
However you can still get the item's "Verbs" collection and then enumerate them until you get the verb you want to invoke. Then you can invoke it using it's "DoIt" method, without the need to pass the verbs name in.
In a WSH JScript it looks like this:
/* workaround for 'item.InvokeVerb("&Delete")' which no longer works */
var verbs = item.Verbs(); // item == return of folder.ParseName(..)
for (var x = 0; x < verbs.Count; x++)
{
var verb = verbs.Item(x);
if (verb.Name == "&Delete") //replace with "&Pin to taskbar"
{
try
{
verb.DoIt();
WSH.Echo ("Deleted:", item.Name);
}
catch(e)
{
WSH.Echo ("Error Deleting:", item.Name + "\r\n\t", e.description, e.number);
}
break;
}
}
}
Likely it also works somehow in PowerShell
ffr:
https://learn.microsoft.com/en-us/windows/win32/shell/folderitem-verbs
https://learn.microsoft.com/en-us/windows/win32/shell/folderitemverb

Related

Changing the current working directory of cmd (from a child process)

So I am trying to write a cd -like program that can be executed using cmd and after it exits the working directory of the calling cmd process should be changed.
Now before this post is flagged as a duplicate: I am aware of this and this question that were asked for pretty much this exact problem but using Linux instead of Windows as well as being pretty broad and unspecific, and I am aware that similar limitations apply to Windows as well (changing the working directory of my process will not change the parent’s working directory).
There is actually is a working solution to this for linux. However it is using gdb for this, and I would like to achieve this task using only built-in Windows utilities (WinAPI, dotNET, etc.).
What I have tried so far
I did manage to use Cheat Engine and the OpenProcess() / WriteProcessMemory() WinAPI funtions to successfully override cmd's working directory. However this solution feels sloppy and doesn't work well (or at least requires more work to be put into.)
My question
Is there a different (maybe simpler?) way on Windows to achieve this? Like a way to invoke/inject code to the cmd process to execute cd whatever\directory\I\want directly without overriding its memory? I have seen the CreateRemoteThread() functions however I didn't manage to find a way to put them to use.
FYI: I am mainly using C# but C/C++ solutions should help too as long as they are based on the native Microsoft libraries.
This post describes a Windows implementation of a function that launches a child process, creates pipes to stdin and stdout from which a command is sent, and a response is returned. Finally, once all response is captured the child process is terminated. If this sounds familiar it is similar in concept to Linux's popen() function with the exception that this implementation was specifically created to capture the response into a buffer of any command that returns one. (Also included is a variant for use when no-response is expected or needed.)
The full source can be adapted for use within a standalone executable, or as an API. (.dll) Either way, the resulting functions accept and process any command using standard Windows CMD syntax. The function cmd_rsp(...) returns the Windows response via stdout into a self-sizing buffer.
The exported prototypes are:
int __declspec(dllexport) cmd_rsp(const char *command, char **chunk, unsigned int size);
int __declspec(dllexport) cmd_no_rsp(const char *command);
A simple use case when capturing a response:
#include "cmd_rsp.h"
int main(void)
{
char *buf = {0};
buf = calloc(100, 1);//initialize to some initial size
if(!buf)return 0;
cmd_rsp("dir /s", &buf, 100);//buffer will grow to accommodate response as needed.
printf("%s", buf);
free(buf);
return 0;
}
A simple use case when response is not needed:
#include "cmd_rsp.h"
int main(void)
{
cmd_no_rsp("cd C:\\dir1\\dir2");
return 0;
}
A detailed description of purpose and usage is described in the link provided above. To illustrate, here are a few sample command inputs, each in this case change the working directory, then execute a command from that directory:
A command to change to sqlite directory, then execute a query:
cd c:\\tempExtract\\sqlite\\Tools\\sqlite-tools-win32-x86-3250300 && sqlite3.exe .\\extract.db \"select * from event, eventdata where eventType=38 and eventdata .eventid=event.eventid\
A command to change to teraterm directory, then execute a script:
"c:\\Program Files (x86)\\teraterm\" && ttpmacro c:\\DevPhys\\LPCR_2\\play\\Play.ttl
A command to change directory then execute a command to send multiple digital acquisition channel settings.
cd C:\\Dir1\\Dir2\\Dir3\\support\\Exes\\WriteDigChannel && .\\WriteDigChannel.exe P1_CH0 1 && .\\WriteDigChannel.exe P1_C H0 0 && .\\WriteDigChannel.exe P1_CH0 1
A recursive directory search from a specified location:
cd C:\\dir1\\dir2 && dir /s /b
I got it working. As was suggested SendInput finally did the trick.
I used a combination of WinAPI calls to GetForegroundWindow() / SetForegroundWindow() and the Windows Forms System.Windows.Forms.SendKeys.SendWait() Method to achieve what I wanted:
Upon calling my cd-wrapper program (sd.exe) and providing my custom target directory (~/ home) it generates the corresponding command along with the "Enter-Pressed-Event" to be sent to it's parent cmd process.
Here's the complete C# code:
if (args.Length != 1)
{
Console.WriteLine(Directory.GetCurrentDirectory());
return;
}
string targetDirectory = args[0];
string command = string.Empty;
if (targetDirectory.Equals("~"))
{
command = #"pushd C:\Users\fred\Desktop";
}
else if (!Directory.Exists(targetDirectory))
{
Console.WriteLine("I/O Error: No such file or directory.");
return;
}
else
{
command = #"cd " + targetDirectory;
}
Target target = Target.Create(Process.GetCurrentProcess().GetParentProcess());
target.SendKeys(command + "{ENTER}", true);
Note that I kind of started to write a complete Framework for this and similar problems alongside this project that contains all my different approaches to this question and the low level WinAPI calls as well as the Extension methods to get the parent process :D
As it would be a bit overkill to paste all of it's code in this answer, here's the GitHub. If I can find the time I'll go ahead and optimize the code, but for now this'll do. Hope this helps anyone encountering a similar problem :)
Edit:
An even "cleaner" way is to use dll injection to directly make cmd switch it's working directory. While it is a lot harder to get working it has the advantage of not littering the cmd command history as compared to the approach described above. In addition to that cmd seems to be aware of any changes to it's current working directory, so it automatically updates the prompt text. Once I have a fully working example, that allows to dynamically specify the target directory I will post it here :)

How to make a registry entry using C# cake?

I need to create a registry entry based on finding of 32/64-bit system from cake script. I can see the File operations reference, Directory operations reference in C# cake site. But i could not find the registry related reference in C# cake. Could anyone please let me know is there any option to make a registry entry using C# cake? If so, please specify the reference link. This will help me a lot to continue in cake script.
An alternative to using C# you could also be using the Reg.exe shipped with all major versions of Windows.
You could use this tool with Cake using StartProcess alias.
An example of doing this below:
DirectoryPath system32Path = Context.Environment
.GetSpecialPath(SpecialPath.Windows)
.Combine("System32");
FilePath regPath = system32Path.CombineWithFilePath("reg.exe");
string keyName = "HKEY_CURRENT_USER\\Software\\Cake";
string valueName = "Rocks";
string valueData = "1";
ProcessSettings regSettings = new ProcessSettings()
.WithArguments(
arguments => arguments
.Append("add")
.AppendQuoted(keyName)
.Append("/f")
.AppendSwitchQuoted("/v", valueName)
.AppendSwitchQuoted("/t", "REG_DWORD")
.AppendSwitchQuoted("/d", valueData)
);
int result = StartProcess(regPath, regSettings);
if (result == 0)
{
Information("Registry value successfully set");
}
else
{
Information("Failed to set registry value");
}
Currently, there are no Cake aliases for working with the registry. Having said that, there is nothing to stop you manipulating the Registry directly using that standard C# types.
An example of one such approach is here:
Writing to registry in a C# application
Cake provides a number of aliases for things that are more complicated to do, however, remember that almost everything that is provided in an alias could be done directly with C# in your main script. The aliases are simply there as a convenience.

How can I enter an email address into text input field in Edge using Selenium WebDriver?

I have the following program:
using System;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Edge;
namespace ConsoleApplication1
{
static class Program
{
static void Main()
{
//var driver = new ChromeDriver();
var driver = new EdgeDriver();
driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(20));
driver.Navigate().GoToUrl("http://www.cornelsen.de/shop/registrieren-lehrer");
driver.FindElement(By.Id("email")).SendKeys("dummy#user.de");
}
}
}
When I run this in Chrome or any other browser aside from Edge, then the email adress is entered correctly. But if I try the same thing in Edge, the "#" character is missing. The field displays only "dummyuser.de".
Any idea what I can do?
As a workaround, you can set the input value directly via ExecuteScript():
IWebElement email = driver.FindElement(By.Id("email"));
IJavaScriptExecutor js = driver as IJavaScriptExecutor;
string script = "arguments[0].setAttribute('value', 'arguments[1]');";
js.ExecuteScript(script, email, "dummy#user.de");
Or, what you can do is to create a fake input element with a predefined value equal to the email address. Select the text in this input, copy and paste into the target input.
Not pretty, but should only serve as a workaround:
// create element
IJavaScriptExecutor js = driver as IJavaScriptExecutor;
string script = #"
var el = document.createElement('input');
el.type = 'text';
el.value = 'arguments[0]';
el.id = 'mycustominput';
document.body.appendChild(el);
";
js.ExecuteScript(script, "dummy#user.de");
// locate the input, select and copy
IWebElement myCustomInput = driver.FindElement(By.Id("mycustominput"));
el.SendKeys(Keys.Control + "a"); // select
el.SendKeys(Keys.Control + "c"); // copy
// locate the target input and paste
IWebElement email = driver.FindElement(By.Id("email"));
email.SendKeys(Keys.Control + "v"); // paste
It wasn't as easy as I thought after all. Issues with alecxe's answer:
arguments[0].setAttribute('value', '...'); works only the first time you call it. After calling element.Clear();, it doesn't work any more. Workaround: arguments[0].value='...';
The site doesn't react on the JavaScript call like it would on element.SendKeys();, e.g. change event is not invoked. Workaround: Send the first part of the string up to the last "forbidden" character via JavaScript, the rest via WebElement.SendKeys (in this particular order, bc if you do another JavaScript call to the same field after SendKeys(), there will occur no change event either).
I also realized that there are more "forbidden" characters in Edge, e.g. accented or Eastern European ones (I'm Central European). The problem with 2. is that the last character might be a forbidden character. In this case, I append a whitespace. Which of course affects the test case behavior, but I haven't had any other idea.
Full C# code:
public static void SendKeys(this IWebElement element, TestTarget target, string text)
{
if (target.IsEdge)
{
int index = text.LastIndexOfAny(new[] { '#', 'Ł', 'ó', 'ź' }) + 1;
if (index > 0)
{
((IJavaScriptExecutor) target.Driver).ExecuteScript(
"arguments[0].value='" + text.Substring(0, index) + "';", element);
text = index == text.Length ? Keys.Space : text.Substring(index);
}
}
element.SendKeys(text);
}
This problem used to occur in old browsers. Apparently it returned in Edge.
You can try sending the string in pieces
IWebElement email = driver.FindElement(By.Id("email"));
email.SendKeys("dummy");
email.SendKeys("#");
email.SendKeys("user.de");
Or try using # ASCII code
driver.FindElement(By.Id("email")).SendKeys("dummy" + (char)64 + "user.de");
Try to clear the Text field first.
try following
driver.FindElement(By.Id("email")).clear().SendKeys("dummy#user.de");
Have you tried Copy Paste?
Clipboard.SetText("dummy#user.de");
email.SendKeys(OpenQA.Selenium.Keys.Control + "v");
Hope it could help.
I just added one extra line to click on text field and then send keys, I tried this and its working for me.
Code is written in java, you can change that to any other, if you want.
//INITIALISE DRIVER
WebDriver driver = null;
driver = new FirefoxDriver();
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
driver.navigate().to("http://www.cornelsen.de/shop/registrieren-lehrer");
driver.manage().window().maximize();
//CLICK EMAIL FIELD, JUST TO HAVE FOCUS ON TEXT FIELD
driver.findElement(By.id("email")).click();
driver.findElement(By.id("email")).sendKeys("dummy#user.de");
I'm the Program Manager for WebDriver at Microsoft. I just tried to reproduce your issue on my home machine (Windows 10 build 10586) and couldn't reproduce. Your exact test entered the '#' symbol fine.
You should check if you have the latest version of Windows 10 and WebDriver. If you hit the Windows key and type "winver" and hit enter it'll open a popup with the Windows version info. You want it to say
Microsoft Windows
Version 1511 (OS Build 10586.104)
This is the latest version of Windows 10 released to the public. If you have this version you'll also need the corresponding version of WebDriver found here:
http://www.microsoft.com/en-us/download/details.aspx?id=49962
Note that if the build is 10240 that you're on the original release build. Our November update added substantial support for new features (like finding elements by XPath and more!) along with bug fixes which might explain your issues.
Lastly I should note we have an Insiders release as well for WebDriver to match with the Insiders program. If you're subscribed to the Insiders program and want to see the newer features and bug fixes for WebDriver you can find the download here:
https://www.microsoft.com/en-us/download/details.aspx?id=48740
Note that it currently supports build 10547 which was actually before the November update. It'll be updated very shortly (next couple of days) to support the latest Windows Insiders flight, build 14267.
Sorry but I not agree with the last comment (Program Manager for WebDriver at Microsoft). I can reproduce the problem. This is my configuration:
Target Machine (Hub node where tests are run):
Win 10 build 10585.104
MS Edge 25.10586.0.0
MS EdgeHTML 13.10586
Selenium framework:
SeleniumHQ (for Java): 2.48.0
I am using Selenium Grid to run my suite. In this case, I was only doing conceptual test of Egde implementing a basic test:
1. Start Hub in local machine (Win 7) opening console (administrator privileges)
2. Register Node in Hub in target remote machine (Win 10 build 10585) opening console (in this case without administrator privileges because in other way edge hangs when create new session).
Setting up my grid and checking that everything is ok when I try to write my account name in login page I can not see the # and my basic test fails (wrong credentials).
I have introduced # by hand in the moment edge is opened (interrupt point) and I can see symbol.
I have sent "###############" to the text field and I can not see any. In summary, I have tried many things and I can not see #
When I started with Web Automation Testing using Selenium (Java) I remember this behaviour in old versions of Firefox and Chrome. I not really sure which one but it was reproducible in old version.
This partial basic code (implementated with pageobject) IS WORKING with Firefox 35.0 and Chrome 48.0.2564.109 but NOT IS WORKING with Edge's version I put at the beginning of my comment.
WebElement element = WebDriverExtensions.findElement(context, By.cssSelector("input[name='username'][type='email']"));
element.clear();
element.sendKeys(email);
Front Developers are using AngularJS and are validating user's text input to match with a welformatted email:
I afraid that current Edge version does not support sendkeys with this kind of character, maybe the problem is front on-line validation and Edge has to suits these situations because they are really common.
Best regards
None of the above worked for me with the version 2.52. This worked for me :
EdgeDriver edgeDriver = new EdgeDriver("folder of my edge driver containing MicrosoftWebDriver.exe");
IJavaScriptExecutor js = _edgeDriver as IJavaScriptExecutor;
js.ExecuteScript("document.getElementById('Email').value = 'some#email.com'");
Make sure to replace the ".getElementById('Email')" with what you should use to find your field with javascript and replace the "folder of my edge driver containing MicrosoftWebDriver.exe" with the correct path.
Good luck!

How can I read the command line supplied to an offline clickonce application?

I have a simple application that opens a TCP connection and communicates via Telnet to another system. The application is to read a file that contains parameters and a simple scripting language to issue commands based on prompts from the connection.
Written in VS2013 using .NET 4
My application works as designed with one little exception.
I am publishing to a location using VS2013 which works well enough but the idea is to read a command line passed to my application that contains the path/file for the script to execute and that doesn't work as expected.
Finding out the hard way, the standard args[] parameters are not passed when it's published this way.
I have searched out multiple solutions that don't work both on here and other sites.
This is the basis (excerpt from page) of my current implementation to read the command line (found here: http://developingfor.net/2010/06/23/processing-command-line-arguments-in-an-offline-clickonce-application/). This seems to be similar to all solutions I've found, each with some variation that doesn't work.
string[] args = null;
if (ApplicationDeployment.IsNetworkDeployed)
{
var inputArgs = AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData;
if (inputArgs != null && inputArgs.Length > 0)
{
args = inputArgs[0].Split(new char[] { ',' });
}
}
else
{
args = e.Args;
}
This SHOULD return args[] with parameters passed. I believe it would also include the actual command with path to the application. The Split function is because the author wishes to pass arguments separated by commas and not spaces.
My incarnation of this is a bit longer to include some checks to see if we actually get arguments from being compiled as an exe instead. If I compile to EXE and supply a command line, all is fine. Here is my code, not very concise as I've made lots of changes to debug and make this work.
I haven't figured out how to debug in the ide as network deployed with a command line so my debug code is via messagebox.
[STAThread]
static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
if (args.Length == 0) //If we don't have args, assume onclick launch
{
if (ApplicationDeployment.IsNetworkDeployed) //are we oneclick launched?
{
var cmdline = AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData; //this should hold the command line and arguments????
if (cmdline != null && cmdline.Length > 0) //we have something and it contains at least 1 value
{
//This is all debug code to see what we get since we can't trace in this mode
MessageBox.Show(cmdline.Length.ToString()); //how many objects do we have?
foreach (String s in cmdline)
{
MessageBox.Show(s); //show us the value of each object
}
Application.Run(new frmMain(args)); //launch the form with our arguments
}
else
{
//quit application
MessageBox.Show("No command line.1"); //debug so we know where we failed
Application.Exit();
}
}
else
{
//quit application
MessageBox.Show("No command line.2"); //debug so we know where we failed
Application.Exit();
}
}
else
{
Application.Run(new frmMain(args)); //launch form with args passed with exe command line
}
}
Running the code above like this:
sTelent.application 1234
I have also explored the URL passing method which seems to only apply if launched from a web server, which this application is not.
At first I got NULL for my object:
AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData
After more research I discovered that in my project properties under the Publish section there is an option button and under Manifests I can choose "Allow URL Parameters to be passed to application"
I checked this box and while I get different behavior, I don't get the desired behavior.
With that option checked I now get 2 messages boxes: The first showing the number of objects in cmdline and that number is 1 and the second showing the value of that one object which contains only the path/command to my application. No other objects and definitely not my arguments.
Am I totally off base? How do I get my command line arguments from an offline clickonce published application?
It seems that you must put the argument on the .appref-ms and not on not the .application or .exe for this to work correctly for clickonce based applications.
I created a short cut on my desktop by copying the installed application link found under All Programs. That should create an icon on your desktop with the same name as your application.
Then, open a command prompt, type in “%userprofile%\Desktop\My App Name.appref-ms” word for word (of course replace "my app name" with your application name). It should then pass the arguments. You can also put the command within a .bat file. I'm sure that you can also reference the link directly, it typically is located under c:\users[user profile]\appdata\roaming\Microsoft\windows\start menu\programs[app name]

commandline argument parameter limitation

Language: C#
I have to pass a huge string array (built dynamically) as an argument to run an exe.
I am thinking of acheiving it by the below 2 ways. But I am not feeling confident.
I can create it as one string delimited by spaces. I can invoke the exe through Process.Start.
Hence the running child process considers the space and holds as a string array.
However I am unsure about the string array limitation. Suppose if my string array count exceeds more than 10,000
I can create it as one string delimited by a special symbol, which never fall in data. I can invoke the exe with the string. The running child process considers it as one single string, where i can split it with the same delimiter to get the string array back. However, here i am unsure about the command size. Will that do, if the command line string length is large
Can anyone help me in letting me know the parameter size limitations
It depends on the OS:
See Command prompt (Cmd. exe) command-line string limitation on the Microsoft Support site.
On computers running Microsoft Windows XP or later, the maximum length of the string that you can use at the command prompt is 8191 characters. On computers running Microsoft Windows 2000 or Windows NT 4.0, the maximum length of the string that you can use at the command prompt is 2047 characters.
(emphasis mine)
In regards to the size of a string array - if you have many millions of strings in a string array - you are mostly limited by the amount of memory available.
If you are passing 10,000 arguments to a program, you should be putting those arguments in a file and reading the file from disk.
Although a bad idea, Process.start with useshellexecute=false would invoke createprocess() which allows for 32767 characters in the command line (although this is also the maximum size for the entire environment block)
You could store the arguments in a text file and pass that text file as the argument. Your application can then parse the text file to analyse the arguments.
It is not really good practice to use command line arguments for huge arrays. Put your arguments in a configuration file instead, and just pass the filename as a command line argument.
The OS limit varies with the Windows version. It could be about 2k or 8k:
http://support.microsoft.com/kb/830473
You may want to consider creating a parameter file and passing the file as the parameter.
I found this:
For OS: maximum command line lenght is 32767 characters (this limit is from unicode string structure), command prompt maximum lenght is 8192 characters (this limit is from cmd.exe). You may also check:
http://support.microsoft.com/kb/830473
Hope this help.
The limitation in Command prompt (Cmd. exe) is 8191. Command prompt (Cmd. exe) command-line string limitation
The limitation in c# code using Process is 32768 chars in win10.
Tested using Process.start()
If starting the child process directly from the parent process is acceptable (UseShellExecute= false), then you could redirect the StandardInput of the child process and pass arbitrary size of data throw it. Here is an example passing an array of 100000 strings and other stuff, serializing them in binary format.
static void Main(string[] args)
{
if (args.Length == 0)
{
var exeFilePath = Assembly.GetExecutingAssembly().Location;
var psi = new ProcessStartInfo(exeFilePath, "CHILD");
psi.UseShellExecute = false;
psi.RedirectStandardInput = true;
Console.WriteLine("Parent - Starting child process");
var childProcess = Process.Start(psi);
var bf = new BinaryFormatter();
object[] data = Enumerable.Range(1, 100000)
.Select(i => (object)$"String-{i}")
.Append(13)
.Append(DateTime.Now)
.Append(new DataTable("Customers"))
.ToArray();
Console.WriteLine("Parent - Sending data");
bf.Serialize(childProcess.StandardInput.BaseStream, data);
Console.WriteLine("Parent - WaitForExit");
childProcess.WaitForExit();
Console.WriteLine("Parent - Closing");
}
else
{
Console.WriteLine("Child - Started");
var bf = new BinaryFormatter();
Console.WriteLine("Child - Reading data");
var data = (object[])bf.Deserialize(Console.OpenStandardInput());
Console.WriteLine($"Child - Data.Length: {data.Length}");
Console.WriteLine("Child - Closing");
}
}
Output:
Parent - Starting child process
Child - Started
Child - Reading data
Parent - Sending data
Parent - WaitForExit
Child - Data.Length: 100003
Child - Closing
Parent - Closing
This example executes in 6 sec in my machine.

Categories