Skip to content

Commit 8c44f43

Browse files
committed
v1.1.0.1
1 parent 7412d28 commit 8c44f43

File tree

4 files changed

+142
-27
lines changed

4 files changed

+142
-27
lines changed

nmf-view/Properties/AssemblyInfo.cs

+10-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,16 @@
1010
[assembly: AssemblyTrademark("")]
1111
[assembly: AssemblyCulture("")]
1212
[assembly: ComVisible(false)]
13-
[assembly: AssemblyVersion("1.0.7.0")]
13+
[assembly: AssemblyVersion("1.1.0.1")]
14+
15+
// v1.1.0.1
16+
// Allow 0-byte messages
17+
18+
// v1.1 (underway)
19+
// Add support for watching std_err
20+
21+
// v1.0.8
22+
// More info about filetype of handles
1423

1524
// v1.0.7
1625
// Display the invoking process' name and PID

nmf-view/Utilities.cs

+33
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,39 @@ class Utilities
1414
[return: MarshalAs(UnmanagedType.Bool)]
1515
public static extern bool IsUserAnAdmin();
1616

17+
[StructLayout(LayoutKind.Sequential)]
18+
public struct STARTUPINFO
19+
{
20+
public uint cb;
21+
public string lpReserved;
22+
public string lpDesktop;
23+
public string lpTitle;
24+
public Int32 dwX;
25+
public Int32 dwY;
26+
public Int32 dwXSize;
27+
public Int32 dwYSize;
28+
public Int32 dwXCountChars;
29+
public Int32 dwYCountChars;
30+
public Int32 dwFillAttribute;
31+
public Int32 dwFlags;
32+
public Int16 wShowWindow;
33+
public Int16 cbReserved2;
34+
public IntPtr lpReserved2;
35+
public IntPtr hStdInput;
36+
public IntPtr hStdOutput;
37+
public IntPtr hStdError;
38+
}
39+
40+
[DllImport("kernel32.dll", SetLastError = true)]
41+
private static extern void GetStartupInfo(out STARTUPINFO lpStartupInfo);
42+
43+
public static string DescribeStartupHandles()
44+
{
45+
STARTUPINFO si;
46+
GetStartupInfo(out si); // dwFlags == 0x400 is STARTF_HASSHELLDATA, meaning stdout is actually a monitor handle, see GetMonitorInfoA.
47+
return $"GetStartupInfo() says dwFlags=0x{si.dwFlags:x}, {((si.dwFlags & 0x100)==0x100 ? "in" : "ex")}cludes STARTF_USESTDHANDLES; stdin=0x{si.hStdInput.ToInt64():x}; stdout=0x{si.hStdOutput.ToInt64():x}; stderr=0x{si.hStdError.ToInt64():x}.";
48+
}
49+
1750
public static bool DenyProcessTermination()
1851
{
1952
try

nmf-view/frmMain.Designer.cs

+16-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

nmf-view/frmMain.cs

+83-24
Original file line numberDiff line numberDiff line change
@@ -30,20 +30,36 @@ enum FileType : uint
3030
FileTypePipe = 0x0003,
3131
FileTypeRemote = 0x8000,
3232
FileTypeUnknown = 0x0000,
33+
FileTypeUnknownError = 0xFFFE,
34+
FileTypeUnknownHandleInvalid = 0xFFFF,
3335
}
3436
const int STD_INPUT_HANDLE = -10;
3537
const int STD_OUTPUT_HANDLE = -11;
3638
const int STD_ERROR_HANDLE = -12;
3739

38-
// [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
39-
// static extern bool FreeConsole();
40+
[DllImport("kernel32.dll", SetLastError = true)]
41+
static extern FileType GetFileType(IntPtr hFile);
42+
FileType GetFileType2(IntPtr hFile)
43+
{
44+
FileType ftResult = GetFileType(hFile);
45+
46+
if (ftResult != FileType.FileTypeUnknown) return ftResult;
47+
int iError = Marshal.GetLastWin32Error();
48+
if (0 == iError /* S_OK */) return FileType.FileTypeUnknown;
49+
if (6 == iError /* ERROR_INVALID_HANDLE */)
50+
{
51+
return FileType.FileTypeUnknownHandleInvalid;
52+
}
53+
return FileType.FileTypeUnknownError;
54+
}
55+
56+
// [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
57+
// static extern bool FreeConsole();
4058

4159
private const int SW_SHOW = 5;
4260
[DllImport("User32")]
4361
private static extern int ShowWindow(int hwnd, int nCmdShow);
4462

45-
[DllImport("kernel32.dll")]
46-
static extern FileType GetFileType(IntPtr hFile);
4763
[DllImport("Kernel32.dll", SetLastError = true)]
4864
static extern IntPtr GetStdHandle(int nStdHandle);
4965

@@ -79,6 +95,8 @@ struct app_state
7995
public Stream strmToApp;
8096
public Stream strmFromExt;
8197
public Stream strmToExt;
98+
//public Stream strmErrToExt;
99+
public Stream strmErrFromApp;
82100
public Process procParent;
83101
}
84102

@@ -91,6 +109,7 @@ private static async Task WriteToApp(string sMessage)
91109
{
92110
try
93111
{
112+
if (null == oSettings.strmToApp) return;
94113
byte[] arrPayload = Encoding.UTF8.GetBytes(sMessage);
95114
byte[] arrSize = BitConverter.GetBytes((UInt32)arrPayload.Length);
96115
await oSettings.strmToApp.WriteAsync(arrSize, 0, 4);
@@ -257,6 +276,7 @@ private void detachApp()
257276
log("Detaching NativeHost App pipes.");
258277
if (null != oSettings.strmToApp) { oSettings.strmToApp.Close(); oSettings.strmToApp = null; }
259278
if (null != oSettings.strmFromApp) { oSettings.strmFromApp.Close(); oSettings.strmFromApp = null; }
279+
if (null != oSettings.strmErrFromApp) { oSettings.strmErrFromApp.Close(); oSettings.strmErrFromApp = null; }
260280
log("NativeHost App pipes detached.");
261281
markAppDetached();
262282
if (oSettings.bPropagateClosures) detachExtension();
@@ -296,7 +316,7 @@ private async Task MessageShufflerForExtension()
296316

297317
if (cbBodyPromised >= Int32.MaxValue)
298318
{
299-
log("Was promised a message >=2gb. Technically this is legal but this app only allows 2GB due to .NET Framework size limits.");
319+
log("Was promised a message >=2gb. Technically this is legal, but this debugger only allows 2GB due to .NET Framework size limits.");
300320
detachExtension();
301321
return;
302322
}
@@ -321,6 +341,7 @@ private async Task MessageShufflerForExtension()
321341

322342
if (oSettings.bSendToFiddler)
323343
{
344+
log("Forwarding message to Fiddler...");
324345
try
325346
{
326347
HttpContent entity = new ByteArrayContent(buffer);
@@ -350,16 +371,39 @@ private async Task MessageShufflerForExtension()
350371
log($"!!! ERROR: JSON Parsing failed at offset {oErrors.iErrorIndex} {oErrors.sWarningText}. Note:Strings must be double-quoted.");
351372
}
352373

353-
if (oSettings.bReflectToExtension &&
354-
(sMessage.Length < (1024 * 1024))) // Don't reflect messages over 1mb. They're illegal!
374+
if (oSettings.bReflectToExtension)
355375
{
356-
await WriteToExtension(sMessage);
376+
// Don't reflect messages over 1mb. They're illegal!)
377+
if (sMessage.Length < (1024 * 1024))
378+
{
379+
log("Reflecting message to extension...");
380+
await WriteToExtension(sMessage);
381+
}
382+
else log("!! Message was over 1mb and must not be reflected !!");
357383
}
358384

359-
if (null != oSettings.strmToApp)
385+
await WriteToApp(sMessage);
386+
}
387+
}
388+
389+
/// <summary>
390+
/// This function sits around waiting for messages from the browser extension.
391+
/// </summary>
392+
private async Task WatchStdErrFromApp()
393+
{
394+
//if (null == oSettings.strmErrFromApp) return;
395+
byte[] arrErrString = new byte[1024];
396+
397+
while (true)
398+
{
399+
int cbThisRead = await oSettings.strmErrFromApp.ReadAsync(arrErrString, 0, arrErrString.Length, ctsApp.Token);
400+
if (cbThisRead < 1)
360401
{
361-
await WriteToApp(sMessage);
402+
return;
362403
}
404+
//MaybeWriteBytesToLogfile("-RawRead: ", arrLenBytes, cbSizeRead, cbThisRead);
405+
string sMessage = Encoding.UTF8.GetString(arrErrString, 0, (int)cbThisRead);
406+
log("App wrote Std_Err: " + sMessage, false);
363407
}
364408
}
365409

@@ -534,6 +578,8 @@ private void frmMain_Load(object sender, EventArgs e)
534578
log($"I am{sExtraInfo}, launched by [{((null != oSettings.procParent) ? (oSettings.procParent.ProcessName + ':' + oSettings.procParent.Id) : "unknown")}].");
535579
lblVersion.Text = $"v{Application.ProductVersion} [{((8 == IntPtr.Size) ? "64" : "32")}-bit]";
536580
Text += sExtraInfo; // Append extra info to form caption.
581+
log(Utilities.DescribeStartupHandles());
582+
log(DescribeStandardHandles());
537583

538584
var arrArgs = Environment.GetCommandLineArgs();
539585
if (arrArgs.Length > 1) oSettings.sExtensionID = arrArgs[1];
@@ -584,17 +630,9 @@ private void WaitForMessages()
584630
{
585631
try
586632
{
587-
var hIn = GetStdHandle(STD_INPUT_HANDLE);
588-
var hInType = GetFileType(hIn);
589-
var hOut = GetStdHandle(STD_OUTPUT_HANDLE);
590-
var hOutType = GetFileType(hOut);
591-
var hErr = GetStdHandle(STD_ERROR_HANDLE);
592-
var hErrType = GetFileType(hErr);
633+
log(DescribeStandardHandles());
593634
oSettings.strmFromExt = Console.OpenStandardInput();
594635
oSettings.strmToExt = Console.OpenStandardOutput();
595-
log($"Attached stdin (0x{hIn.ToInt64():x}, {hInType}) and " +
596-
$"stdout (0x{hOut.ToInt64():x}, {hOutType}) streams.");
597-
log($"Not using stderr (0x{hErr.ToInt64():x}, {hErrType}).");
598636
pbExt.BackColor = Color.FromArgb(159, 255, 159);
599637
Task.Run(async () => await MessageShufflerForExtension());
600638
}
@@ -604,6 +642,19 @@ private void WaitForMessages()
604642
}
605643
}
606644

645+
private string DescribeStandardHandles()
646+
{
647+
var hIn = GetStdHandle(STD_INPUT_HANDLE);
648+
var hInType = GetFileType2(hIn);
649+
var hOut = GetStdHandle(STD_OUTPUT_HANDLE);
650+
var hOutType = GetFileType2(hOut);
651+
var hErr = GetStdHandle(STD_ERROR_HANDLE);
652+
var hErrType = GetFileType2(hErr);
653+
return ($"GetStdHandle() says stdin=(0x{hIn.ToInt64():x}, {hInType}); " +
654+
$"stdout=(0x{hOut.ToInt64():x}, {hOutType}); " +
655+
$"stderr=(0x{hErr.ToInt64():x}, {hErrType}).");
656+
}
657+
607658
private void clbOptions_ItemCheck(object sender, ItemCheckEventArgs e)
608659
{
609660
if (e.Index == 0) { oSettings.bReflectToExtension = (e.NewValue == CheckState.Checked); return; }
@@ -714,14 +765,15 @@ private bool ConnectApp(string sFilename)
714765
myProcess.StartInfo.UseShellExecute = false;
715766
myProcess.StartInfo.WorkingDirectory = Path.GetDirectoryName(myProcess.StartInfo.FileName);
716767

717-
// Hide by default
718-
// TODO: allow showing https://source.chromium.org/chromium/chromium/src/+/main:base/process/launch_win.cc;l=298;drc=1ad438dde6b39e1c0d04b8f8cb27c1a14ba6f90e
768+
// TODO: If the compat hack lands for Chrome, then we should use the same logic here to show GUI if the app targets SUBSYSTEM_WINDOWS
769+
// https://weblogs.asp.net/whaggard/223020
770+
// https://source.chromium.org/chromium/chromium/src/+/main:base/process/launch_win.cc;l=298;drc=1ad438dde6b39e1c0d04b8f8cb27c1a14ba6f90e
719771
myProcess.StartInfo.CreateNoWindow = true;
720772
myProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; // Does this do anything?
721773

722774
myProcess.StartInfo.RedirectStandardInput = true;
723775
myProcess.StartInfo.RedirectStandardOutput = true;
724-
// TODO: STDERR?
776+
myProcess.StartInfo.RedirectStandardError = true;
725777

726778
try
727779
{
@@ -741,8 +793,10 @@ private bool ConnectApp(string sFilename)
741793
// https://docs.microsoft.com/en-us/dotnet/api/system.console?view=net-5.0#Streams
742794
oSettings.strmToApp = myProcess.StandardInput.BaseStream;
743795
oSettings.strmFromApp = myProcess.StandardOutput.BaseStream;
796+
oSettings.strmErrFromApp = myProcess.StandardError.BaseStream;
744797
log($"Started {oSettings.sExeName} as the proxied NativeMessagingHost.");
745798
Task.Run(async () => await MessageShufflerForApp());
799+
Task.Run(async () => await WatchStdErrFromApp());
746800
return true;
747801
}
748802
}
@@ -952,12 +1006,12 @@ private void frmMain_FormClosed(object sender, FormClosedEventArgs e)
9521006

9531007
private void txtSendToApp_TextChanged(object sender, EventArgs e)
9541008
{
955-
btnSendToApp.Enabled = ((txtSendToApp.TextLength > 0) && IsAppAttached());
1009+
btnSendToApp.Enabled = (/*(txtSendToApp.TextLength > 0) && */ IsAppAttached());
9561010
}
9571011

9581012
private void txtSendToExtension_TextChanged(object sender, EventArgs e)
9591013
{
960-
btnSendToExtension.Enabled = ((txtSendToExtension.TextLength > 0) && IsExtensionAttached());
1014+
btnSendToExtension.Enabled = (/*(txtSendToExtension.TextLength > 0) && */ IsExtensionAttached());
9611015
}
9621016

9631017
private async void btnSendToApp_Click(object sender, EventArgs e)
@@ -1001,5 +1055,10 @@ private void frmMain_KeyDown(object sender, KeyEventArgs e)
10011055
}
10021056
}
10031057
}
1058+
1059+
private void btnPokeStdErr_Click(object sender, EventArgs e)
1060+
{
1061+
Console.Error.WriteLine("Poking StdErr @" + DateTime.Now.ToString());
1062+
}
10041063
}
10051064
}

0 commit comments

Comments
 (0)