SerGreen / Appacker

Tool for making single .exe application packages
234 stars 29 forks source link

Execute in same session #3

Closed jochemstoel closed 6 years ago

jochemstoel commented 6 years ago

When executed from the command line, the packed output executable opens in a new session/window. This makes it impossible to read/write stdin or stdout pipes of the packed executable. I don't know how to fix, please instruct.

SerGreen commented 6 years ago

If i understood correctly, you have an application that you usually run from the command line and it redirects its I/O to the parent console process, but once it's packed you actually now launch the wrapper app which in turn launches your target app, therefore target app now redirects its input/output into the wrapper and not the console.
This is probably fixable by making some i/o redirections in the wrapper tool. Can you provide some example application to test on?

jochemstoel commented 6 years ago

An example application to test on? Anything that writes to stdout really. example.exe

The source.

try {
    var { version, configuration } = require('./bundledFile.json')
    console.log(`example.exe version ${version}`)
    console.log(`this command line application will do something ${configuration.something}.`)
    let i = 0
    let startTime = new Date().getTime()
    let progress = () => { 
        if(i<100) {
            console.log(`[${i}%] processing ...`)
            setTimeout(progress, Math.floor(Math.random() * 1000) + 1)
        } else {
            let processTime = new Date().getTime() - startTime
            let random = Math.floor(Math.random() * 300) + 17
            console.log(`complete!`, `processed ${random} things in ${processTime} second(s).`)
        }
        i++
    }
    progress()
} catch (error) {
    console.error(error.message)
}

Pretend this application has dependencies bundled and I wan't to catch its process stdout.

SerGreen commented 6 years ago

Thank you, now i see the problem - it opens an empty console window and prints nothing. I checked the same code with a .NET console app and it still behaves the same way.
This was weird, because unpacker.exe wrapper starts separate process for the target app, so it should behave the same way as if you extract it yourself and launch with double click. But then i tried to pack it with the Debug build of the Appacker and it worked just fine, output was there in the console.
So the problem was in the difference between Debug and Release builds of Unpacker project: in debug it has Console Application as output type, but in release it's Windows Application, which is a console app, but without displaying console window. And apparently the type of a console app influences the default values of ProcessStartInfo object which is used to start target app, namely UseShellExecute appears to be set to false when it's a Windows Application (which redirects I/O of the child process to the current process, which is window-less). So in order to fix it i had to add UseShellExecute = true to the start of the target app's process:

// Launch unpacked app
ProcessStartInfo procInfo = new ProcessStartInfo()
{
    FileName = Path.Combine(tempDir, pathToMainExe),
    WorkingDirectory = tempDir,
    UseShellExecute = true
};
Process proc = Process.Start(procInfo);

TL;DR: It's fixed now, will upload update shortly.


UPD: Ok, now i'm really confused. To double check and compare difference i packed your example.exe with the old version of Appacker and... it works. It no longer opens empty console window. I even rebooted my PC, it still works, both if launched by double-click or via command prompt. I don't even...
So probably all i wrote above has nothing to do with the bug? It wasn't me, it fixed itself and now i can not reproduce the issue anymore. What is this magic?
Can you please try this Appacker v1.3.4 and check if it does anything for you?

SerGreen commented 6 years ago

Now that i think of it, empty console window was never an issue, wasn't it? I tested on a different PC and it doesn't do that. It was probably some glitch on my end that resolved itself later, and i thought that that was an issue you were talking about.
So i guess what you want to get fixed is that if you start example_packed.exe programmatically and listen to that process' stdout, you receive nothing, because you're actually attached to the unpacker.exe this way and not the target app. Well, this could be fixed by setting UseShellExecute = false this time: all output from the target app is redirected to the unpacker.exe (who launched it) and you can listen to the unpacker's output. But here's another issue with that: if you redirect stdout of the packed app to the Unpacker, you can not see the output anymore if you launch packed app normally ('cuz it's redirected to the window-less unpacker in the background).
I can think of three solutions right now:

  1. In your program instead of just starting packed_app.exe and listening to its stdout, you find the actual unpacked app's process, attach to it and listen its stdout. I can make it so unpacker exe will print to its output the PID of the unpacked app.
  2. Make a switch in Appacker for redirecting packed app's output, but this way packed_app.exe will be usable either in normal way or via listening its output in a program. Not an ideal solution.
  3. Maybe it's possible to make Unpacker re-broadcast unpacked app's output without stealing it? Not sure, but it would be perfect. Though only for output, you can't do that way input.
jochemstoel commented 6 years ago

Thank you very much for looking into this so deeply but based on your findings I think Appacker is not the right solution for this project.

SerGreen commented 6 years ago

Well, feel free to open new issues/suggestions if you'll come up with an idea to improve Appacker.
Cheers!

SerGreen commented 6 years ago

Ok, hold on, i may have found a way to fix this. I don't know why i haven't thought of this earlier, it is so simple:

There's a way to detect if stdout of the current process was redirected: Console.IsOutputRedirected. That means that i can simply check if output of the unpacker was redirected and if that's the case, launch target app and redirect its i/o too. So when you launch packed app in regular way, you see its output in its console, but if you programmatically redirect stdout of the packed app, you'll receive output stream of the target app.

Here's a demo screenshot. On the left is the regular launch (except the background window is actually hidden in the release build) and on the right is the listener app that launches another app and redirects its output to the console.
The only drawback is that i had to make unpacker.exe Console Application instead of Windows Application, and now its window briefly flashes when you launch a packed app. I can't find a way to make it hidden completely.

I have updated the v1.3.4 release, check it out and see if it works as you need.

SerGreen commented 6 years ago

I guess i'll close this issue as fixed.