microsoft / cppwinrt

C++/WinRT
MIT License
1.66k stars 239 forks source link

command line of any (or an) windows executable module #291

Closed DBJDBJ closed 6 years ago

DBJDBJ commented 6 years ago

I need to produce command line data of any of several kinds of WIN 10 executable modules. Modern C++ abstraction to hold this is vector ... where sting_type is wide or narrow string.

Is it wide or narrow depends on the stdlib.h value wargv . If and when it is null we use it or we use argv.

Sound simple? But after several days (!) of cogitation the most modern C++ solution implemented in msvc I could come up with is this:

 #include <stdlib.h>
namespace {
#define _CRT_DECLARE_GLOBAL_VARIABLES_DIRECTLY

const auto  wargv_ = (__wargv);
const auto  argv_ = (__argv);
const auto  argc_ = (__argc);

#undef _CRT_DECLARE_GLOBAL_VARIABLES_DIRECTLY

namespace {

    using wvecT = std::vector<std::wstring>;
    using nvecT = std::vector<std::string >;

    // wargv_ !=  nullptr
    inline auto decide(std::true_type tt) {
        return wvecT{ wargv_, wargv_ + argc_ };
    }
    // wargv_ ==  nullptr
    inline auto decide( bool ft) {
        return nvecT{ argv_, argv_ + argc_ };
    }
}

auto cli_data = []() {
    return decide( 
        wargv_ != NULL 
        ? std::true_type{}
        : false
    );
};
} // nspace

usage is then simple:

auto my_cli = cli_data() ;
// 
auto  this_module_file_name = my_cli[0] ;

This is the solution even after VS 15.5 update. Can anyone offer a better one using msvc?

How is (if it is) cppWinRT obtaining the command line of executable module it is running in?

Please advise ...

Scottj1s commented 6 years ago

This question isn't specifically about C++/WinRT usage. I'd advise posting it to a more general forum like stackoverflow.

tim-weis commented 6 years ago

A C++/WinRT application obtains the command line like any other application: By calling GetCommandLine (either directly, or by using the facilities provided by the CRT), which reads out the value stored in the PEB. There's also a convenience implementation (CommandLineToArgvW) to parse the command line and decompose it into individual arguments.

If "modern" is your goal, you shouldn't be using ANSI encoding at all. Once you remove all ANSI clutter from your code, you'll see the complexity significantly go down.

Besides, if what you really want is the module name of the executing code, call GetModuleFileName (and friends). This returns the real thing, and isn't subject to someone passing you unexpected command line arguments.

At any rate, this is really a generic question about any Windows executable, not related to C++/WinRT at all, so you might want to consider taking it to another site, as suggested by Scott Jones.

DBJDBJ commented 6 years ago

@Scottj1s

cppWinRT is astonishing work. The context of my comments is that cppWinRT problem is msvc. By msvc team own admission C++17 is only 75% implemented in msvc. cppWinRT mandates C++17. But which compiler is to be used, one has to ask?

Relevance to the cppWinRT comes from the fact that the msvc (+ win10 sdk ) code I have presented has obvious utility but it is ridiculous because it is a workaround so that it is possible to compile it in msvc the latest ... whatever is the rev number after VS 15.5 update ...

Workaround done in order that msvc can compile something are leaving technical debt inside cppWinRT.

  1. By " modern", I mean nothing else but "modern C++" , C++17 and so on
  2. I do not want to use WIN32 API to obtain command line of the executable module
  3. wargv, argv, __argc are in the stdlib.h and as a such perfectly OK to use and legal in UCRT.

cppWinRT mandates C++17. The code above is simple if using gcc/clang ... it is not of course part of cppWinRT but shows what simple lambdas msvc C++17 can not do currently, and leaves one wondering about the workarounds cppWinRT team had to do to make it compile with msvc c++17.

Good example revolves around the modern C++ code to obtain command line as a vector of narrow or wide strings. Core lambda for that is still not possible in msvc but it is in gcc and clang .. This simple lambda makes simple API possible:

auto cli_data = obtain_cli () ; // cli_data is wide or narrow strings vector, depending on the runtime situation

I had no time to reverse engineer cppWinRT because there is no documentation. The little I have seen has this curious omission of auto, lambda and if-constexpr , c++17 features.

I think the wise thing to do would be to wait for REDSTONE 4 ... as the never given promise of UCRT, SDK, cppWinRT and VS delivering full C++17 conformance.

CVipulS commented 6 years ago

Assuming Compiler Explorer is using the newest 15.5 preview 4 (1912) and not 15.2 (1910) as the VS version, the argument to it must still be replaced from -std=c++1z to /std:c++latest Lambdas arrived with C++11, IIRC. Have you thought of more modern approach, like say, structured bindings?