/*
* Licensed to the Apache Software Foundation ( ASF ) under one
* or more contributor license agreements . See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership . The ASF licenses this file
* to you under the Apache License , Version 2 . 0 ( the
* " License " ) ; you may not use this file except in compliance
* with the License . You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing ,
* software distributed under the License is distributed on an
* " AS IS " BASIS , WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND , either express or implied . See the License for the
* specific language governing permissions and limitations
* under the License .
*/
/*
* Author : Tomas Holy
*/
#ifndef _WIN32_WINNT
#define _WIN32_WINNT
0 x05010100
#endif
#include <shlobj.h>
#include <winnls.h>
#include "nblauncher.h"
#include "../../../platform/o.n.bootstrap/launcher/windows/utilsfuncs.h"
#include "../../../platform/o.n.bootstrap/launcher/windows/argnames.h"
#include "../../../platform/o.n.bootstrap/launcher/windows/nbexecloader.h"
using namespace std;
const char *NbLauncher::NBEXEC_FILE_PATH = NBEXEC_DLL;
const char *NbLauncher::OPT_NB_DEFAULT_USER_DIR =
"netbeans_default_userdir=" ;
const char *NbLauncher::OPT_NB_DEFAULT_CACHE_DIR =
"netbeans_default_cachedir=" ;
const char *NbLauncher::OPT_NB_DEFAULT_OPTIONS =
"netbeans_default_options=" ;
const char *NbLauncher::OPT_NB_EXTRA_CLUSTERS =
"netbeans_extraclusters=" ;
const char *NbLauncher::OPT_NB_JDK_HOME =
"netbeans_jdkhome=" ;
const char *NbLauncher::ENV_USER_PROFILE =
"USERPROFILE" ;
const char *NbLauncher::HOME_TOKEN =
"${HOME}" ;
const char *NbLauncher::DEFAULT_USERDIR_ROOT_TOKEN =
"${DEFAULT_USERDIR_ROOT}" ;
const char *NbLauncher::DEFAULT_CACHEDIR_ROOT_TOKEN =
"${DEFAULT_CACHEDIR_ROOT}" ;
const char *NbLauncher::BASEDIR_TOKEN =
"${BASEDIR}" ;
const char *NbLauncher::NETBEANS_DIRECTORY =
"\\NetBeans\\" ;
const char *NbLauncher::NETBEANS_CACHES_DIRECTORY =
"\\NetBeans\\Cache\\" ;
const char *NbLauncher::CON_ATTACH_MSG =
"\n\nThe launcher has determined that the parent process has a console and will reuse it for its own console output.\n"
"Closing the console will result in termination of the running program.\n"
"Use '--console suppress' to suppress console output.\n"
"Use '--console new' to create a separate console window.\n" ;
const char *NbLauncher::staticOptions[] = {
"-J-Dnetbeans.importclass=org.netbeans.upgrade.AutoUpgrade" ,
"--branding" ,
"nb"
};
NbLauncher::NbLauncher() {
}
NbLauncher::NbLauncher(
const NbLauncher& orig) {
}
NbLauncher::~NbLauncher() {
}
int NbLauncher::start(
char *cmdLine) {
CmdArgs args(
50 );
args.addCmdLine(cmdLine);
return start(args.getCount(), args.getArgs());
}
int NbLauncher::start(
int argc,
char *argv[]) {
SetErrorMode(SetErrorMode(
0 ) | SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
DWORD parentProcID =
0 ;
if (!checkLoggingArg(argc, argv,
true ) || !setupProcess(argc, argv, parentProcID, CON_AT
TACH_MSG) || !initBaseNames() || !readClusterFile()) {
return -1 ;
}
parseConfigFile((baseDir + "\\etc\\" + getAppName() + ".conf" ).c_str());
if (!parseArgs(argc, argv)) {
return -1 ;
}
string oldUserDir = userDir;
parseConfigFile((userDir + "\\etc\\" + getAppName() + ".conf" ).c_str());
userDir = oldUserDir;
addExtraClusters();
string nbexecPath;
SetDllDirectory(baseDir.c_str());
if (dirExists(platformDir.c_str())) {
nbexecPath = platformDir;
} else {
nbexecPath = baseDir + '\\' + platformDir;
}
if (!dirExists(nbexecPath.c_str())) {
logErr(false , true , "Could not find platform cluster:\n%s" , nbexecPath.c_str());
return false ;
}
CmdArgs newArgs(argc + 20 );
addSpecificOptions(newArgs);
if (!clusters.empty()) {
newArgs.add(ARG_NAME_CLUSTERS);
newArgs.add(clusters.c_str());
}
if (!userDir.empty()) {
newArgs.add(ARG_NAME_USER_DIR);
newArgs.add(userDir.c_str());
}
if (!defUserDirRoot.empty()) {
newArgs.add(ARG_DEFAULT_USER_DIR_ROOT);
newArgs.add(defUserDirRoot.c_str());
}
if (!cacheDir.empty() && !customUserDirFound) {
newArgs.add(ARG_NAME_CACHE_DIR);
newArgs.add(cacheDir.c_str());
}
if (!nbOptions.empty()) {
newArgs.addCmdLine(nbOptions.c_str());
}
for (int i = 0 ; i < argc; i++) {
newArgs.add(argv[i]);
}
if (!jdkHome.empty()) {
newArgs.add(ARG_NAME_JDKHOME);
newArgs.add(jdkHome.c_str());
}
if (parentProcID) {
newArgs.add(ARG_NAME_LA_PPID);
char tmp[16 ] = "" ;
newArgs.add(itoa(parentProcID, tmp, 10 ));
}
nbexecPath += NBEXEC_FILE_PATH;
const char *curDir = getCurrentDir();
if (curDir) {
char olddir[MAX_PATH];
DWORD rc = GetCurrentDirectory(MAX_PATH, olddir);
if (rc == 0 ) {
logErr(true , false , "Failed to get current directory" );
} else {
string od = string(olddir);
od.insert(0 , "-J-Dnetbeans.user.dir=" );
newArgs.add(od.c_str());
}
logMsg("Changing current directory to: \" %s\"" , curDir);
SetCurrentDirectory(curDir);
}
NBExecLoader loader;
return loader.start(nbexecPath.c_str(), newArgs.getCount(), newArgs.getArgs());
}
UINT GetAnsiCodePageForLocale(LCID lcid) {
// See https://devblogs.microsoft.com/oldnewthing/20161007-00/?p=94475
UINT acp;
int sizeInChars = sizeof (acp) / sizeof (TCHAR);
if (GetLocaleInfo(lcid,
LOCALE_IDEFAULTANSICODEPAGE | LOCALE_RETURN_NUMBER,
reinterpret_cast <LPTSTR>(&acp),
sizeInChars) != sizeInChars)
{
return 0 ;
}
return acp;
}
bool NbLauncher::initBaseNames() {
char path[MAX_PATH] = "" ;
getCurrentModulePath(path, MAX_PATH);
logMsg("Executable: %s" , path);
char *bslash = strrchr(path, '\\' );
if (!bslash) {
return false ;
}
appName = bslash + 1 ;
appName.erase(appName.rfind('.' ));
if (ARCHITECTURE == 64 ) {
appName = appName.erase(appName.length() - 2 );
}
logMsg("Application name: %s" , appName.c_str());
*bslash = '\0' ;
bslash = strrchr(path, '\\' );
if (!bslash) {
return false ;
}
*bslash = '\0' ;
/* Useful messages for debugging character set issues. On Java versions where
https : //bugs.openjdk.org/browse/JDK-8272352 has been fixed, NetBeans should now run fine when
there are Unicode characters in the NetBeans installation path , the JDK path , the user / cache
directory paths , or in the java . io . tmpdir path ( the latter sometimes being a problem for JNA ,
which is used by FlatLAF ) . Since the JVM is started in - process via JNI , the Java environment
will inherit the UTF - 8 code page setting that we have set in the launcher ' s application
manifest , without requiring the user to change regional settings in the Control Panel . ( JEP 400
might eventually do something similar for the java . exe / javaw . exe executables . See
https://www.mail-archive.com/core-libs-dev@openjdk.java.net/msg80489.html .) */
logMsg("ANSI code page per GetACP() : %d" , GetACP());
logMsg("ANSI code page per GetConsoleCP() : %d" , GetConsoleCP());
logMsg("ANSI code page for GetThreadLocale() : %d" , GetAnsiCodePageForLocale(GetThreadLocale()));
logMsg("ANSI code page for GetUserDefaultLCID() : %d" , GetAnsiCodePageForLocale(GetUserDefaultLCID()));
logMsg("ANSI code page for GetSystemDefaultLCID(): %d" , GetAnsiCodePageForLocale(GetSystemDefaultLCID()));
baseDir = path;
logMsg("Base dir: %s" , baseDir.c_str());
getDefaultUserDirRoot();
getDefaultCacheDirRoot();
getUserHome();
return true ;
}
void NbLauncher::addCluster(const char *cluster) {
class SetCurDir {
public :
SetCurDir(const char *dir) {
oldCurDir[0 ] = '\0' ;
DWORD rc = GetCurrentDirectory(MAX_PATH, oldCurDir);
if (rc == 0 ) {
logErr(true , false , "Failed to get current directory" );
return ;
}
if (rc > MAX_PATH) {
logMsg("Failed to get current directory, buffer is too small." );
return ;
}
if (!SetCurrentDirectory(dir)) {
logErr(true , true , "Failed to set current directory to \" %s\"" , dir);
oldCurDir[0 ] = '\0' ;
}
}
~SetCurDir() {
if (oldCurDir[0 ]) {
if (!SetCurrentDirectory(oldCurDir)) {
logErr(true , true , "Failed to set current directory to \" %s\"" , oldCurDir);
}
}
}
private :
char oldCurDir[MAX_PATH];
};
logMsg("addCluster: %s" , cluster);
SetCurDir setCurDir(baseDir.c_str());
char clusterPath[MAX_PATH + 1 ] = {0 };
strncpy(clusterPath, cluster, MAX_PATH);
if (!normalizePath(clusterPath, MAX_PATH)) {
logMsg("Invalid cluster path: %s" , cluster);
return ;
}
if (!clusters.empty()) {
clusters += ';' ;
}
logMsg("Adding cluster %s" , clusterPath);
clusters += clusterPath;
}
void NbLauncher::addExtraClusters() {
logMsg("addExtraClusters()" );
const char delim = ';' ;
string::size_type start = extraClusters.find_first_not_of(delim, 0 );
string::size_type end = extraClusters.find_first_of(delim, start);
while (string::npos != end || string::npos != start) {
string cluster = extraClusters.substr(start, end - start);
addCluster(cluster.c_str());
start = extraClusters.find_first_not_of(delim, end);
end = extraClusters.find_first_of(delim, start);
}
}
bool NbLauncher::readClusterFile() {
clusters = "" ;
string clusterFile = baseDir + "\\etc\\" + getAppName() + ".clusters" ;
logMsg("readClusterFile() file: %s" , clusterFile.c_str());
FILE* file = fopen(clusterFile.c_str(), "r" );
if (!file) {
logErr(true , true , "Cannot open file \" %s\" for reading." , clusterFile.c_str());
return false ;
}
char line[4096 ] = "" ;
while (fgets(line, sizeof (line), file)) {
char *str = skipWhitespaces(line);
if (*str == '#' || *str == '\0' ) {
continue ;
}
char *pc = str;
while (*pc != '\0' && *pc != '\t' && *pc != '\n' && *pc != '\r' ) {
pc++;
}
*pc = '\0' ;
if (platformDir.empty()) {
char *slash = strrchr(str, '\\' );
if (!slash) {
slash = strrchr(str, '/' );
}
char *dir = slash ? slash + 1 : str;
if (strncmp(dir, "platform" , strlen("platform" )) == 0 ) {
platformDir = str;
} else {
addCluster(str);
}
} else {
addCluster(str);
}
}
bool ok = ferror(file) == 0 ;
if (!ok) {
logErr(true , true , "Error while reading file \" %s\"." , clusterFile.c_str());
}
fclose(file);
return ok;
}
bool NbLauncher::parseArgs(int argc, char *argv[]) {
#define CHECK_ARG \
if (i+1 == argc) {\
logErr(false , true , "Argument is missing for \" %s\" option." , argv[i]);\
return false ;\
}
logMsg("parseArgs():" );
for (int i = 0 ; i < argc; i++) {
logMsg("\t%s" , argv[i]);
}
customUserDirFound = 0 ;
for (int i = 0 ; i < argc; i++) {
if (strcmp(ARG_NAME_USER_DIR, argv[i]) == 0 ) {
CHECK_ARG;
char tmp[MAX_PATH + 1 ] = {0 };
strncpy(tmp, argv[++i], MAX_PATH);
if (!normalizePath(tmp, MAX_PATH)) {
logErr(false , true , "User directory path \" %s\" is not valid." , argv[i]);
return false ;
}
customUserDirFound = 1 ;
userDir = tmp;
logMsg("User dir: %s" , userDir.c_str());
}
if (strcmp(ARG_NAME_CACHE_DIR, argv[i]) == 0 ) {
CHECK_ARG;
char tmp[MAX_PATH + 1 ] = {0 };
strncpy(tmp, argv[++i], MAX_PATH);
if (!normalizePath(tmp, MAX_PATH)) {
logErr(false , true , "Cache directory path \" %s\" is not valid." , argv[i]);
return false ;
}
cacheDir = tmp;
logMsg("Cache dir: %s" , cacheDir.c_str());
}
}
logMsg("parseArgs() finished" );
return true ;
}
bool NbLauncher::findUserDir(const char *str) {
logMsg("NbLauncher::findUserDir(%s)" , str);
userDir = str;
replaceToken(userDir);
logMsg("NbLauncher::findUserDir: %s" , userDir.c_str());
return true ;
}
bool NbLauncher::findCacheDir(const char *str) {
logMsg("NbLauncher::findCacheDir(%s)" , str);
cacheDir = str;
replaceToken(cacheDir);
logMsg("NbLauncher::findCacheDir: %s" , cacheDir.c_str());
return true ;
}
void NbLauncher::replaceToken(std::string& str) {
// Replace the allowed tokens in configuration options
replaceString(str, HOME_TOKEN, userHome);
replaceString(str, DEFAULT_CACHEDIR_ROOT_TOKEN, defCacheDirRoot);
replaceString(str, DEFAULT_USERDIR_ROOT_TOKEN, defUserDirRoot);
replaceString(str, BASEDIR_TOKEN, baseDir);
}
void NbLauncher::replaceString(std::string& str, const std::string& from, const std::string& to) {
if (from.empty()) {
return ;
}
// Loop over all occurrences of the search string in the input string and
// replace them all
size_t start_pos = 0 ;
while ((start_pos = str.find(from, start_pos)) != std::string::npos) {
str.replace(start_pos, from.length(), to);
// Skip over the replacement
start_pos += to.length();
}
}
void NbLauncher::getDefaultUserDirRoot() {
TCHAR defUserDirRootChar[MAX_PATH];
if (FAILED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0 , defUserDirRootChar))) {
defUserDirRoot = std::string();
}
defUserDirRoot = constructApplicationDir((string) defUserDirRootChar, false );
defUserDirRoot.erase(defUserDirRoot.rfind('\\' ));
logMsg("Default Userdir Root: %s" , defUserDirRoot.c_str());
}
void NbLauncher::getDefaultCacheDirRoot() {
TCHAR defCacheDirRootChar[MAX_PATH];
if (FAILED(SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, 0 , defCacheDirRootChar))) {
defCacheDirRoot = std::string();
}
defCacheDirRoot = constructApplicationDir((string) defCacheDirRootChar, true );
defCacheDirRoot.erase(defCacheDirRoot.rfind('\\' ));
logMsg("Default Cachedir Root: %s" , defCacheDirRoot.c_str());
}
void NbLauncher::getUserHome() {
char *userProfile = getenv(ENV_USER_PROFILE);
if (userProfile) {
userHome = userProfile;
} else {
TCHAR userHomeChar[MAX_PATH];
if (FAILED(SHGetFolderPath(NULL, CSIDL_DESKTOP, NULL, 0 , userHomeChar))) {
defCacheDirRoot = std::string();
userHome = std::string();
}
userHome = userHomeChar;
userHome.erase(userHome.rfind('\\' ));
}
logMsg("User home: %s" , userHome.c_str());
}
bool NbLauncher::getOption(char *&str, const char *opt) {
if (strncmp(str, opt, strlen(opt)) == 0 ) {
str += strlen(opt);
char *end = trimWhitespaces(str);
if (*str == '"' ) {
str++;
}
if (end >= str && *end == '"' ) {
*end = '\0' ;
}
logMsg("Option found: %s%s" , opt, str);
return true ;
}
return false ;
}
bool NbLauncher::parseConfigFile(const char * path) {
logMsg("parseConfigFile(%s)" , path);
FILE *file = fopen(path, "r" );
if (!file) {
logErr(true , false , "Cannot open file \" %s\" for reading." , path);
return false ;
}
char line[4096 ] = "" ;
while (fgets(line, sizeof (line), file)) {
char *str = skipWhitespaces(line);
if (*str == '#' ) {
continue ;
}
if (getOption(str, getDefUserDirOptName())) {
findUserDir(str);
logMsg("User dir: %s" , userDir.c_str());
} else if (getOption(str, getDefCacheDirOptName())) {
findCacheDir(str);
logMsg("Cache dir: %s" , cacheDir.c_str());
} else if (getOption(str, getDefOptionsOptName())) {
// replace \" by "
int len = strlen(str);
int k = 0 ;
for (int i = 0 ; i < len; i++) {
if (str[i] == '\\' && str[i+1 ] == '\"' ) {
continue ;
}
str[k++] = str[i];
}
str[k] = '\0' ;
nbOptions = str;
replaceToken(nbOptions);
logMsg("After replacement: %s" , nbOptions.c_str());
} else if (getOption(str, getExtraClustersOptName())) {
extraClusters = str;
} else if (getOption(str, getJdkHomeOptName())) {
jdkHome = str;
replaceToken(jdkHome);
logMsg("jdkHome: %s" , jdkHome.c_str());
}
}
bool ok = ferror(file) == 0 ;
if (!ok) {
logErr(true , false , "Error while reading file \" %s\"." , path);
}
fclose(file);
return true ;
}
typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO);
const char * NbLauncher::getAppName() {
return "netbeans" ;
}
void NbLauncher::addSpecificOptions(CmdArgs &args) {
for (unsigned i = 0 ; i < sizeof (staticOptions) / sizeof (char *); i++) {
args.add(staticOptions[i]);
}
}
const char * NbLauncher::getDefUserDirOptName() {
return OPT_NB_DEFAULT_USER_DIR;
}
const char * NbLauncher::getDefCacheDirOptName() {
return OPT_NB_DEFAULT_CACHE_DIR;
}
const char * NbLauncher::getDefOptionsOptName() {
return OPT_NB_DEFAULT_OPTIONS;
}
const char * NbLauncher::getExtraClustersOptName() {
return OPT_NB_EXTRA_CLUSTERS;
}
const char * NbLauncher::getJdkHomeOptName() {
return OPT_NB_JDK_HOME;
}
const char * NbLauncher::getCurrentDir() {
return 0 ;
}
std::string NbLauncher::constructApplicationDir(const std::string& dir, bool cache) {
if (cache) {
return dir + NETBEANS_CACHES_DIRECTORY;
} else {
return dir + NETBEANS_DIRECTORY;
}
}
Messung V0.5 in Prozent C=99 H=93 G=95
¤ Dauer der Verarbeitung: 0.6 Sekunden
¤
*© Formatika GbR, Deutschland