I have a third-party console application. I need run it from my application but I cannot run it as a separate process (because I need to work with its dependencies: fill Import tables manually, setup hooks etc.). So probably I should call main function of this executable manually. Here is how I'm trying to do this:
- Load this EXE using 
auto hMod = LoadLibrary("console_app.exe") - Fill Import table of this exe manually
 - Get entry point of this EXE and call it
 
And I'm stuck with the last step.
Here is how I'm trying to call entry point:
void runMain(HINSTANCE hInst)
{
    typedef BOOL(WINAPI *PfnMain)(int, char*[]);
    auto imageNtHeaders = ImageNtHeader(hInst);
    auto pfnMain = (PfnMain)(DWORD_PTR)(imageNtHeaders->OptionalHeader.AddressOfEntryPoint + (DWORD_PTR)hInst);
    char* args[] = { R"(<console_app_path>)", R"(arg1)", R"(arg2)" };
    pfnMain(3, args);
}
It works. But it works as if there is no arguments.
Where am I wrong? How can I run an executable inside my process with arguments? Thanks.
UPDATE:
I've investigated how my particular third-party exe gets cmd arguments and found that:
- It doesn't import 
GetCommandLineat all and do not call it - After 
call _inittermcallargcandargvarguments are available throughcs:argcandcs:argv(see pictures below)

 - CMD arguments that I pass to my main console app are transferred to child EXE too.
 
Can you explain, please, what _initterm actually do and where CMD arguments are actually stored?
                        
You're calling the entry point of the application, not
int main(int, char**). Now you may have read that the entry point of a C++ program isint main(int, char**)but that's just a C++ perspective.The Win32 perspective is different; the entry point is a
int (*)(void);. The Visual Studio linker looks forint mainCRTStartup(void);and uses that, unless you specify another entry point with/ENTRY. The default implementation ofmainCRTStartupcallsGetCommandLine()to fill inargv[]before callingmain(argc,argv). There are also other things inmainCRTStartupwhich you might want to happen: run global ctors, initialize the CRT state, ...Of course, that's assuming the other program was compiled with Visual C++, but whatever language it's been written in, it must be calling
GetCommandLine.Now, for your problem, here's an interesting observation:
GetCommandLine()returns a writeable pointer. You can overwrite the existing command line. Of course, if you control the import tables, you decide whatGetCommandLinemeans. (Remember, as usual there are A and W variants).One warning: the MSVCRT isn't designed to be initialized twice, neither the static version nor the DLL one. So practically speaking you can't use it, and that will hurt.
[edit] Your update shows a call to
_initterm. That's a MSVCRT function, as I already hinted. Specifically,The MSVCRT DLL calls
GetCommandLine()on behalf of the EXE.