Это ответ на вторую часть вопроса, но я не могу передать параметры в программу, т. Е. Как получить аргументы командной строки в приложении Visual C ++ для Windows.
Самый простой, но также и самый ограниченный способ - использовать аргументы стандарта C ++ main
,
int main( int argc, char* argv[] )
{
// Whatever, e.g.
vector<string> const args( argv, argv + argc );
}
Стандарт C ++ настоятельно рекомендует, чтобы эти аргументы были закодированы с помощью некоторого многобайтового набора символов , например UTF-8,
C ++ 11 §3.6.1 / 2 :
& ldquo; Если argc
отлично от нуля, эти аргументы должны быть указаны в argv[0]
через argv[argc-1]
как указатели на начальные символы многобайтовых строк с нулевым символом в конце (NTMBS) (17.5.2.1.4.2) и argv[0]
должны быть указателем на начальный символ NTMBS, который представляет имя, используемое для вызова программы или ""
. & rdquo;
Однако во время первого стандарта C ++, в 1998 году, ни * nix world, ни Windows-соглашение не делали этого. Вместо этого соглашением было передавать аргументы с определенной кодировкой символов для конкретной локали. Мир Linux почти сразу начал переход к UTF-8, в то время как Windows этого не сделала, так что до 2012 года в Windows стандартных аргументов main
было недостаточно для передачи, например. произвольные имена файлов & hellip;
К счастью, в Windows командная строка , которая передается процессу и доступна через функцию API GetCommandLine
, кодируется в кодировке UTF-16, что означает, что любое имя файла (и действительно любой текст) можно пропустить.
С третьей стороны, функция API, которая обеспечивает стандартный синтаксический анализ командной строки, CommandLineToArgvW
, имеет как минимум одного глупого жука и, возможно, more & hellip; И предположительно нестандартная функция запуска Visual C ++ Unicode C ++ wmain
имеет аргументы, предоставляемые этой функцией. Таким образом, для достижения наилучших результатов, до тех пор, пока это не будет исправлено, следует использовать некоторый правильный синтаксический анализ командной строки, созданный в домашних условиях, например как показано в приведенной ниже программе (я только что выбрал специальную «личную программу», которую я создал на прошлой неделе, она похожа на Windows 2000 Resource Kit & rsquo; s timethis
):
// A program to measure the execution time of another program.
// Based vaguely on Jeffrey Richter's "timep" program in
// the 2nd edition of "Win32 System Programming".
//
// Author: Alf P. Steinbach, 2012. License: Boost license 1.0.
#undef UNICODE
#define UNICODE
#undef STRICT
#define STRICT
#undef NOMINMAX
#define NOMINMAX
#include <windows.h>
#include <shlwapi.h> // PathGetCharType
#include <assert.h> // assert
#include <functional> // std::function
#include <iomanip> // set::setfill, std::setw
#include <iostream> // std::wcout, std::endl
#include <sstream> // std::wostringstream
#include <stddef.h> // ptrdiff_t
#include <stdexcept> // std::runtime_error, std::exception
#include <stdint.h> // int64_t
#include <string> // std::string
#include <type_traits> // std::is_fundamental
#include <utility> // std::move
using namespace std;
#if !defined( CPP_STATIC_ASSERT )
# define CPP_STATIC_ASSERT( e ) static_assert( e, #e )
#endif
#if !defined( CPP_NORETURN )
# define CPP_NORETURN [[noreturn]]
#endif
// MSVC workaround: "#define CPP_NORETURN __declspec( noreturn )"
// clang workaround: "#define CPP_NORETURN __attribute__(( noreturn ))"
namespace cpp {
namespace detail {
template< class Destination, class Source >
class ImplicitCast
{
public:
static Destination value( Source const v )
{
return static_cast<Destination>( v );
}
};
template< class Source >
class ImplicitCast< bool, Source >
{
public:
static bool value( Source const v )
{
return !!v; // Shuts up Visual C++ sillywarning about performance.
}
};
};
template< class Destination, class Source >
Destination implicitCast( Source const v )
{
CPP_STATIC_ASSERT( is_fundamental< Destination >::value );
CPP_STATIC_ASSERT( is_fundamental< Source >::value );
return detail::ImplicitCast< Destination, Source >::value( v );
}
typedef ptrdiff_t Size;
inline bool hopefully( bool const c ) { return c; }
inline CPP_NORETURN bool throwX( string const& s )
{
throw runtime_error( s );
}
inline CPP_NORETURN bool throwX( string const& s, exception const& reasonX )
{
throwX( s + "\n!Because - " + reasonX.what() );
}
class ScopeGuard
{
private:
function<void()> cleanup_;
ScopeGuard( ScopeGuard const& ); // No such.
ScopeGuard& operator=( ScopeGuard const& ); // No such.
public:
~ScopeGuard() { cleanup_(); }
ScopeGuard( function<void()> const cleanup )
: cleanup_( cleanup )
{}
};
class SubstringRef
{
private:
wchar_t const* start_;
wchar_t const* end_;
public:
Size length() const { return end_ - start_; }
wchar_t const* start() const { return start_; }
wchar_t const* end() const { return end_; }
SubstringRef( wchar_t const* start, wchar_t const* end )
: start_( start )
, end_( end )
{}
};
inline void skipWhitespace( wchar_t const*& p )
{
while( *p != L'\0' && iswspace( *p ) ) { ++p; }
}
inline wchar_t const* theAfterWhitespacePart( wchar_t const* p )
{
skipWhitespace( p );
return p;
}
inline void invert( bool& b ) { b = !b; }
} // namespace cpp
namespace winapi {
using cpp::hopefully;
using cpp::invert;
using cpp::Size;
using cpp::skipWhitespace;
using cpp::SubstringRef;
using cpp::theAfterWhitespacePart;
using cpp::throwX;
namespace raw {
typedef DWORD DWord;
typedef FILETIME FileTime;
typedef HANDLE Handle;
typedef PROCESS_INFORMATION ProcessInformation;
typedef SYSTEMTIME SystemTime;
typedef WORD Word;
} // namespace raw
// The following logic is mainly a workaround for a bug in CommandLineToArgvW.
// See [http://preview.tinyurl.com/CommandLineToArgvWBug].
inline SubstringRef nextArgumentIn( wchar_t const* const commandLine )
{
wchar_t const* p = commandLine;
skipWhitespace( p );
wchar_t const* const start = p;
bool isInQuotedPart = false;
while( *p != L'\0' && (isInQuotedPart || !iswspace( *p ) ) )
{
if( *p == L'\"' ) { invert( isInQuotedPart ); }
++p;
}
return SubstringRef( start, p );
}
// This corresponds essentially to the argument of wWinMain(...).
inline wchar_t const* commandLineArgPart()
{
SubstringRef const programSpec = nextArgumentIn( GetCommandLine() );
return theAfterWhitespacePart( programSpec.end() );
}
class ProcessInfo
{
private:
raw::ProcessInformation info_;
ProcessInfo( ProcessInfo const& ); // No such.
ProcessInfo& operator=( ProcessInfo const& ); // No such.
public:
raw::ProcessInformation& raw() { return info_; }
raw::Handle handle() const { return info_.hProcess; }
~ProcessInfo()
{
::CloseHandle( info_.hThread );
::CloseHandle( info_.hProcess );
}
ProcessInfo(): info_() {}
ProcessInfo( ProcessInfo&& other )
: info_( move( other.info_ ) )
{
other.info_ = raw::ProcessInformation(); // Zero.
}
};
inline ProcessInfo createProcess( wchar_t const commandLine[] )
{
STARTUPINFO startupInfo = { sizeof( startupInfo ) };
ProcessInfo processInfo;
wstring mutableCommandLine( commandLine );
mutableCommandLine += L'\0';
GetStartupInfo( &startupInfo );
bool const creationSucceeded = !!CreateProcess (
nullptr, // LPCTSTR lpApplicationName,
&mutableCommandLine[0], // LPTSTR lpCommandLine,
nullptr, // LPSECURITY_ATTRIBUTES lpProcessAttributes,
nullptr, // LPSECURITY_ATTRIBUTES lpThreadAttributes,
true, // BOOL bInheritHandles,
NORMAL_PRIORITY_CLASS, // DWORD dwCreationFlags,
nullptr, // LPVOID lpEnvironment,
nullptr, // LPCTSTR lpCurrentDirectory,
&startupInfo, // LPSTARTUPINFO lpStartupInfo,
&processInfo.raw() // LPPROCESS_INFORMATION lpProcessInformation
);
hopefully( creationSucceeded )
|| throwX( "winapi::createProcess: CreateProcess failed" );
return processInfo;
}
inline raw::Handle dup(
raw::Handle const h,
raw::DWord const desiredAccess,
bool inheritable = false
)
{
raw::Handle result = 0;
bool const wasDuplicated = !!DuplicateHandle(
GetCurrentProcess(), h,
GetCurrentProcess(), &result,
desiredAccess,
inheritable,
0 // options
);
hopefully( wasDuplicated )
|| throwX( "winapi::dup: DuplicateHandle failed" );
assert( result != 0 );
return result;
}
inline int64_t mSecsFromRelative( raw::FileTime const t )
{
ULARGE_INTEGER asLargeInt;
asLargeInt.u.HighPart = t.dwHighDateTime;
asLargeInt.u.LowPart = t.dwLowDateTime;
return asLargeInt.QuadPart/10000;
}
SubstringRef filenamePart( SubstringRef const& path )
{
wchar_t const* p = path.end();
while( p != path.start() && PathGetCharType( *p ) != GCT_SEPARATOR )
{
--p;
}
if( PathGetCharType( *p ) == GCT_SEPARATOR ) { ++p; }
return SubstringRef( p, path.end() );
}
} // namespace winapi
winapi::ProcessInfo createProcess( wchar_t const commandLine[], char const errMsg[] )
{
try{ return winapi::createProcess( commandLine ); }
catch( exception const& x ) { cpp::throwX( errMsg, x ); }
}
winapi::raw::Handle run( wchar_t const commandLine[] )
{
namespace raw = winapi::raw;
using cpp::hopefully;
using cpp::throwX;
using winapi::dup;
using winapi::ProcessInfo;
static char const* const createErrMsg = "Failed to create process";
ProcessInfo const process = createProcess( commandLine, createErrMsg );
// Early handle duplication ensures that one has the required rights.
raw::Handle const accessibleHandle =
dup( process.handle(), PROCESS_QUERY_INFORMATION | SYNCHRONIZE );
raw::DWord const waitResult = WaitForSingleObject( process.handle(), INFINITE );
hopefully( waitResult == WAIT_OBJECT_0 )
|| throwX( "Failed waiting for process termination." );
return accessibleHandle;
}
class Interval
{
private:
int hours_;
int minutes_;
int seconds_;
int milliseconds_;
public:
int msecs() const { return milliseconds_; }
int seconds() const { return seconds_; }
int minutes() const { return minutes_; }
int hours() const { return hours_; }
Interval( int msecs, int seconds = 0, int minutes = 0, int hours = 0 )
: milliseconds_( msecs )
, seconds_( seconds )
, minutes_( minutes )
, hours_( hours )
{
assert( unsigned( hours ) < 24 );
assert( unsigned( minutes ) < 60 );
assert( unsigned( seconds ) < 60 );
assert( unsigned( msecs ) < 1000 );
}
static Interval fromMSecs( int msecs )
{
int const totalSeconds = msecs / 1000;
int const totalMinutes = totalSeconds / 60;
int const totalHours = totalMinutes / 24;
return Interval(
msecs % 1000, totalSeconds % 60, totalMinutes %60, totalHours
);
}
};
wostream& operator<<( wostream& stream, Interval const& t )
{
wostringstream formatter;
formatter << setfill( L'0' );
formatter
<< setw( 2 ) << t.hours() << ":"
<< setw( 2 ) << t.minutes() << ":"
<< setw( 2 ) << t.seconds() << "."
<< setw( 3 ) << t.msecs();
return (stream << formatter.str());
}
string narrowStringFrom( cpp::SubstringRef const& s )
{
return string( s.start(), s.end() ); // Non-ANSI characters => garbage.
}
void cppMain()
{
namespace raw = winapi::raw;
using cpp::hopefully;
using cpp::implicitCast;
using cpp::ScopeGuard;
using cpp::SubstringRef;
using cpp::throwX;
using winapi::commandLineArgPart;
using winapi::filenamePart;
using winapi::mSecsFromRelative;
using winapi::nextArgumentIn;
SubstringRef const programSpec = nextArgumentIn( GetCommandLine() );
SubstringRef const programName = filenamePart( programSpec );
wchar_t const* const otherCommandLine = commandLineArgPart();
hopefully( nextArgumentIn( otherCommandLine ).length() > 0 )
|| throwX( "Usage: " + narrowStringFrom( programName ) + " command" );
raw::DWord const startMSecs = GetTickCount();
raw::Handle const finishedProcess = run( otherCommandLine );
raw::DWord const endMSecs = GetTickCount();
raw::DWord const realElapsedMSecs = endMSecs - startMSecs;
ScopeGuard const closingHandle( [=]() { CloseHandle( finishedProcess ); } );
Interval const realElapsedTime = Interval::fromMSecs( realElapsedMSecs );
static char const* const commandLineLabel = "Command line: ";
static char const* const rElapsedTimeLabel = "External elapsed time: ";
static char const* const pElapsedTimeLabel = "In-process elapsed time: ";
static char const* const kernelTimeLabel = "In-process kernel time: ";
static char const* const userTimeLabel = "In-process user time: ";
wclog << endl;
wclog << commandLineLabel << "[" << otherCommandLine << "]" << endl;
wclog << rElapsedTimeLabel << realElapsedTime << endl;
raw::FileTime creationTime;
raw::FileTime exitTime;
raw::FileTime kernelTime;
raw::FileTime userTime;
bool const timesWereObtained = !!GetProcessTimes(
finishedProcess, &creationTime, &exitTime, &kernelTime, &userTime
);
hopefully( timesWereObtained )
|| throwX( "cppMain: GetProcessTimes failed" );
int const elapsedTimeMSecs= implicitCast<int>(
mSecsFromRelative( exitTime ) - mSecsFromRelative( creationTime )
);
int const kernelTimeMSecs = implicitCast<int>( mSecsFromRelative( kernelTime ) );
int const userTimeMSecs = implicitCast<int>( mSecsFromRelative( userTime ) );
wclog << pElapsedTimeLabel << Interval::fromMSecs( elapsedTimeMSecs ) << endl;
wclog << kernelTimeLabel << Interval::fromMSecs( kernelTimeMSecs ) << endl;
wclog << userTimeLabel << Interval::fromMSecs( userTimeMSecs ) << endl;
}
int main()
{
try
{
cppMain();
return EXIT_SUCCESS;
}
catch( exception const& x )
{
wcerr << "!" << x.what() << endl;
}
return EXIT_FAILURE;
}