jstring return in JNI program - string

This is JNI code.
Java code:
public class Sample1 {
public native String stringMethod(String text);
public static void main(String[] args)
{
System.loadLibrary("Sample1");
Sample1 sample = new Sample1();
String text = sample.stringMethod("world");
System.out.println("stringMethod: " + text);
}
}
Cpp Method for stringMethod function:
JNIEXPORT jstring JNICALL Java_Sample1_stringMethod
(JNIEnv *env, jobject obj, jstring string) {
const char *name = env->GetStringUTFChars(string, NULL);//Java String to C Style string
char msg[60] = "Hello ";
jstring result;
strcat(msg, name);
env->ReleaseStringUTFChars(string, name);
puts(msg);
result = env->NewStringUTF(msg); // C style string to Java String
return result;
}
When running my java code. I got the result below.
stringMethod: world
But I appended the string "world" with "Hello ". I'm also returning here the appended string. But why I'm getting only "world" not "Hello World". Really I confused with this code. What should I do to get the result with appended string?

JNIEXPORT jstring JNICALL Java_Sample1_stringMethod
(JNIEnv *env, jobject obj, jstring string)
{
const char *name = (*env)->GetStringUTFChars(env,string, NULL);
char msg[60] = "Hello ";
jstring result;
strcat(msg, name);
(*env)->ReleaseStringUTFChars(env,string, name);
puts(msg);
result = (*env)->NewStringUTF(env,msg);
return result;
}

There are several ways but the best I got by converting const char * to c++ string and then to jbyteArray, and its easy to conversion of byteArray to UTF-8 on java side.
C++ side:
const char* string = propertyValue;
std::string str = string;
jbyteArray array = env->NewByteArray(str.length());
env->SetByteArrayRegion(array,0,str.length(),(jbyte*)str.c_str());
return array;
Java/kotlin side:
String((array), Charset.defaultCharset()))

Related

How to change the value of string from a cout

void extractWord (string& str)
I have to write a function that extracts the word between ‘*’.
For example, using the three test cases below:
string s = "This is to be *reversed*"
string s1 ="*Reversed* starts here";
string s2 = "This is *in* the middle";
and after each function call,
s=reversed, s1=Reversed, s2=in
So i figured out...
void extractWord (string& str)
{
char target= '*';
int idx1=0;
while (str[idx1] != target)
idx1=idx1+1;
int idx2=idx1+1;
while (str[idx2] != target)
idx2=idx2+1;
for(int i=0;i<sizeof(str);i++)
{
if ((i>idx1)&&(i<idx2))
cout<<str[i];
}
}
int main()
{
string s="This is to be *reversed*";
string s1 = "*Reversed* starts here";
string s2= "This is *in* the middle";
extractWord(s);
cout<<endl;
extractWord(s1);
cout<<endl;
extractWord(s2);
cout<<endl;
}
but how do I change the value of s into the output of this function?
I have modified your code a bit. I hope this solves your problem:
//#include "stdafx.h"
#include < string >
#include < iostream >
using namespace std;
void extractWord (string& str)
{
char target= '*';
int idx1=0;
while (str[idx1] != target)
idx1=idx1+1;
int idx2=idx1+1;
while (str[idx2] != target)
idx2=idx2+1;
str=str.substr(idx1+1,idx2-idx1-1); //changed
}
int main()
{
string s="This is to be *reversed*";
string s1 = "*Reversed* starts here";
string s2= "This is *in* the middle";
extractWord(s);
cout<<s<<endl; //changed
extractWord(s1);
cout<<s1<<endl; //changed
extractWord(s2);
cout<<s2<<endl; //changed
system("PAUSE");
return 0;
}
Now, every time you call void extractWord (string& str) it replaces string with only word between *'s.
I've used std::string::substr function. > http://www.cplusplus.com/reference/string/string/substr/
Other option is to make function that returns word between *'s.
//#include "stdafx.h"
#include < string >
#include < iostream >
using namespace std;
string extractWord (string& str)
{
char target= '*';
int idx1=0;
while (str[idx1] != target)
idx1=idx1+1;
int idx2=idx1+1;
while (str[idx2] != target)
idx2=idx2+1;
return str.substr(idx1+1,idx2-idx1-1);
}
int main()
{
string s="This is to be *reversed*";
string s1 = "*Reversed* starts here";
string s2= "This is *in* the middle";
string res;
res=extractWord(s);
cout<<res<<endl;
res=extractWord(s1);
cout<<res<<endl;
res=extractWord(s2);
cout<<res<<endl;
system("PAUSE");
return 0;
}
However, note that it doesn't work if your string do not contain two *'s or it has more than one word that has to be extracted. I hope this helped you.

convert String^ to standard C++ string

I faced a problem cannot convert parameter from 'System::String ^' to 'std::string'. How can i convert System::String^ into standard C++ string in Visual C++ environment ?
From this link at Microsoft:
void MarshalString ( String ^ s, string& os ) {
using namespace Runtime::InteropServices;
const char* chars =
(const char*)(Marshal::StringToHGlobalAnsi(s)).ToPointer();
os = chars;
Marshal::FreeHGlobal(IntPtr((void*)chars));
}
int main() {
string a = "test";
String ^ c = gcnew String("abcd");
cout << a << endl;
MarshalString(c, a);
cout << a << endl;
}
//*** convert String^ to standard C++ string
` String ^SyStr = "abc"; // system string
string StStr =""; // standard string
for each (char c in SyStr )
{
StStr .push_back( c);
} `
//**** End convert String^ to standard C++ string
//**** convert standard C++ string to String^
` String ^SyStr = ""; // system string
string StStr ="xyz"; // standard string
SyStr = gcnew String(StStr.c_str());`
//**** End convert standard C++ string to String^

Marshaling char * in .NetcompactFramework(Windows CE)

I have the following signature from c++
IDTECHREADER_EXPORTS void ReadTwoBlocks(char *pathConfig,
char *datablock1, char *datablock2, int timeout, bool &ret )
I was able to Marshal this correctly on the Full .NetFrameWork and it works as below
[DllImport("IDTechReader.dll", EntryPoint = "ReadTwoBlocks" )]
private static extern void _ReadTwoBlocks(
[In][MarshalAs(UnmanagedType.LPStr)] string pathConfig,
[Out][MarshalAs(UnmanagedType.LPStr)] StringBuilder datablock1,
[Out] [MarshalAs(UnmanagedType.LPStr)] StringBuilder datablock2,
int TimeOut,
ref bool result);
However using the same Marshaling as above doesn't work on the NetcompactFramework(Windows CE) it gives an error "NotSupported Exception"
How do we correctly Marshal the above C++ method signature so that it will work correctly on the .NET CompactFramework(windows CE)
any ideas are apperciated...thanks.
The marshaler is probably choking on the MarshalAs(UnmanagedType.LPStr). You're either going to have to change the signature to a fixed size byte[] and do the string conversion in managed code using Encoding.ASCII.GetString(), or you could use an IntPtr type and allocate the memory using Marshal.AllocHGlobal/FreeHGlobal and deal with the string conversion in your code.
I think this might work..
private const int MAX_STRING = 256;
[DllImport("IDTechReader.dll", EntryPoint = "ReadTwoBlocks")]
private static extern void _ReadTwoBlocks(
byte[] pathConfig,
[Out] byte[] datablock1,
[Out] byte[] datablock2,
int TimeOut,
ref bool result);
public void ReadTwoBlocks(string pathConfig,
StringBuilder datablock1,
StringBuilder datablock2,
int TimeOut,
ref bool result)
{
var pathConfigBuff = new byte[MAX_STRING];
var datablock1Buff = new byte[MAX_STRING];
var datablock2Buff = new byte[MAX_STRING];
// Convert unicode string to null terminated single byte charater string
Array.Copy(Encoding.ASCII.GetBytes(pathConfig), pathConfigBuff, pathConfig.Length);
// Call your native method
_ReadTwoBlocks(pathConfigBuff, datablock1Buff, datablock2Buff, TimeOut, ref result);
// If success, copy the datablocks to the StringBuffers
if (result)
{
datablock1.Append(Encoding.ASCII.GetString(datablock1Buff, 0, MAX_STRING).Replace('\0', ' ').Trim());
datablock2.Append(Encoding.ASCII.GetString(datablock2Buff, 0, MAX_STRING).Replace('\0', ' ').Trim());
}
}
It would be something like this:
[DllImport("IDTechReader.dll")]
private static extern void ReadTwoBlocks(IntPtr pathConfig,
IntPtr datablock1, IntPtr datablock2, int timeout, ref bool ret);
and when you use it like this:
string pathConfig = "..\program.ini";
IntPtr ptrPathConfig = IntPtr.Zero;
ptrPathConfig = Marshal.StringToHGlobalAnsi(pathConfig);
IntPtr ptrDatablock1 = IntPtr.Zero;
IntPtr ptrDatablock2 = IntPtr.Zero;
int timeout = 300;
bool ret = false;
ReadTwoBlocks(ptrPathConfig, ptrDatablock1, ptrDatablock2, timeout, ref ret);
string db1 = Marshal.PtrToStringAnsi(ptrDatablock1);
string db2 = Marshal.PtrToStringAnsi(ptrDatablock2);

jint problem with NDK

I'm trying to make my first native function with NDK and I'm in trouble with very basic stuff.
Please consider the following c code:
#include <jni.h>
#include <string.h>
JNIEXPORT jint JNICALL Java_eu_elevelcbt_sm_YCrCbUtils_toARGB(
JNIEnv* env, jbyteArray src, jintArray out, jint width, jint height){
jbyte *c_src = (*env)->GetByteArrayElements(env, src, NULL);
jint *c_out = (*env)->GetDirectBufferAddress(env, out);
if (c_out==NULL)
return -1;
int length = width * height;
int co;
unsigned int color;
for (co=0; co<length; co++) {
color = c_src[co] & 0xFF;
color = 0xFF000000 | (color<<16) | (color<<8) | color;
c_out[co] = color;
}
(*env)->ReleaseByteArrayElements(env, src, c_src, 0);
return 0;
}
JNIEXPORT jint JNICALL Java_eu_elevelcbt_sm_YCrCbUtils_sum(jint a, jint b){
return a+b;
}
and the following Java class:
public class YCrCbUtils {
public native int toARGB(byte[] src, int[] out, final int width, final int height);
public native int sum(int a, int b);
static {
System.loadLibrary("yuv");
}
}
Problem 1: If I call the second function
Log.v("DBG", "sum is: " + new YCrCbUtils().sum(10, 5));
This is what I get: "sum is 1079199776" !!!! WHY?!??!? :(
If I try calling first function like this:
int[] colors = new int[size.width * size.height]; // where width=800 and height=480
new YCrCbUtils().toARGB(data, colors, size.width, size.height); // data is a byte[]
I get a SIGSEGV error...
HELP please!!!
PS: my dev environment is MAC OSX Snow Leopard, NDK-r5b. My runtime env is Nexus One 2.3.3
...ok I'm stupid...
My methods signatures were WRONG... They always must have "JNIEnv* env, jobject obj" as first two members... well I spend an afternoon on this but the good thing is that now I'll never forget it!
Also, on my first method I had to change
jint *c_out = (*env)->GetDirectBufferAddress(env, out);
with
jint *c_out = (*env)->GetIntArrayElements(env, out, NULL);
as the previous one was returning a NULL pointer

C++/CLI Converting from System::String^ to std::string

Can someone please post a simple code that would convert,
System::String^
To,
C++ std::string
I.e., I just want to assign the value of,
String^ originalString;
To,
std::string newString;
Don't roll your own, use these handy (and extensible) wrappers provided by Microsoft.
For example:
#include <msclr\marshal_cppstd.h>
System::String^ managed = "test";
std::string unmanaged = msclr::interop::marshal_as<std::string>(managed);
You can easily do this as follows
#include <msclr/marshal_cppstd.h>
System::String^ xyz="Hi boys";
std::string converted_xyz=msclr::interop::marshal_as< std::string >( xyz);
Check out System::Runtime::InteropServices::Marshal::StringToCoTaskMemUni() and its friends.
Sorry can't post code now; I don't have VS on this machine to check it compiles before posting.
This worked for me:
#include <stdlib.h>
#include <string.h>
#include <msclr\marshal_cppstd.h>
//..
using namespace msclr::interop;
//..
System::String^ clrString = (TextoDeBoton);
std::string stdString = marshal_as<std::string>(clrString); //String^ to std
//System::String^ myString = marshal_as<System::String^>(MyBasicStirng); //std to String^
prueba.CopyInfo(stdString); //MyMethod
//..
//Where: String^ = TextoDeBoton;
//and stdString is a "normal" string;
Here are some conversion routines I wrote many years ago for a c++/cli project, they should still work.
void StringToStlWString ( System::String const^ s, std::wstring& os)
{
String^ string = const_cast<String^>(s);
const wchar_t* chars = reinterpret_cast<const wchar_t*>((Marshal::StringToHGlobalUni(string)).ToPointer());
os = chars;
Marshal::FreeHGlobal(IntPtr((void*)chars));
}
System::String^ StlWStringToString (std::wstring const& os) {
String^ str = gcnew String(os.c_str());
//String^ str = gcnew String("");
return str;
}
System::String^ WPtrToString(wchar_t const* pData, int length) {
if (length == 0) {
//use null termination
length = wcslen(pData);
if (length == 0) {
System::String^ ret = "";
return ret;
}
}
System::IntPtr bfr = System::IntPtr(const_cast<wchar_t*>(pData));
System::String^ ret = System::Runtime::InteropServices::Marshal::PtrToStringUni(bfr, length);
return ret;
}
void Utf8ToStlWString(char const* pUtfString, std::wstring& stlString) {
//wchar_t* pString;
MAKE_WIDEPTR_FROMUTF8(pString, pUtfString);
stlString = pString;
}
void Utf8ToStlWStringN(char const* pUtfString, std::wstring& stlString, ULONG length) {
//wchar_t* pString;
MAKE_WIDEPTR_FROMUTF8N(pString, pUtfString, length);
stlString = pString;
}
I found an easy way to get a std::string from a String^ is to use sprintf().
char cStr[50] = { 0 };
String^ clrString = "Hello";
if (clrString->Length < sizeof(cStr))
sprintf(cStr, "%s", clrString);
std::string stlString(cStr);
No need to call the Marshal functions!
UPDATE Thanks to Eric, I've modified the sample code to check for the size of the input string to prevent buffer overflow.
I spent hours trying to convert a windows form listbox ToString value to a standard string so that I could use it with fstream to output to a txt file. My Visual Studio didn't come with marshal header files which several answers I found said to use. After so much trial and error I finally found a solution to the problem that just uses System::Runtime::InteropServices:
void MarshalString ( String ^ s, string& os ) {
using namespace Runtime::InteropServices;
const char* chars =
(const char*)(Marshal::StringToHGlobalAnsi(s)).ToPointer();
os = chars;
Marshal::FreeHGlobal(IntPtr((void*)chars));
}
//this is the code to use the function:
scheduleBox->SetSelected(0,true);
string a = "test";
String ^ c = gcnew String(scheduleBox->SelectedItem->ToString());
MarshalString(c, a);
filestream << a;
And here is the MSDN page with the example:
http://msdn.microsoft.com/en-us/library/1b4az623(v=vs.80).aspx
I know it's a pretty simple solution but this took me HOURS of troubleshooting and visiting several forums to finally find something that worked.
C# uses the UTF16 format for its strings.
So, besides just converting the types, you should also be conscious about the string's actual format.
When compiling for Multi-byte Character set Visual Studio and the Win API assumes UTF8 (Actually windows encoding which is Windows-28591 ).
When compiling for Unicode Character set Visual studio and the Win API assume UTF16.
So, you must convert the string from UTF16 to UTF8 format as well, and not just convert to std::string.
This will become necessary when working with multi-character formats like some non-latin languages.
The idea is to decide that std::wstring always represents UTF16.
And std::string always represents UTF8.
This isn't enforced by the compiler, it's more of a good policy to have.
#include "stdafx.h"
#include <string>
#include <codecvt>
#include <msclr\marshal_cppstd.h>
using namespace System;
int main(array<System::String ^> ^args)
{
System::String^ managedString = "test";
msclr::interop::marshal_context context;
//Actual format is UTF16, so represent as wstring
std::wstring utf16NativeString = context.marshal_as<std::wstring>(managedString);
//C++11 format converter
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> convert;
//convert to UTF8 and std::string
std::string utf8NativeString = convert.to_bytes(utf16NativeString);
return 0;
}
Or have it in a more compact syntax:
int main(array<System::String ^> ^args)
{
System::String^ managedString = "test";
msclr::interop::marshal_context context;
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> convert;
std::string utf8NativeString = convert.to_bytes(context.marshal_as<std::wstring>(managedString));
return 0;
}
I like to stay away from the marshaller.
Using CString newString(originalString);
Seems much cleaner and faster to me. No need to worry about creating and deleting a context.
// I used VS2012 to write below code-- convert_system_string to Standard_Sting
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace System;
using namespace Runtime::InteropServices;
void MarshalString ( String^ s, std::string& outputstring )
{
const char* kPtoC = (const char*) (Marshal::StringToHGlobalAnsi(s)).ToPointer();
outputstring = kPtoC;
Marshal::FreeHGlobal(IntPtr((void*)kPtoC));
}
int _tmain(int argc, _TCHAR* argv[])
{
std::string strNativeString;
String ^ strManagedString = "Temp";
MarshalString(strManagedString, strNativeString);
std::cout << strNativeString << std::endl;
return 0;
}
For me, I was getting an error with some of these messages. I have an std::string. To convert it to String^, I had to do the following String^ sysString = gcnew String(stdStr.c_str()); where sysString is a System::String^ and stdStr is an std::string. Hope this helps someone
You may have to #include <string> for this to work

Resources