windows: Trick to get UTF-8 encoded argv in main entry point

- Adapt exifprint to the new wmain strategy
- Delete have_unicode_path
- wmain does not work with MSYS & MinGW
- cmake: entry point via cmake instead of pragma
- cmake: better doc for MSVC flags
- Fix entry point in sample apps
- Adapt CMake code to work with MSVC & MinGW
main
Luis Díaz Más 3 years ago
parent 7933ff401d
commit fdfb295cc4

@ -9,7 +9,7 @@ project(exiv2 # use TWEAK to categorize the build
# 1.00.0.20 = RC2 Preview # 1.00.0.20 = RC2 Preview
# 1.00.0.29 = RC2 Development # 1.00.0.29 = RC2 Development
DESCRIPTION "Exif/IPTC/Xmp C++ metadata library and tools plus ICC Profiles, Previews and more." DESCRIPTION "Exif/IPTC/Xmp C++ metadata library and tools plus ICC Profiles, Previews and more."
LANGUAGES CXX LANGUAGES C CXX
) )
if(NOT CMAKE_BUILD_TYPE) if(NOT CMAKE_BUILD_TYPE)

@ -167,13 +167,7 @@ if(MSVC)
string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
endif () endif ()
# Object Level Parallelism add_compile_options(/MP) # Object Level Parallelism
add_compile_options(/MP) add_compile_options(/utf-8) # Set source and execution character sets to UTF-8
add_definitions(-DNOMINMAX) # This definition is not only needed for Exiv2 but also for xmpsdk add_definitions(-DNOMINMAX) # This definition is not only needed for Exiv2 but also for xmpsdk
# https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/
if (MSVC_VERSION GREATER_EQUAL "1910") # VS2017 and up
add_compile_options("/Zc:__cplusplus")
endif()
endif() endif()

@ -114,11 +114,20 @@ list(APPEND APPLICATIONS remotetest)
# ****************************************************************************** # ******************************************************************************
foreach(application ${APPLICATIONS}) foreach(application ${APPLICATIONS})
target_link_libraries(${application} PRIVATE exiv2lib) target_link_libraries(${application} PRIVATE exiv2lib)
if(MSVC)
target_link_libraries(${application} PRIVATE wmain)
target_link_options(${application} PRIVATE "/ENTRY:wWinMainCRTStartup")
endif()
if (MINGW)
target_link_libraries(${application} PRIVATE wmain)
target_compile_options(${application} PRIVATE -municode)
target_link_options(${application} PRIVATE -municode)
endif()
if( EXIV2_ENABLE_PNG ) if( EXIV2_ENABLE_PNG )
target_link_libraries(${application} PRIVATE ${ZLIB_LIBRARIES} ) target_link_libraries(${application} PRIVATE ${ZLIB_LIBRARIES} )
if (MSVC) if (MSVC)
set_target_properties(${application} PROPERTIES LINK_FLAGS "/ignore:4099") # Ignore missing PDBs set_target_properties(${application} PROPERTIES LINK_FLAGS "/ignore:4099") # Ignore missing PDBs
endif() endif()
endif() endif()
endforeach() endforeach()

@ -25,25 +25,6 @@
#include <cassert> #include <cassert>
#include <regex> #include <regex>
// https://github.com/Exiv2/exiv2/issues/468
#if defined(EXV_UNICODE_PATH) && defined(__MINGW__)
#undef EXV_UNICODE_PATH
#endif
#ifdef EXV_UNICODE_PATH
#define _tchar wchar_t
#define _tstrcmp wcscmp
#define _t(s) L##s
#define _tcout wcout
#define _tmain wmain
#else
#define _tchar char
#define _tstrcmp strcmp
#define _t(s) s
#define _tcout cout
#define _tmain main
#endif
// copied from src/tiffvisitor_int.cpp // copied from src/tiffvisitor_int.cpp
static const Exiv2::TagInfo* findTag(const Exiv2::TagInfo* pList,uint16_t tag) static const Exiv2::TagInfo* findTag(const Exiv2::TagInfo* pList,uint16_t tag)
{ {
@ -52,31 +33,32 @@ static const Exiv2::TagInfo* findTag(const Exiv2::TagInfo* pList,uint16_t tag)
} }
int _tmain(int argc, _tchar* const argv[]) int main(int argc, char* const argv[])
try { try {
setlocale(LC_CTYPE, ".utf8");
Exiv2::XmpParser::initialize(); Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate); ::atexit(Exiv2::XmpParser::terminate);
#ifdef EXV_ENABLE_BMFF #ifdef EXV_ENABLE_BMFF
Exiv2::enableBMFF(); Exiv2::enableBMFF();
#endif #endif
const _tchar* prog = argv[0]; const char* prog = argv[0];
if (argc == 1) { if (argc == 1) {
std::_tcout << _t("Usage: ") << prog << _t(" [ [--lint] path | --version | --version-test ]") << std::endl; std::cout << "Usage: " << prog << " [ [--lint] path | --version | --version-test ]" << std::endl;
return 1; return 1;
} }
int rc = 0 ; int rc = 0 ;
const _tchar* file = argv[1]; const char* file = argv[1];
bool bLint = _tstrcmp(file,_t("--lint")) == 0 && argc == 3; bool bLint = strcmp(file, "--lint") == 0 && argc == 3;
if ( bLint ) file= argv[2]; if ( bLint ) file= argv[2];
if ( _tstrcmp(file,_t("--version")) == 0 ) { if ( strcmp(file,"--version") == 0 ) {
std::vector<std::regex> keys; std::vector<std::regex> keys;
Exiv2::dumpLibraryInfo(std::cout,keys); Exiv2::dumpLibraryInfo(std::cout,keys);
return rc; return rc;
} else if ( _tstrcmp(file,_t("--version-test")) == 0 ) { } else if ( strcmp(file,"--version-test") == 0 ) {
// verifies/test macro EXIV2_TEST_VERSION // verifies/test macro EXIV2_TEST_VERSION
// described in include/exiv2/version.hpp // described in include/exiv2/version.hpp
std::cout << "EXV_PACKAGE_VERSION " << EXV_PACKAGE_VERSION << std::endl std::cout << "EXV_PACKAGE_VERSION " << EXV_PACKAGE_VERSION << std::endl

@ -287,6 +287,23 @@ if(EXIV2_BUILD_EXIV2_COMMAND)
target_include_directories(exiv2 PRIVATE ${Intl_INCLUDE_DIRS}) target_include_directories(exiv2 PRIVATE ${Intl_INCLUDE_DIRS})
endif() endif()
if(MSVC OR MINGW)
# Trick to get properly UTF-8 encoded argv
# More info at: https://github.com/huangqinjin/wmain
add_library(wmain STATIC wmain.c)
target_link_libraries(exiv2 PRIVATE wmain)
endif()
if (MSVC)
target_link_options(wmain INTERFACE /WHOLEARCHIVE:$<TARGET_FILE:wmain>)
target_link_options(exiv2 PRIVATE "/ENTRY:wWinMainCRTStartup")
endif()
if (MINGW)
target_compile_options(exiv2 PRIVATE -municode)
target_link_options(exiv2 PRIVATE -municode)
endif()
if (USING_CONAN AND WIN32 AND EXISTS ${PROJECT_BINARY_DIR}/conanDlls) if (USING_CONAN AND WIN32 AND EXISTS ${PROJECT_BINARY_DIR}/conanDlls)
# In case of using conan recipes with their 'shared' option turned on, we will have dlls of # In case of using conan recipes with their 'shared' option turned on, we will have dlls of
# the 3rd party dependencies in the conanDlls folder. # the 3rd party dependencies in the conanDlls folder.

@ -120,6 +120,8 @@ namespace {
// Main // Main
int main(int argc, char* const argv[]) int main(int argc, char* const argv[])
{ {
setlocale(LC_CTYPE, ".utf8");
Exiv2::XmpParser::initialize(); Exiv2::XmpParser::initialize();
::atexit(Exiv2::XmpParser::terminate); ::atexit(Exiv2::XmpParser::terminate);
#ifdef EXV_ENABLE_BMFF #ifdef EXV_ENABLE_BMFF

@ -332,7 +332,6 @@ void Exiv2::dumpLibraryInfo(std::ostream& os,const std::vector<std::regex>& keys
int have_strings =0; int have_strings =0;
int have_sys_types =0; int have_sys_types =0;
int have_unistd =0; int have_unistd =0;
int have_unicode_path=0;
int enable_bmff =0; int enable_bmff =0;
int enable_webready =0; int enable_webready =0;
@ -512,7 +511,6 @@ void Exiv2::dumpLibraryInfo(std::ostream& os,const std::vector<std::regex>& keys
output(os,keys,"have_strings" ,have_strings ); output(os,keys,"have_strings" ,have_strings );
output(os,keys,"have_sys_types" ,have_sys_types ); output(os,keys,"have_sys_types" ,have_sys_types );
output(os,keys,"have_unistd" ,have_unistd ); output(os,keys,"have_unistd" ,have_unistd );
output(os,keys,"have_unicode_path" ,have_unicode_path);
output(os,keys,"enable_bmff" ,enable_bmff ); output(os,keys,"enable_bmff" ,enable_bmff );
output(os,keys,"enable_webready" ,enable_webready ); output(os,keys,"enable_webready" ,enable_webready );
output(os,keys,"enable_nls" ,enable_nls ); output(os,keys,"enable_nls" ,enable_nls );

@ -0,0 +1,40 @@
#include <windows.h>
extern int __cdecl main();
int wmain(int argc, wchar_t* argv[])
{
char** args;
int nbytes = sizeof(char*) * (argc + 1);
HANDLE heap = GetProcessHeap();
for (int i = 0; i < argc; ++i)
nbytes += WideCharToMultiByte(CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL);
args = HeapAlloc(heap, 0, nbytes);
args[0] = (char*)(args + argc + 1);
for (int i = 0; i < argc; ++i)
args[i+1] = args[i] + WideCharToMultiByte(CP_UTF8, 0, argv[i], -1, args[i], nbytes, NULL, NULL);
args[argc] = NULL;
argc = main(argc, args);
HeapFree(heap, 0, args);
return argc;
}
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
{
(void) hInstance;
(void) hPrevInstance;
(void) lpCmdLine;
(void) nCmdShow;
int argc;
wchar_t** argv;
argv = CommandLineToArgvW(GetCommandLineW(), &argc);
argc = wmain(argc, argv);
LocalFree(argv);
return argc;
}
Loading…
Cancel
Save