|
Maybe this will help. (Ranges and combining characters).
UnicodeRanges Class (System.Text.Unicode) | Microsoft Learn
"Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I
|
|
|
|
|
Hello, good day, I have 2 problems.
1. I can't find the installation path or the option mentioned in this post doesn't appear.
https://stackoverflow.com/questions/20718093/eclipse-interface-icons-very-small-on-high-resolution-screen-in-windows-8-1
2. Modifying the eclipse .ini file actually enlarges the icons but deconfigures my entire eclipse.
How can I solve it? Thank you.
|
|
|
|
|
Isn't there a forum somewhere where else (not this site) for Eclipse questions?
|
|
|
|
|
Any suggestions in Java for the following scenario:
Actually its truncating trailing zeros when converting to double.
Ex-1:
String - "123.4000"
double - 123.4000
Ex-2:
String - "123.4560"
double - 123.4560
|
|
|
|
|
Well, I do not see any truncation in your question. But most likely you misunderstand the difference between the string representation of a number and its actual value. For example the number 1.5 , can be presented as a string with a number of trailing zeroes such as: "1.50", "1.5000" etc. But its value is still 1.5 .
|
|
|
|
|
I understand that, i am getting input in form of string, the same need to be converted to double and send with out ignoring trailing zeros. I think now I am more clear on requirement.
|
|
|
|
|
Member 16135433 wrote: I think now I am more clear on requirement. Sorry, no you are not clear. What do you mean by "converted to double and send with out ignoring trailing zeros"? A double value, as I mentioned in my first reply, does not have trailing zeroes, it is just a number. How and where are you trying to send these numbers?
|
|
|
|
|
Quote: converted to double and send
No, not clear at all. What are you "sending" this data to?
All numerical types do not track trailing zeros, so whatever you're sending this data to must accept the values as strings, not a double type.
|
|
|
|
|
Member 16135433 wrote: the same need to be converted to double and send with out ignoring trailing zeros
Breaking that down into steps
1. String arrives
2. Convert to double
3. Something happens????
4. Then "send".
Unless something happens at step 3 which you did not define then of course you do not need to convert it in the first place.
That is because "send" in the modern world always means a string. XML, HTML, Json, even many other representations in TCP/IP will always be a string.
The only time when that is not true is when you are using a binary format and there can be all sorts for complications with that (precision, big versus, little, etc)
So presuming there is in fact a real need to handle it as a double then when you "send" it you must format it correctly. Just as though you started with a double in first place. In other words how it arrives is irrelevant.
|
|
|
|
|
|
There is no such thing as a value "with trailing zeros". "Trailing zeros" is a presentation thing, when you show the value in your UI, not a representation thing in a floating-point variable.
|
|
|
|
|
I found the following code posted by @Richard-MacCutchan to a thread about how to use JNI without having to add the location of jvm.dll into Environment Variables. I kinda understood how it works but still...
#include <Windows.h>
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <filesystem> // requires -std:c++17
#include "jni.h"
HMODULE LoadDll(
const char* jrePath
)
{
const char* pszjvmname = "bin\\server\\jvm.dll"; HMODULE hJVMDLL = 0;
std::filesystem::path jvmpath(jrePath);
jvmpath /= pszjvmname;
if (!std::filesystem::exists(jvmpath))
{
std::cerr << "JVM library " << jvmpath << " not found." << std::endl;
}
hJVMDLL = LoadLibraryW(reinterpret_cast<PCWSTR>(jvmpath.c_str()));
if (hJVMDLL != NULL)
{
std::clog << "jvm.dll loaded from: " << jvmpath << std::endl;
}
return hJVMDLL; }
JNIEnv* AttachJVM(
const char* jrePath,
JavaVM* jvm,
std::string strcwd
)
{
HMODULE hJVMDLL = LoadDll(jrePath);
if (hJVMDLL == 0)
{
return nullptr;
}
typedef jint(JNICALL* fpCJV)(JavaVM**, void**, void*);
fpCJV JNI_CreateJavaVM = (fpCJV)::GetProcAddress(hJVMDLL, "JNI_CreateJavaVM");
JavaVMOption options[2];
std::stringstream ssoptions;
ssoptions << "-Djava.class.path=";
ssoptions << strcwd;
std::string stropts = ssoptions.str();
options[0].optionString = const_cast<char*>(stropts.c_str());
options[1].optionString = const_cast<char*>("-verbose:jni");
JavaVMInitArgs vm_args; vm_args.version = JNI_VERSION_1_8;
vm_args.nOptions = 1; vm_args.ignoreUnrecognized = false;
vm_args.options = options;
for (int i = 0; i < vm_args.nOptions; ++i)
{
std::clog << "Options[" << i << "]: " << options[i].optionString << std::endl;
}
JNIEnv* env; jint res = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
if (res != 0)
{
std::cerr << "C++: JNI_CreateJavaVM returned: " << res << std::endl;
}
jint version = env->GetVersion();
std::clog << "JVM Version: " << (version >> 16) << "." << (version & 0xffff) << std::endl;
return env; }
void CallClass(
JNIEnv* jniEnv,
const char* pszClassname,
const char* pszMethodname,
const char* pszSignature
)
{
jclass jvmclass = jniEnv->FindClass(pszClassname);
if (jvmclass != NULL)
{
std::cout << "C++: Found the class: " << pszClassname << std::endl;
jmethodID jmid = jniEnv->GetStaticMethodID(jvmclass, pszMethodname, pszSignature);
if (jmid != NULL)
{
std::cout << "C++: Found the method: " << pszMethodname << std::endl;
jniEnv->CallStaticVoidMethod(jvmclass, jmid, NULL);
std::cout << "C++: env->CallStaticVoidMethod complete" << std::endl;
}
else
{
std::cerr << "C++: Failed to find the method: " << pszMethodname << std::endl;
}
}
else
{
std::cerr << "C++: Failed to find the class: " << pszClassname << std::endl;
}
}
int main(
int argc,
const char** argv
)
{
const char* jreDir = nullptr;
std::clog.setstate(std::ios::badbit);
for (argv++; argc > 1; ++argv, --argc)
{
if (*argv[0] == '-')
{
if (strstr(*argv, "-d"))
std::clog.clear();
}
else
{
jreDir = *argv;
}
}
if (jreDir == nullptr)
{
std::cerr << "No root path provided for JVM." << std::endl;
return 1;
}
JNIEnv* jniEnv = NULL;
std::filesystem::path cwd = std::filesystem::current_path();
JavaVM jvm;
jniEnv = AttachJVM(jreDir, &jvm, cwd.string());
if (jniEnv == NULL)
{
std::cerr << "C++: Failed to get Java environment" << std::endl;
return 1;
}
CallClass(jniEnv, "CppToJava", "main", "([Ljava/lang/String;)V");
jint jvmres = jvm.DestroyJavaVM(); std::clog << "C++: DestroyJavaVM and terminate: " << jvmres << std::endl;
}
I have two minor problems, I get a bit lost, I understand that it looks to see if Java in installed and tries to get the path to it and then to load the DLL, but I didn't managed to make it work for my situation, and also, on client machines I'm not making them install Java, but it comes in the app files with a license agreement, I'm using Eclipse Adoptium (...\MyApp\ThirdParty\Eclipse Adoptium\jre-17.0.7.7-hotspot).
If it isn't much to ask, could someone help me change the above code so that it will work in this scenario: Before creating the JVM, I'm running some other functions, and one of them returns the location for the app folder (ex: D:\Program Files\MyApp). Inside that folder are the apps data, and a folder Data, inside it a folder Java, and inside that all the java class files (...\MyApp\Data\Java\JavaMethods.class). So because I know the location of the app, I can give the location for jvm.dll by using the variable std::string location which would have as an example D:\Program Files\MyApp, then to that I can append \ThirdParty\Eclipse Adoptium\jre-17.0.7.7-hotspot\bin\server for the location of jvm.dll.
To be more precise, what I need to add before location.insert(0, "-Djava.class.path=");, to load the jvm.dll knowing it's location by combining like I said, the value from function parameter which would be set before calling the function and would have as an example D:\Program Files\MyApp, with \ThirdParty\Eclipse Adoptium\jre-17.0.7.7-hotspot\bin\server.
Here is an example how my app is using JNI extracted to a new project:
#include <jni.h>
#include <string>
#include <iostream>
#include <chrono>
#include <thread>
JavaVM* jvm = nullptr;
std::string createVM(std::string location) {
location.insert(0, "-Djava.class.path=");
location.append("Data\\Java");
JavaVMInitArgs vm_args;
JavaVMOption* options = new JavaVMOption[1];
options[0].optionString = &location[0];
vm_args.version = JNI_VERSION_10;
vm_args.nOptions = 1;
vm_args.options = options;
vm_args.ignoreUnrecognized = false;
JNIEnv* env = nullptr;
jint rc = JNI_OK;
if (jvm == nullptr) {
rc = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
}
else {
rc = jvm->AttachCurrentThread((void**)&env, NULL);
}
delete[] options;
if (rc != JNI_OK) {
if (rc == JNI_EVERSION)
return "JNI_EVERSION";
else if (rc == JNI_ENOMEM)
return "JNI_ENOMEM";
else if (rc == JNI_EINVAL)
return "JNI_EINVAL";
else if (rc == JNI_EEXIST)
return "JNI_EEXIST";
else
return "JNI_FATALERROR";
}
return "JNI_CREATED";
}
std::string createIdentification() {
JNIEnv* env;
jvm->AttachCurrentThread((void**)&env, NULL);
jclass jClass = env->FindClass("JavaMethods");
if (jClass == nullptr) {
return "ClassNotFound cI";
}
else {
jmethodID methodID = env->GetStaticMethodID(jClass, "createIdentification", "()Ljava/lang/String;");
if (methodID == nullptr) {
return "MethodNotFound cI";
}
else {
jboolean isCopy;
jstring jResult = (jstring)env->CallStaticObjectMethod(jClass, methodID);
const char* string = env->GetStringUTFChars(jResult, &isCopy);
std::string result = string;
env->ReleaseStringUTFChars(jResult, string);
return result;
}
}
}
int main() {
std::cout << createVM("D:\\Program Files\\MyApp\\").c_str() << std::endl;
std::cout << createIdentification().c_str();
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
return 0;
}
|
|
|
|
|
I managed to make it work:
#include <string>
#include <iostream>
#include <chrono>
#include <thread>
#include <jni.h>
#include <Windows.h>
JavaVM* jvm = nullptr;
std::string createVM(std::string location) {
std::string jvmLocation = location;
jvmLocation.append("ThirdParty\\Eclipse Adoptium\\jre-17.0.7.7-hotspot\\bin\\servers\\jvm.dll");
HMODULE hJVMDLL = LoadLibraryA(jvmLocation.c_str());
typedef jint(JNICALL* fpCJV)(JavaVM**, void**, void*);
if (hJVMDLL != NULL) {
fpCJV JNI_CreateJavaVM = (fpCJV)::GetProcAddress(hJVMDLL, "JNI_CreateJavaVM");
location.insert(0, "-Djava.class.path=");
location.append("Data\\Java");
JavaVMInitArgs vm_args;
JavaVMOption* options = new JavaVMOption[1];
options[0].optionString = &location[0];
vm_args.version = JNI_VERSION_10;
vm_args.nOptions = 1;
vm_args.options = options;
vm_args.ignoreUnrecognized = false;
JNIEnv* env = nullptr;
jint rc = JNI_OK;
if (jvm == nullptr) {
rc = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
}
else {
rc = jvm->AttachCurrentThread((void**)&env, NULL);
}
delete[] options;
if (rc != JNI_OK) {
if (rc == JNI_EVERSION)
return "JNI_EVERSION";
else if (rc == JNI_ENOMEM)
return "JNI_ENOMEM";
else if (rc == JNI_EINVAL)
return "JNI_EINVAL";
else if (rc == JNI_EEXIST)
return "JNI_EEXIST";
else
return "JNI_FATALERROR";
}
return "JNI_CREATED";
}
else {
return "ERROR_LOADING_DLL";
}
}
std::string createIdentification() {
JNIEnv* env;
jvm->AttachCurrentThread((void**)&env, NULL);
jclass jClass = env->FindClass("JavaMethods");
if (jClass == nullptr) {
return "ClassNotFound cI";
}
else {
jmethodID methodID = env->GetStaticMethodID(jClass, "createIdentification", "()Ljava/lang/String;");
if (methodID == nullptr) {
return "MethodNotFound cI";
}
else {
jboolean isCopy;
jstring jResult = (jstring)env->CallStaticObjectMethod(jClass, methodID);
const char* string = env->GetStringUTFChars(jResult, &isCopy);
std::string result = string;
env->ReleaseStringUTFChars(jResult, string);
return result;
}
}
}
int main() {
std::cout << createVM("Location_To_App_Folder").c_str() << std::endl;
if (jvm != NULL) {
std::cout << createIdentification().c_str();
}
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
return 0;
}
Thank you @Richard-MacCutchan for the original code!
|
|
|
|
|
Valentinor wrote: I'm not making them install Java
That is oddly phrased since they will need to have java installed somehow.
As a suggestion only you might want to work on your error handling if it turns out Java isn't installed. Telling a user that a dll is missing is not going to help them nor you when they ask why it isn't working. You might want to also print where you looked when you can't find it.
|
|
|
|
|
jschell wrote: That is oddly phrased since they will need to have java installed somehow.
Why did you stopped there with the quote? As the next part of the phrase contained the reason why I'm not making the install Java:
Valentinor wrote: but it comes in the app files with a license agreement, I'm using Eclipse Adoptium (...\MyApp\ThirdParty\Eclipse Adoptium\jre-17.0.7.7-hotspot).
So yeah, they don't need to install java, as it is included with the app.
|
|
|
|
|
Valentinor wrote: So yeah, they don't need to install java,
On Windows a Java install consists basically of the following.
1. Lay down the files into the file system.
2. Create the registry data so the user can uninstall it.
So apparently what you are actually doing is giving the user the option to use the Java that is already installed or to use the VM that comes with your application.
Besides my other suggestion you might also want to consider whether the VM they have installed is the correct version for your appliction.
|
|
|
|
|
jschell wrote: 1. Lay down the files into the file system.
Yes or no, depending what you mean by "file system". When the app is installed, inside it's folder structure it will also have Eclipse Adoptium (...\MyApp\ThirdParty\Eclipse Adoptium\jre-17.0.7.7-hotspot)
jschell wrote: 2. Create the registry data so the user can uninstall it.
It will be for the app itself and not just for java, as Eclipse Adoptium will be a part of the app, integrated into it, and not separate. When the app is uninstalled, so will Eclipse Adoptium as it is part of its files. If the user has any other form of Java installed, they won't be affected in any way.
jschell wrote: So apparently what you are actually doing is giving the user the option to use the Java that is already installed or to use the VM that comes with your application.
No. The app will only use Java that comes with it, as the app won't even look in another location if Java is installed, only inside it's file structure.
jschell wrote: whether the VM they have installed is the correct version for your appliction
I explained in the above statement why this doesn't matter for my case.
jschell wrote: As a suggestion only you might want to work on your error handling if it turns out Java isn't installed. Telling a user that a dll is missing is not going to help them nor you when they ask why it isn't working.
I never said that I don't have an error handling system already added. If any of Java files are missing or are corrupted, or any of the other app files are missing or are corrupted, an error will appear telling the user to run the check for corrupted files or reinstall the app, accompanied by an error message, that will tell me exactly which file is the problem, if it is missing or if it is corrupted.
|
|
|
|
|
I have a socket though which I'm sending files. If the file is under the buffer size (8192 in my case) then it is fine, but if the file is over that size, then when it writes to file, it writes the first chunk of 8192 bites every time. I'm using ObjectStream because beside the file, I'm sending other objects as well in the actual app, but this is the part of sending the file.
Client it sends the file data (testing):
System.out.println("Starting client");
Socket socket = new Socket("localhost", port);
System.out.println("Client sending data");
ObjectOutputStream dataOut = new ObjectOutputStream(socket.getOutputStream());
BufferedInputStream is = new BufferedInputStream(new FileInputStream(inFile));
byte[] buffer = new byte[8192];
int sizeRead = 0;
while ((sizeRead = is.read(buffer, 0, 8192)) >= 0) {
printByte(buffer, "in");
dataOut.writeObject(true);
dataOut.writeObject(buffer);
dataOut.writeObject(sizeRead);
dataOut.flush();
}
is.close();
System.out.println("Done sending file");
dataOut.writeObject(false);
socket.close();
System.out.println("Client closed");
Server that creates the file:
System.out.println("Starting server");
ServerSocket server = new ServerSocket(port);
System.out.println("Server waiting");
Socket socket = server.accept();
System.out.println("Client connected");
ObjectInputStream dataIn = new ObjectInputStream(socket.getInputStream());
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(outFile));
Object auxKeepReading = dataIn.readObject();
if (auxKeepReading instanceof Boolean) {
while ((boolean) auxKeepReading) {
Object auxBuffer = dataIn.readObject();
if (!(auxBuffer instanceof byte[])) {
System.out.println("Broke byte");
break;
}
Object auxSize = dataIn.readObject();
if (!(auxSize instanceof Integer)) {
System.out.println("Broke int");
break;
}
printByte((byte[]) auxBuffer, "out");
bos.write((byte[]) auxBuffer, 0, (int) auxSize);
auxKeepReading = dataIn.readObject();
if (!(auxKeepReading instanceof Boolean)) {
System.out.println("Broke boolean");
break;
}
}
} else {
System.out.println("Broke boolean");
}
bos.close();
socket.close();
server.close();
System.out.println("Server stopped");
Why is it that it keeps sending the first chunk of byte[], and not what it reads new?
|
|
|
|
|
On client side after sending the size that it read, I added buffer = new byte[8192]; and now I don't have the problem and it is sending new data but there are 2 problems:
1. I don't know if this is what you should do;
2. The speed is limited to 3 MB/s when using IP instead of localhost, on an internet connection of 1.000 Mbps (~125 MB/s) upload/download (they are the same). I tried to increase the buffer size but still the same speed.
|
|
|
|
|
I was looking at this code earlier and wondered why you sent the buffer size after the data. It makes much more sense to send the size first. Also there is no point in sending 8192 bytes if you have only read one byte from the input file. So only send the amount of data that has been read. Tuning TCP performance is not an exact science unfortunately, but you can find plenty of discussions of the subject on the internet.
|
|
|
|
|
Richard MacCutchan wrote: I was looking at this code earlier and wondered why you sent the buffer size after the data. It makes much more sense to send the size first.
Because when they are used it doesn't matter the order they were sent, I didn't even think about that.
Richard MacCutchan wrote: Also there is no point in sending 8192 bytes if you have only read one byte from the input file. So only send the amount of data that has been read.
I changed that now on client: dataOut.writeObject(Arrays.copyOf(buffer, sizeRead));
What about buffer = new byte[8192]; I added, is that how it should be done to send now data each time?
dataOut.writeObject(true);
dataOut.writeObject(sizeRead);
dataOut.writeObject(Arrays.copyOf(buffer, sizeRead));
dataOut.flush();
buffer = new byte[8192];
Richard MacCutchan wrote: Tuning TCP performance is not an exact science unfortunately, but you can find plenty of discussions of the subject on the internet.
From what I've seen they suggest two things most of the time:
1. Setting socket.setTcpNoDelay(true); . I tried that on both client and server bust still no use;
2. Using BufferedOutputStream/BufferedInputStream inside ObjectOutputStream/ObjectInputStream, but still the same 3 MB/s. Even after combining 1. and 2.
|
|
|
|
|
JohnCodding wrote: What about buffer = new byte[8192]; I added, is that how it should be done to send now data each time? Yes, that is fine, as you allocate the buffer before you start the read/write loop. So each read from the input file will refill the same buffer. But I would be tempted to use ObjectOutputStream write(byte[](Java Platform SE 7 )[^], rather than writeObject , to send the byte data.
I have never had to do any TCP tuning so can't offer any useful suggestions, sorry.
|
|
|
|
|
Richard MacCutchan wrote: But I would be tempted to use ObjectOutputStream write(byte[](Java Platform SE 7 )[^], rather than writeObject, to send the byte data.
In the past when I used socket but not for files, I had some problems when I was using combination of ObjectOutputStream writeBoolean(), writeInt(), writeUTF(), writeObject(), the order was correct when writing/reading but I was still getting some exceptions, and when I switch to only writeObject() I didn't had any problems. And with objects I have more control over what the server gets from the client when the data is wrong, and shadow ban the IP if it keeps sending the wrong data based on some checks. As java class files can easily be decompiled, they can recreate the code and send part of the data good then wrong one just to be jerks or for phishing data. I have some checks on the server to know when someone clearly wasn't supposed to send data, and ignore it, and it did help.
Richard MacCutchan wrote: I have never had to do any TCP tuning so can't offer any useful suggestions, sorry.
Yeah, until now I didn't had problems, but now with files, also some that can be big, I do care about speed a lot. I'll keep looking and maybe I find a way to remove the limit. As there is clearly a limit because the speed stays around 3 MB/s and I did see someone complaining about the same exact speed, but there wasn't a solution on that thread.
|
|
|
|
|
JohnCodding wrote: The speed is limited to 3 MB/s when using IP instead of localhost, on an internet connection of 1.000 Mbps
Not quite sure what you are saying there but...
Yes localhost and the actual network are different. So a speed difference is expected. Matter of fact if it was the same I would expect (most likely) a problem with the actual measurement or that there was a hardware/software throttle happening in the client.
JohnCodding wrote: internet connection ... upload/download (they are the same).
Noting also that I would not expect that. Even for a business. But I do want to emphasize that there is a difference between 'network' and 'internet'.
|
|
|
|
|
jschell wrote: Noting also that I would not expect that. Even for a business.
SpeedTest[^]
jschell wrote: Not quite sure what you are saying there but...
When transferring files over internet using the code I posted for sending/receiving, the transfer speed is always limited to 3 MB/s (bounces around 3 MB/s, it goes over or under with 100-200 KB/s) instead of the actual capabilities of internet speed and hardware (SSD).
If localhost is used, then the transfer is not limited to 3 MB/s.
|
|
|
|
|