Skip to content

Commit

Permalink
v1.1.0.1
Browse files Browse the repository at this point in the history
  • Loading branch information
ericlaw1979 committed May 12, 2023
1 parent 7412d28 commit 8c44f43
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 27 deletions.
11 changes: 10 additions & 1 deletion nmf-view/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,16 @@
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("1.0.7.0")]
[assembly: AssemblyVersion("1.1.0.1")]

// v1.1.0.1
// Allow 0-byte messages

// v1.1 (underway)
// Add support for watching std_err

// v1.0.8
// More info about filetype of handles

// v1.0.7
// Display the invoking process' name and PID
Expand Down
33 changes: 33 additions & 0 deletions nmf-view/Utilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,39 @@ class Utilities
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool IsUserAnAdmin();

[StructLayout(LayoutKind.Sequential)]
public struct STARTUPINFO
{
public uint cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public Int32 dwX;
public Int32 dwY;
public Int32 dwXSize;
public Int32 dwYSize;
public Int32 dwXCountChars;
public Int32 dwYCountChars;
public Int32 dwFillAttribute;
public Int32 dwFlags;
public Int16 wShowWindow;
public Int16 cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}

[DllImport("kernel32.dll", SetLastError = true)]
private static extern void GetStartupInfo(out STARTUPINFO lpStartupInfo);

public static string DescribeStartupHandles()
{
STARTUPINFO si;
GetStartupInfo(out si); // dwFlags == 0x400 is STARTF_HASSHELLDATA, meaning stdout is actually a monitor handle, see GetMonitorInfoA.
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}.";
}

public static bool DenyProcessTermination()
{
try
Expand Down
18 changes: 16 additions & 2 deletions nmf-view/frmMain.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

107 changes: 83 additions & 24 deletions nmf-view/frmMain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,36 @@ enum FileType : uint
FileTypePipe = 0x0003,
FileTypeRemote = 0x8000,
FileTypeUnknown = 0x0000,
FileTypeUnknownError = 0xFFFE,
FileTypeUnknownHandleInvalid = 0xFFFF,
}
const int STD_INPUT_HANDLE = -10;
const int STD_OUTPUT_HANDLE = -11;
const int STD_ERROR_HANDLE = -12;

// [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
// static extern bool FreeConsole();
[DllImport("kernel32.dll", SetLastError = true)]
static extern FileType GetFileType(IntPtr hFile);
FileType GetFileType2(IntPtr hFile)
{
FileType ftResult = GetFileType(hFile);

if (ftResult != FileType.FileTypeUnknown) return ftResult;
int iError = Marshal.GetLastWin32Error();
if (0 == iError /* S_OK */) return FileType.FileTypeUnknown;
if (6 == iError /* ERROR_INVALID_HANDLE */)
{
return FileType.FileTypeUnknownHandleInvalid;
}
return FileType.FileTypeUnknownError;
}

// [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
// static extern bool FreeConsole();

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

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

Expand Down Expand Up @@ -79,6 +95,8 @@ struct app_state
public Stream strmToApp;
public Stream strmFromExt;
public Stream strmToExt;
//public Stream strmErrToExt;
public Stream strmErrFromApp;
public Process procParent;
}

Expand All @@ -91,6 +109,7 @@ private static async Task WriteToApp(string sMessage)
{
try
{
if (null == oSettings.strmToApp) return;
byte[] arrPayload = Encoding.UTF8.GetBytes(sMessage);
byte[] arrSize = BitConverter.GetBytes((UInt32)arrPayload.Length);
await oSettings.strmToApp.WriteAsync(arrSize, 0, 4);
Expand Down Expand Up @@ -257,6 +276,7 @@ private void detachApp()
log("Detaching NativeHost App pipes.");
if (null != oSettings.strmToApp) { oSettings.strmToApp.Close(); oSettings.strmToApp = null; }
if (null != oSettings.strmFromApp) { oSettings.strmFromApp.Close(); oSettings.strmFromApp = null; }
if (null != oSettings.strmErrFromApp) { oSettings.strmErrFromApp.Close(); oSettings.strmErrFromApp = null; }
log("NativeHost App pipes detached.");
markAppDetached();
if (oSettings.bPropagateClosures) detachExtension();
Expand Down Expand Up @@ -296,7 +316,7 @@ private async Task MessageShufflerForExtension()

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

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

if (oSettings.bReflectToExtension &&
(sMessage.Length < (1024 * 1024))) // Don't reflect messages over 1mb. They're illegal!
if (oSettings.bReflectToExtension)
{
await WriteToExtension(sMessage);
// Don't reflect messages over 1mb. They're illegal!)
if (sMessage.Length < (1024 * 1024))
{
log("Reflecting message to extension...");
await WriteToExtension(sMessage);
}
else log("!! Message was over 1mb and must not be reflected !!");
}

if (null != oSettings.strmToApp)
await WriteToApp(sMessage);
}
}

/// <summary>
/// This function sits around waiting for messages from the browser extension.
/// </summary>
private async Task WatchStdErrFromApp()
{
//if (null == oSettings.strmErrFromApp) return;
byte[] arrErrString = new byte[1024];

while (true)
{
int cbThisRead = await oSettings.strmErrFromApp.ReadAsync(arrErrString, 0, arrErrString.Length, ctsApp.Token);
if (cbThisRead < 1)
{
await WriteToApp(sMessage);
return;
}
//MaybeWriteBytesToLogfile("-RawRead: ", arrLenBytes, cbSizeRead, cbThisRead);
string sMessage = Encoding.UTF8.GetString(arrErrString, 0, (int)cbThisRead);
log("App wrote Std_Err: " + sMessage, false);
}
}

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

var arrArgs = Environment.GetCommandLineArgs();
if (arrArgs.Length > 1) oSettings.sExtensionID = arrArgs[1];
Expand Down Expand Up @@ -584,17 +630,9 @@ private void WaitForMessages()
{
try
{
var hIn = GetStdHandle(STD_INPUT_HANDLE);
var hInType = GetFileType(hIn);
var hOut = GetStdHandle(STD_OUTPUT_HANDLE);
var hOutType = GetFileType(hOut);
var hErr = GetStdHandle(STD_ERROR_HANDLE);
var hErrType = GetFileType(hErr);
log(DescribeStandardHandles());
oSettings.strmFromExt = Console.OpenStandardInput();
oSettings.strmToExt = Console.OpenStandardOutput();
log($"Attached stdin (0x{hIn.ToInt64():x}, {hInType}) and " +
$"stdout (0x{hOut.ToInt64():x}, {hOutType}) streams.");
log($"Not using stderr (0x{hErr.ToInt64():x}, {hErrType}).");
pbExt.BackColor = Color.FromArgb(159, 255, 159);
Task.Run(async () => await MessageShufflerForExtension());
}
Expand All @@ -604,6 +642,19 @@ private void WaitForMessages()
}
}

private string DescribeStandardHandles()
{
var hIn = GetStdHandle(STD_INPUT_HANDLE);
var hInType = GetFileType2(hIn);
var hOut = GetStdHandle(STD_OUTPUT_HANDLE);
var hOutType = GetFileType2(hOut);
var hErr = GetStdHandle(STD_ERROR_HANDLE);
var hErrType = GetFileType2(hErr);
return ($"GetStdHandle() says stdin=(0x{hIn.ToInt64():x}, {hInType}); " +
$"stdout=(0x{hOut.ToInt64():x}, {hOutType}); " +
$"stderr=(0x{hErr.ToInt64():x}, {hErrType}).");
}

private void clbOptions_ItemCheck(object sender, ItemCheckEventArgs e)
{
if (e.Index == 0) { oSettings.bReflectToExtension = (e.NewValue == CheckState.Checked); return; }
Expand Down Expand Up @@ -714,14 +765,15 @@ private bool ConnectApp(string sFilename)
myProcess.StartInfo.UseShellExecute = false;
myProcess.StartInfo.WorkingDirectory = Path.GetDirectoryName(myProcess.StartInfo.FileName);

// Hide by default
// TODO: allow showing https://source.chromium.org/chromium/chromium/src/+/main:base/process/launch_win.cc;l=298;drc=1ad438dde6b39e1c0d04b8f8cb27c1a14ba6f90e
// 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
// https://weblogs.asp.net/whaggard/223020
// https://source.chromium.org/chromium/chromium/src/+/main:base/process/launch_win.cc;l=298;drc=1ad438dde6b39e1c0d04b8f8cb27c1a14ba6f90e
myProcess.StartInfo.CreateNoWindow = true;
myProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; // Does this do anything?

myProcess.StartInfo.RedirectStandardInput = true;
myProcess.StartInfo.RedirectStandardOutput = true;
// TODO: STDERR?
myProcess.StartInfo.RedirectStandardError = true;

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

private void txtSendToApp_TextChanged(object sender, EventArgs e)
{
btnSendToApp.Enabled = ((txtSendToApp.TextLength > 0) && IsAppAttached());
btnSendToApp.Enabled = (/*(txtSendToApp.TextLength > 0) && */ IsAppAttached());
}

private void txtSendToExtension_TextChanged(object sender, EventArgs e)
{
btnSendToExtension.Enabled = ((txtSendToExtension.TextLength > 0) && IsExtensionAttached());
btnSendToExtension.Enabled = (/*(txtSendToExtension.TextLength > 0) && */ IsExtensionAttached());
}

private async void btnSendToApp_Click(object sender, EventArgs e)
Expand Down Expand Up @@ -1001,5 +1055,10 @@ private void frmMain_KeyDown(object sender, KeyEventArgs e)
}
}
}

private void btnPokeStdErr_Click(object sender, EventArgs e)
{
Console.Error.WriteLine("Poking StdErr @" + DateTime.Now.ToString());
}
}
}

0 comments on commit 8c44f43

Please sign in to comment.