原文地址:Windows下的Java多版本管理 | ZYG's Notes (creeeeeeeeeeper.github.io)
使用说明
注意:此版本管理器用来设置全局Java版本,暂无局部修改功能(以后可能会加吧……)
下载
点击此处可以下载jvm.exe,放到一个不碍事的地方(藏起来也可以!)
配置系统变量
首先确保系统变量和用户变量中没有配乱的Java环境变量,建议全部删除掉
全部删掉后,在系统变量中新建一个CLASSPATH
变量,值为%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar;%JAVA_HOME%\bin
。在系统变量的
Path
变量中新建一个%CLASSPATH%
系统变量的配置就完了。
jvm.exe
初始化
写完JavaVersionManager发现首字母缩写和JavaVirtualMachine一样,不过没关系,用起来感觉也差不多,所以就还是叫jvm吧。
首先使用cmd运行jvm.exe,第一次会出现如下初始化信息:
如果这样就是初始化完成了,初始化时会在C:\User\<your username>
这个路径下面产生一个配置文件,JavaVersionManager.ini,不要更改这个文件的内容。被管理的版本会存在这里,如果创建失败可以手动创建
配置版本管理器的环境变量
给jvm.exe配置环境变量
首先将jvm.exe放到一个不碍事的地方,然后配置jvm.exe的环境变量,这样在所有地方就可以用jvm
的指令直接运行版本管理器(如下图)。
设置方法
cmd中运行jvm.exe,使用jvm.exe -set-ev
指令自动配置环境变量,配置后后不要更改jvm.exe的程序名。由于配置的是系统环境变量,所以需要确认UAC。
配置好后会出现Environment variable has been set successfully.
指令说明
-set-ev
上面介绍过,用来设置JavaVersionManager自己的环境变量
-version
查看JavaVersionManager的版本
-versions
相当于java -version
,查看当前的Java版本
-list
列举被添加到管理器中的jdk版本
-add <path> <describe version>
向管理器中添加jdk版本。黄色的警告一般来说不用管,用管理员身份启动可能就没这个问题
如:add D:\Programming\Java\jkd21 21
-set describe version>
如:-set 21
这样后会弹出UAC提示,确认后%JAVA_HOME%
会改成jdk21的路径,重新启动一个终端,使用java -version
查看是否改好了版本
-remove <describe version>
如:使用-remove 21
,可以删除管理器中的版本,不会删除你下载的jdk文件夹,只是不再对其进行管理!!
以后加个直接能下载的功能。。。嗯,以后再说
源码:C语言写的,写着玩的,代码有很多不足之处,轻喷哈哈哈
JavaVersionManager.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <io.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>
#include <windows.h>
#include <direct.h>
JavaVersionManager.cpp
#include "JavaVersionManager.h"
char up[0x200];
int IfRunAsAdmin = 0;
int getUserProfile()
{
const char* userProfile;
size_t size;
if (_dupenv_s((char**)&userProfile, &size, "USERPROFILE") != 0 || userProfile == NULL) {
printf("\033[41mJavaVersionManager\033[0m\033[1m: Initialize failed. Excpetion: cannot get user profile path.\n");
return 1;
}
strncpy_s(up, sizeof(up), userProfile, _TRUNCATE);
free((void*)userProfile);
return 0;
}
int InitConfigFile()
{
char filePath[0x400];
snprintf(filePath, sizeof(filePath), "%s\\JavaVersionManager.ini", up);
FILE* file;
errno_t err = fopen_s(&file, filePath, "w");
if (err != 0) {
perror("\033[41mJavaVersionManager\033[0m\033[1m: Failed to open file for writing.");
return 1;
}
fprintf(file, "# JavaVersionManager Configuration File\n");
fclose(file);
printf("\033[42mJavaVersionManager\033[0m\033[1m: Initialized successfully.\n");
return 0;
}
void prthp()
{
printf("\n");
printf("\tUsage: -set-ev\n");
printf("\t -version\n");
printf("\t -versions\n");
printf("\t -list\n");
printf("\t -add <path> <descibe version>\n");
printf("\t -set <descibe version>\n");
printf("\t -remove <descibe version>\n");
printf("\t -help\n\n");
printf("\tuse \"-set-ev\" to set environment variable for JavaVersionManager that you can run as \"jvm\"\n");
printf("\t\"path\" refers to the path of the JDK directory\n");
printf("\t\"describe version\"similar to naming your JDK, when change version you can use, only accept Integer\n\n");
}
int isPureDigit(const char* str) {
while (*str) {
if (*str < '0' || *str > '9') {
return 0;
}
str++;
}
return 1;
}
void CreateAdminProcess(const char* jdkpath) {
char command[512];
snprintf(command, sizeof(command), "setx /M JAVA_HOME \"%s\"", jdkpath);
char fullCommand[600];
snprintf(fullCommand, sizeof(fullCommand), "cmd.exe /C %s", command);
STARTUPINFOA si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
HINSTANCE result = ShellExecuteA(
NULL,
"runas",
"cmd.exe",
fullCommand,
NULL,
SW_HIDE
);
if ((intptr_t)result <= 32) {
IfRunAsAdmin = 0;
}
else {
IfRunAsAdmin = 1;
}
}
DWORD WINAPI ThreadFunction(LPVOID lpParam) {
const char* jdkpath = (const char*)lpParam;
CreateAdminProcess(jdkpath);
return 0;
}
void remove_empty_lines() {
FILE* file;
errno_t err = fopen_s(&file, up, "r");
if (err != 0 || file == NULL) {
perror("\033[43mJavaVersionManager\033[0m\033[1m: Something wrong happened, but they are not important...");
return;
}
FILE* temp_file;
err = fopen_s(&temp_file, "temp.ini", "w");
if (err != 0 || temp_file == NULL) {
perror("\033[43mJavaVersionManager\033[0m\033[1m: Something wrong happened, but they are not important...");
fclose(file);
return;
}
char line[256];
while (fgets(line, sizeof(line), file)) {
if (strcmp(line, "\n") != 0) {
fputs(line, temp_file);
}
}
fclose(file);
fclose(temp_file);
if (remove(up) != 0) {
perror("\033[41mJavaVersionManager\033[0m\033[1m: Failed to delete the original file.");
}
if (rename("temp.ini", up) != 0) {
perror("\033[41mJavaVersionManager\033[0m\033[1m: Failed to rename the temporary file.");
}
}
void CreateEnvVariable(const char* cwd)
{
char command[512];
snprintf(command, sizeof(command), "setx /M Path \"%%Path%%;%s;\"", cwd);
char fullCommand[600];
snprintf(fullCommand, sizeof(fullCommand), "cmd.exe /C %s", command);
STARTUPINFOA si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
HINSTANCE result = ShellExecuteA(
NULL,
"runas",
"cmd.exe",
fullCommand,
NULL,
SW_HIDE
);
if ((intptr_t)result <= 32) {
IfRunAsAdmin = 0;
}
else {
IfRunAsAdmin = 1;
}
}
DWORD WINAPI ThreadFunction2(LPVOID lpParam) {
const char* cwd = (const char*)lpParam;
CreateEnvVariable(cwd);
return 0;
}
int CommandInterpreter(int paramCount, char* command[])
{
if (paramCount == 1)
{
prthp();
}
else
{
if (paramCount == 2)
{
if (strcmp(command[1], "-version") == 0)
{
printf("\nJavaVersionManager: Version 1.0.0 2024-11-16 released\n");
}
else if (strcmp(command[1], "-versions") == 0)
{
system("java -version");
}
else if (strcmp(command[1], "-help") == 0)
{
prthp();
}
else if (strcmp(command[1], "-list") == 0)
{
char filePath[0x400];
snprintf(filePath, sizeof(filePath), "%s\\JavaVersionManager.ini", up);
FILE* file;
errno_t err = fopen_s(&file, filePath, "r");
if (err != 0) {
printf("\033[41mJavaVersionManager\033[0m\033[1m: Something wrong happended.\n");
return 0;
}
else {
char line[0x100];
putchar('\n');
while (fgets(line, sizeof(line), file)) {
if (line[0] != '#' && line[0] != '\n') {
printf("%s", line);
}
}
putchar('\n');
fclose(file);
}
}
else if (strcmp(command[1], "-set-ev") == 0)
{
char cwd[1024];
if (_getcwd(cwd, sizeof(cwd)) != NULL) {
HANDLE hThread = CreateThread(NULL, 0, ThreadFunction2, (LPVOID)cwd, 0, NULL);
if (hThread == NULL) {
printf("\n\033[41mJavaVersionManager Exception\033[0m\033[1m: Failed to create thread. Error code:%lu\n", GetLastError());
return 1;
}
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
if (IfRunAsAdmin == 0)
{
printf("\n\033[41mJavaVersionManager Exception\033[0m\033[1m: Failed to set environment variable. Please run this command as administrator.\n");
}
else
{
printf("\nEnvironment variable has been set successfully.\n");
IfRunAsAdmin = 0;
}
}
else {
perror("\033[41mJavaVersionManager Exception\033[0m\033[1m: Failed to get current working directory.");
return 1;
}
}
else
{
printf("\n\033[41mJavaVersionManager Exception\033[0m\033[1m: Unknown command.\n");
}
}
else if (paramCount == 3)
{
if (strcmp(command[1], "-set") == 0)
{
if (!isPureDigit(command[2])) {
printf("\033[41mJavaVersionManager Exception\033[0m\033[1m: Invalid version number. Please provide a numeric version.\n");
return 0;
}
char filePath[0x400];
snprintf(filePath, sizeof(filePath), "%s\\JavaVersionManager.ini", up);
FILE* file;
errno_t err = fopen_s(&file, filePath, "r");
if (err != 0) {
printf("\033[41mJavaVersionManager Exception\033[0m\033[1m: Something wrong happened.\n");
return 0;
}
else {
char line[0x100];
int versionFound = 0;
char version[4] = { 0 };
char jdkPath[0x400];
while (fgets(line, sizeof(line), file)) {
if (line[0] == '[') {
sscanf_s(line, "[%3s]", version, (unsigned)_countof(version));
version[strcspn(version, "]")] = '\0';
if (strcmp(version, command[2]) == 0) {
if (fgets(jdkPath, sizeof(jdkPath), file) != NULL) {
printf("\nJDK Path for version %s: \n%s\n", command[2], jdkPath);
versionFound = 1;
HANDLE hThread = CreateThread(NULL, 0, ThreadFunction, (LPVOID)jdkPath, 0, NULL);
if (hThread == NULL) {
printf("\n\033[41mJavaVersionManager Exception\033[0m\033[1m: Failed to create thread. Error code:%lu\n", GetLastError());
return 1;
}
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
if (IfRunAsAdmin == 0) {
printf("\n\033[41mJavaVersionManager Exception\033[0m\033[1m: Failed to set JDK Path. Please run this command as administrator.\n");
}
else {
printf("\nJDK Path for version %s has been set successfully.\n", command[2]);
IfRunAsAdmin = 0;
}
}
else {
printf("\n\033[41mJavaVersionManager Exception\033[0m\033[1m: \nVersion specified but no path found. Please check your configuration file at %s\\JavaVersionManager.ini.\n", up);
versionFound = 1;
}
break;
}
}
}
if (!versionFound) {
printf("\033[41mno such a version\033[0m\033[1m\n");
}
fclose(file);
}
}
else if (strcmp(command[1], "-remove") == 0)
{
char filePath[0x400];
snprintf(filePath, sizeof(filePath), "%s\\JavaVersionManager.ini", up);
FILE* file;
errno_t err = fopen_s(&file, filePath, "r");
if (err != 0) {
printf("\033[41mJavaVersionManager Exception\033[0m\033[1m: Something wrong happened.\n");
return 0;
}
FILE* tempFile;
fopen_s(&tempFile, "temp.ini", "w");
if (tempFile == NULL) {
printf("\033[41mJavaVersionManager Exception\033[0m\033[1m: Cannot create temporary file.\n");
fclose(file);
return 0;
}
char line[0x100];
int versionFound = 0;
char version[4] = { 0 };
while (fgets(line, sizeof(line), file)) {
if (line[0] == '[') {
sscanf_s(line, "[%3s]", version, (unsigned)_countof(version));
version[strcspn(version, "]")] = '\0';
if (strcmp(version, command[2]) == 0) {
versionFound = 1;
fgets(line, sizeof(line), file);
continue;
}
}
fputs(line, tempFile);
}
fclose(file);
fclose(tempFile);
remove(filePath);
rename("temp.ini", filePath);
if (versionFound) {
printf("\nVersion %s has been removed successfully.\n", command[2]);
}
else {
printf("\n\033[41mNo such a version was found.\033[0m\033[1m\n");
remove("temp.ini");
}
remove_empty_lines();
}
else
{
printf("\n\033[41mJavaVersionManager Exception\033[0m\033[1m: Unknown command.\n");
}
}
else if (paramCount == 4)
{
if (strcmp(command[1], "-add") == 0)
{
if (GetFileAttributesA(command[2]) == INVALID_FILE_ATTRIBUTES) {
printf("\033[41mJavaVersionManager Exception\033[0m\033[1m: Invalid path.\n");
return 0;
}
if (!isPureDigit(command[3])) {
printf("\033[41mJavaVersionManager Exception\033[0m\033[1m: Invalid version number. Please provide a numeric version.\n");
return 0;
}
char filePath[0x400];
snprintf(filePath, sizeof(filePath), "%s\\JavaVersionManager.ini", up);
FILE* file;
errno_t err = fopen_s(&file, filePath, "r");
if (err != 0) {
printf("\033[41mJavaVersionManager Exception\033[0m\033[1m: Something wrong happened.\n");
return 0;
}
char line[0x100];
int versionFound = 0;
char version[4] = { 0 };
while (fgets(line, sizeof(line), file)) {
if (line[0] == '[') {
sscanf_s(line, "[%3s]", version, (unsigned)_countof(version));
version[strcspn(version, "]")] = '\0';
if (strcmp(version, command[3]) == 0) {
versionFound = 1;
break;
}
}
}
if (versionFound) {
printf("JavaVersionManager Exception: Version already exists.\n");
return 0;
}
fclose(file);
err = fopen_s(&file, filePath, "a");
if (err != 0) {
printf("\033[41mJavaVersionManager Exception\033[0m\033[1m: Something wrong happened.\n");
return 0;
}
fprintf(file, "\n[%s]\n", command[3]);
fprintf(file, "%s", command[2]);
fclose(file);
printf("\nVersion %s has been added successfully.\n", command[3]);
remove_empty_lines();
}
}
}
return 0;
}
int main(int argc, char* argv[])
{
if (getUserProfile() != 0) {
return 1;
}
char filePath[0x400];
snprintf(filePath, sizeof(filePath), "%s\\JavaVersionManager.ini", up);
FILE* file;
errno_t err = fopen_s(&file, filePath, "r");
if (err != 0)
{
if (InitConfigFile() != 0) {
return 1;
}
}
else
{
fclose(file);
}
CommandInterpreter(argc, argv);
return 0;
}