uglify crashing after running child_process.execFile - c#

EDIT 2
I "solved" the problem, but I don't want to post it as an answer b/c it doesn't explain what actually happened. In the code for the .NET resourceReader.exe I use
Console.OutputEncoding = System.Text.Encoding.UTF8;
to output the internationalized resources to stdout in unicode. If I reset the encoding at the end of my program with
Console.OutputEncoding = System.Text.Encoding.Default;
then I don't get any errors in Node. If I don't reset it, I get the error described in the original question. It seems that .NET is somehow messing up some of the output encoding settings on the cmd.exe and causing the subsequent node run to fail!
EDIT
I narrowed down the error to being caused by resourceReader.exe. It's a.NET program which reads some resource streams out of the .NET assembly and prints them to the stdout using Console.WriteLine. I added Console.OutputEncoding = System.Text.Encoding.UTF8 to resourceReader.exe because some of the resources are in non ASCII letters and that's whats causing the crash in grunt!
If I take that line out, the task doesn't crash, but the resources show up in non printable ASCII characters! Also, the crash only happens if I actually print non-ASCII to sdtout. If I don't print them, it doesn't error.
ORIGINAL
I added a step to my Gruntfile which uses child_process.execFile to run an read some data from an external program and uses it in the build. Now whenever I run my build, it runs fine the first time, but crashes the second time!
Here's the output from the crash (this is during the uglify task):
File build/Scripts/NDB.contacts.min.js created: 16.85 kBevents.js:85
throw er; // Unhandled 'error' event
^
Error: This socket is closed.
at WriteStream.Socket._writeGeneric (net.js:656:19)
at WriteStream.Socket._write (net.js:709:8)
at doWrite (_stream_writable.js:301:12)
at writeOrBuffer (_stream_writable.js:288:5)
at WriteStream.Writable.write (_stream_writable.js:217:11)
at WriteStream.Socket.write (net.js:634:40)
at Log._write (C:\...\node_modules\grunt\node_modules\grunt-legacy-log\index.js:161:26)
at Log.wrapper [as _write] (C:\...\node_modules\grunt\node_modules\grunt-legacy-log\node_modules\lodash\index.js:3095:19)
at Log._writeln (C:\...\node_modules\grunt\node_modules\grunt-legacy-log\index.js:166:8)
at Log.wrapper [as _writeln] (C:\...\node_modules\grunt\node_modules\grunt-legacy-log\node_modules\lodash\index.js:3095:19)
at Log.writeln (C:\...\node_modules\grunt\node_modules\grunt-legacy-log\index.js:177:8)
at Log.wrapper (C:\...\node_modules\grunt\node_modules\grunt-legacy-log\node_modules\lodash\index.js:3095:19)
at writeln (C:\...\node_modules\grunt\lib\grunt\fail.js:30:13)
at Object.fail.fatal (C:\...\node_modules\grunt\lib\grunt\fail.js:46:3)
at process.uncaughtHandler (C:\...\node_modules\grunt\lib\grunt.js:121:10)
at process.emit (events.js:129:20)
at process._fatalException (node.js:236:26)
at Task.runTaskFn (C:\...\node_modules\grunt\lib\util\task.js:250:7)
at Task.<anonymous> (C:\...\node_modules\grunt\lib\util\task.js:293:12)
at C:\...\node_modules\grunt\lib\util\task.js:220:11
at process._tickCallback (node.js:355:11)
Here's the code for the task which uses child_process.
function readAllCultures() {
var readDeferred = q.defer();
childProc.execFile("../tools/resourceReader.exe", function (err, stdout, stderr) {
if (err) throw new Error(err);
var cultures = JSON.parse(stdout);
readDeferred.resolve(cultures);
});
return readDeferred.promise;
}
Here's some things I discovered debugging that might be helpful
If I redirect the output of grunt (using either > filename or | process) it runs fine
When I redirect output, I never see the message from uglify that it created the main output only that it created the source map.
If I close and reopen my command prompt (cmd.exe) it works fine
I added a listener to the exit and close events of the child process using rdr.on("close", function() { console.log("close"); }); and the same for exit. Both events fire as expected in the first run.
Using Process Explorer, I can see node.exe open under the command prompt and close again when my command finishes running. There are no processes visibly "left open" under the command prompt.

The fact that the stack trace is ultimately showing a socket.write error is interesting. Nothing in the code you've provided suggests you are trying to write to a socket.
If we follow the stack down, we can see that it's actually grunt that is trying to write to a socket, as it's attempting to log an uncaught exception.
So, first your grunt task throws a currently unknown error, and then grunt itself errors because it can't tell you about it.
I would first try and log the error that occurs in your child process. Currently if there is an error present, you simply throw it without finding out what it is. It's likely that this is what grunt is trying and failing to log.
Replace
if (err) throw new Error(err);
With
if (err) console.error(err);
This will hopefully avoid the socket.write problem and give you specific information about what error is happening on the child process. What do you see?
Second, I would try using child_process.exec instead of child_process.execFile. This will spawn a shell and run resourceReader.exe inside of it (instead of running it directly). This might help avoid any problems you are encountering with the command still running/failing in the background, which could be the cause of the socket.write error.

Related

NET 6 COM: An outgoing call cannot be made since the application is dispatching an input-synchronous call

I have a Win11, NET 6.0, Windows App that calls Word through COM to run a Word macro stored inside of the Word instance. All the relevant code has been running for a year or so. I have been debugging for two days without success, reading up on the exception message that I am suddenly getting, trying random code changes, and so on.
My C# program gets the Word instance and tries to run the macro named "FH3" as shown in the code and log trace below. But the code never gets to run the macro because the code that tries to get the Word instance (WordAppGet) fails at runtime. Here are three lines from my log file that show the execution and exception error message.
MacroRun Running Word macro: 'FH3'
WordAppVarsGet GetActiveObject Word.Application failed.
Exception: An outgoing call cannot be made since the application is dispatching an input-synchronous call. (0x8001010D (RPC_E_CANTCALLOUT_ININPUTSYNCCALL))
The following test case code runs okay in Visual Studio.
[TestMethod()]
public void MacroRunTest() {
var me = MethodBase.GetCurrentMethod()?.Name;
MacroRunHelper("FH2", me);
}
// this code has been running fine for many months
public static void
MacroRunHelper(string macroName, string me) {
var msg1 = $"{me} Running Word macro: '{macroName}'";
LogMan.SendNormal(msg1);
var wapp = WordAppGet();
try {
wapp.Run(macroName);
}
catch (Exception ex) {
var msg = $"{me} {ex.Message} '{macroName}'";
LogMan.Send(LogType.Error, msg);
}
}
/// <summary>
/// Get and store a reference to the active Word application.
/// </summary>
public static Word.Application
WordAppGet() {
Word.Application wapp = null;
try {
// Marshal2.GetActiveObject is a copy of the Microsoft reference code
// because it was not included in the MS Interop library when the code was written.
// And GetActiveObject is still not included as of 2022-09-18.
//
// this call fails with the error message
wapp = Marshal2.GetActiveObject("Word.Application") as Application;
}
catch (Exception ex) {
var msg = $"{me} GetActiveObject Word.Application failed.";
LogMessage(PError, msg);
LogMessage(PError, ex.Message);
throw;
}
return wapp;
}
For what it's worth, the online doc about the error message talks a lot about windows controls and BeginInvoke, but this has nothing to do with any Windows controls as far as I can tell.
I have used this same code pattern to access Word, Excel, Outlook, PowerPoint, on NET Framework for a couple of years, and on NET 5 and 6 for more than a year.
It is a mystery to me why it stopped working for Word. It is a mystery to me why it continues to work in the Visual Studio debugger.
Does anyone know how I can fix it to run again? I wonder if any recent Win11 updates have had any changes that break this kind of code. Thank you.
The source of the problem was far away from the code shown above. I switched my top-level WindowsApp from receiving input commands using sockets to receiving using Windows messages. The WndProc branch called some helper code SYNCHRONOUSLY which called other code, and about 10 or 15 calls down the WordAppGet code was called.
Because WndProc calls were synchronous, the WndProc thread was not allowed to "call out" over COM because it might create a deadlock condition. Using Task.Run(...) in the WndProc message branch put the work on a separate thread that was allowed to call out over COM.
Receiving input commands via sockets does not involve the single-thread STA WndProc thread, so sockets worked for a year or more. I was trying to improve the speed of the code and thought Windows messages would be faster. But I wasted more time debugging the COM issue than sockets execution times would have used in 20 years. Bummer.
FWIW, I did not detect the problem until many weeks after I switched from sockets to messages because the COM use case was not tested after the switch.

App.MobileService.LoginAsync fails to show dialog on select machine -> Mind Blown

Just wondering if anyone might be able to point me in the right direction here.
user = await App.MobileService.LoginAsync(provider)
this is the line of code in question. The problem is; this works fine on 2/3 test machines (All Windows 10), the dialog is displayed and the program operates as expected. on the third machine however, the dialog does not display. I have wrapped the function in a try catch block and I am catching all exceptions that I then route to a MessageDialog to display on the screen. the messages are never shown, as though the try succeeded, but the function exits on that line exactly and throws no exceptions. I am using MobileServiceAuthenticationProvider.MicrosoftAccount as my provider.
Code redacted to highlight the error, the full code returns a boolean value for success/failure. All traces past the failing line do not appear, so the function is definitely exiting at the specified line.
try
{
//This line fails on a single machine out of three
user = await App.MobileService.LoginAsync(provider)
}
catch(Exception e)
{
//when it fails, this does not trigger, and no traces after this point
//appear until outside the function
MessageDialog msg = new MessageDialog(e.ToString());
await msg.ShowAsync();
}
and just to make things really weird...message dialogs prior to this point in the code work just fine...
I suspect that the security of the machine in question is blocking the login (windows defender), but I really have no idea where to look for this, or even how to test the problem further. Any ideas as to what would prevent this single machine from displaying the Microsoft login window, or ideas on further debugging would be appreciated.
You are not awaiting the response from the Async reply. This means that you will have an ordering and concurrency issue - sometimes it will work, and sometimes it won't and it's all in the timing.
You need:
var user = await client.LoginAsync(provider);

PrivateFontCollection hangs on initilizing

i have a client server application. i want to load a font from file in my server part.
here is my code to do that. but unfortunately it will hangs on new PrivateFontCollection(); line!!!!
note that this part is running in another thread.
string fontAdd = #"C:\ETLEngine\Languages\Fonts\BNazanin.ttf";
System.Drawing.Text.PrivateFontCollection privateFonts = new System.Drawing.Text.PrivateFontCollection();
privateFonts.AddFontFile(fontAdd);
var mapFont = new Font(privateFonts.Families[0], 12, FontStyle.Bold);
please help me get out of this.
is there any alternative way for loading font from files?
Actualy I did write a console application which just do the code above, and everything works completely fine!! i got this sample code from msdn and stackoverflow, but i don't know why it doesn't work in my server side application!!! it doesn't produce an error, i set a break point on that line, and hit F10 or F11 and then its going to execute that line but never comes back to execute next line! and the thread still is in running state, not terminated or something else...! that's it!!!

How can I capture tf.exe stderr without stopping its dialog prompts?

I'm trying to write an application that provides my own UI for tf.exe (in TFS 2010). (yes, I know VS already does this but this app is custom). For some commands, like properties, I want to capture output from stdout. Also, when a command fails, I want to capture its error output from stderr. I'm using .NET's Process class to launch tf.exe, like so:
try
{
sccProcess.StartInfo.FileName = "tf.exe";
sccProcess.StartInfo.Arguments = arguments;
sccProcess.StartInfo.CreateNoWindow = true;
sccProcess.StartInfo.UseShellExecute = false;
sccProcess.StartInfo.RedirectStandardOutput = true;
sccProcess.StartInfo.RedirectStandardError = true;
sccProcess.Start();
output = sccProcess.StandardOutput.ReadToEnd();
// Redirecting synchronously from output and error streams may cause a deadlock.
// To prevent that, we always read the error stream asynchronously.
sccProcess.ErrorDataReceived += (sender, args) => errorStringBuilder.Append(args.Data);
sccProcess.BeginErrorReadLine();
sccProcess.WaitForExit();
exitCode = sccProcess.ExitCode;
error = errorStringBuilder.ToString();
}
catch (Win32Exception)
{
// The file name for the process couldn't be found.
exitCode = -1;
}
finally
{
sccProcess.Close();
}
However, when I run a command, say "tf checkin", I notice that when standard error is redirected, I no longer see the checkin dialog box that normally opens. Instead, the checkin just happens. Thus, it seems like redirecting stderr for tf.exe behaves as if I set the noprompt flag. Does anyone know how I can capture stderr data without stopping tf.exe dialog prompts?
Thanks,
-Craig
You might be better off calling the TFS API directly rather than calling tf.exe from code. That way you'll have much more control over the behaviour of the application and all the benefits of exceptions rather than stderr. The API also exposes a lot more functionality than is available from tf.exe tfpt.exe and visual studio.
Finally, after months of being frustrated about this I found the solution.
Apparently there's a hidden parameter to tf.exe called /prompt, which forces the UI to be shown even though you've redirected stdout.
Source: http://www.wintellect.com/cs/blogs/jrobbins/archive/2006/12/26/working-offline-with-tfs.aspx

How do I detect which program has returned an error code?

I'm attempting to run a series of commands programmatically, read the error codes, and detect if these codes indicate success or failure so I can respond accordingly.
Currently my commands are using psexec which then launches robocopy. I've noted that while most commands return an error code of 0 if the program is successful, robocopy is odd in that it returns values in the range of 0-8 even if the operation is successful, so I am adding some extra logic in my error detection to note when robocopy returns an error code which otherwise suggests a failure.
The problem is that in this same set of commands I'm using PSExec to launch various other executables and batch files, so I need an error detection solution that allows me to know when robocopy is the one returning these error codes or if it's PSExec because an error code of 5 in robocopy is fine usually whereas an error code of 5 in PSExec says that access is denied.
So my question is, how do I know which program has returned the error code? I'm using c# .NET 4.0, and I'm using the Process class to programmatically launch these programs. I set the program name as psexec, and the arguments include the robocopy or other programs. I then run, wait for the exit, and store the error code, then attempt to parse it.
What do you all suggest?
Here is a code snippet:
foreach (var command in commands)
{
// TODO: Add exception handling
string processName = command.Split(delimiters).ToList().ElementAt(0); // split up command into pieces, select first "token" as the process name
string commandArguments = command.Replace(processName + " ", ""); // remove the process name and following whitespace from the command itself, storing it in a new variable
Process commandProcess = new Process(); // declare a new process to be used
commandProcess.StartInfo.FileName = processName; // add file start info for filename to process
commandProcess.StartInfo.Arguments = commandArguments; // add file start info for arguments to process
commandProcess.StartInfo.UseShellExecute = false; // skip permissions request
commandProcess.Start(); // start process according to command's data
commandProcess.WaitForExit(); // wait for the process to exit before continuing
bool commandSuccessful = ParseCommandErrorCode(commandProcess, commandProcess.ExitCode); // grab error code
if (!commandSuccessful)
{
// ERROR! abort operation and inform the user of the last completed operation, and how many commands have not been run
} // end if
Console.WriteLine("Error code: {0}", commandProcess.ExitCode); // print error code
commandProcess.Close(); // close process
} // end foreach
Haven't you already answered your own question? You will have to match the error code to success or failure for each utility. commandProcess.StartInfo.FileName will tell you if the utility launched was robocopy or PSExe. When parsing the error code, map the value to success or failure depending on the name of the file.
I do backup of large database, so there is a command file .cmd. in that I have mny Start ROBOCOPY cource destination and arguments each process script line for a* b* c* c* etc.
example as below: in sample.cmd file(acts as btach file),
I have following lines of scripts in a sample.cmd file as:
Start ROBOCOY src dest a* b* c* /z /w:1 r:1
Start ROBOCOY src dest d* e* f* g* /z /w:1 r:1
Start ROBOCOY src dest h* K* P* Y* /z /w:1 r:1
Start ROBOCOY src dest xry* srp* /z /w:1 r:1
When I rum > Robocopy sample.cmd I starts with cmd.exe and another 4 multiple console windows robocoy.exe copying files simultaneously as per above commands, it waits for another file, as it has wait time, if file is being used by another process. Is is more faster as it do job simultaneously.
Now I am devloping GUI using C# windows to run the process instead going to command console and
start
main()
{
process.start( "path of sample.cmd" )
process.waitforexit()
label.text=" sucessful copy"
}
However, if it takes control of oneprocess, i.e cmd.exe and and there are 4 robocopy processes in taskmanager. when cmd.exe process completes, it returns the cursor to label.text "Sucesssfully completed". While there are robocopy processes still running. you can see the robocopy windows doing the copying process.
Here is the question: I want to take contrl of all the processes (cmd.exe and robocopy.exe) programatically in C#, so that when the label.text should display "sucessfully completed" only when all commands are successfully completed", if one fails, then there is no point in the GUI.
option 2 (similar to Biju has written above): is it better to remove robocoy command scripts from sample.cmd(batch file) file and write code to run the 4 robocopy lines in C#, but how to run the robocooy script line written .cmd file, as they have arguments as well. I code runs each robocopy process then each will return to the next line of code and if it fails, we can catch the error and display in the message box.
Hope this will help... However, Iam looking for more better way, if somebody can improve on the same. Thanks :)

Categories

Resources