return a String as LPCTSTR fails

178 views
Skip to first unread message

Michael Bauschert

unread,
Oct 1, 2012, 4:15:58 AM10/1/12
to jna-...@googlegroups.com
Hi,

can anybody tell me why this code returns "Test" on the java side

LPCTSTR  jTest() {
LPCTSTR s1 = "Test";
return s1;
}

and this not:

LPCTSTR  jTest() {
CString s1 = "Test";
s1.ReleaseBuffer();
LPCTSTR  s = s1.GetBuffer();
return s;
}

JUnit returns:

junit.framework.ComparisonFailure: expected:<[Test]> but was:<[ÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝî QÝÝ]>
at junit.framework.Assert.assertEquals(Assert.java:81)

So why do i receive data rubbish ?

My Envirnoment:

Win7 / 64Bit
VS 2005 / MS SDK 7.1
JRE1.6 32 Bit


Michael Bauschert

unread,
Oct 1, 2012, 6:04:39 AM10/1/12
to jna-...@googlegroups.com
In the meantime i found out, that switch in release mode fixes the issue:

Debug-Config (fails):

<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_WINDOWS;_DEBUG;_USRDLL"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
PrecompiledHeaderThrough="stdafx.h"
PrecompiledHeaderFile=".\Debug/header.pch"
AssemblerListingLocation=".\Debug/"
ObjectFile=".\Debug/"
ProgramDataBaseFileName=".\Debug/"
WarningLevel="3"
SuppressStartupBanner="true"
DebugInformationFormat="4"
/>

Release-Config (works)

<Tool
Name="VCCLCompilerTool"
Optimization="4"
InlineFunctionExpansion="0"
PreprocessorDefinitions="WIN32;_WINDOWS;NDEBUG;_USRDLL"
RuntimeLibrary="2"
UsePrecompiledHeader="0"
PrecompiledHeaderThrough="stdafx.h"
PrecompiledHeaderFile=".\Debug/header.pch"
AssemblerListingLocation=".\Debug/"
ObjectFile=".\Debug/"
ProgramDataBaseFileName=".\Debug/"
WarningLevel="3"
SuppressStartupBanner="true"
DebugInformationFormat="1"
CompileAs="0"
/>

Anybody an idea why?

Daniel Doubrovkine

unread,
Oct 1, 2012, 9:13:40 AM10/1/12
to jna-...@googlegroups.com
This is very likely something in the marshaller, but lets imagine you can fix this - you will be leaking memory. Once the pointer returned, the data will get copied to a Java memory buffer and then it will be orphaned without a chance for you to release it.
--

dB. | Moscow - Geneva - Seattle - New York
dblock.org - @dblockdotorg


Michael Bauschert

unread,
Oct 1, 2012, 9:18:31 AM10/1/12
to jna-...@googlegroups.com
Hi Daniel,

how can i safely return a a string without creating a memory leak?

Regards
Michael

Daniel Doubrovkine

unread,
Oct 1, 2012, 9:34:56 AM10/1/12
to jna-...@googlegroups.com
There's an example in https://github.com/twall/jna/blob/master/www/FrequentlyAskedQuestions.md, you need a function that doesn't allocate memory but expects memory in and fills the string out.

How do I read back a function's string result?

Suppose you have a function:

// Returns the number of characters written to the buffer
int getString(char* buffer, int bufsize);

The native code is expecting a fixed-size buffer, which it will fill in with the requested data. A Java String is not appropriate here, since Strings are immutable. Nor is a Java StringBuffer, since the native code only fills the buffer and does not change its size. The appropriate argument type would be either byte[]Memory, or an NIO Buffer, with the size of the object passed as the second argument. The method Native.toString(byte[]) may then be used to convert the array of byte into a Java String.

Timothy Wall

unread,
Oct 1, 2012, 10:46:50 PM10/1/12
to jna-...@googlegroups.com
Alternatively, if you return a pointer to native-allocated memory, you need to provide an complementary function to free that memory later, e.g.

Pointer getString(); // use Pointer.getString(0) on the return value to get the string value
void freeString(Pointer p);

Michael Bauschert

unread,
Oct 2, 2012, 2:54:27 AM10/2/12
to jna-...@googlegroups.com
Hi,

now i have the native method 

public void jTest(char[] array, int length);

My C++-Code looks like this:

void jTest(char** result, int length) { 
char* test = "Test";
result = &test;
}

my Java TestCase does a 

char[] array = new char[1024];
wrapper.jTest(array,array.length);
String result = Native.toString(array);

But after calling the jTest method the array is still empty.

I have used also a byte[] instead of a char array, and use a single pointer instead of a pointer to a pointer for the c++ method - without success

Any Ideas what's going wrong?


2012/10/2 Timothy Wall <twal...@java.net>

Michael Bauschert

unread,
Oct 2, 2012, 3:09:20 AM10/2/12
to jna-...@googlegroups.com
Hi,

i've changed two things and now it's working:

- using again a byte[] instead of a char[]
- doing a strcpy on the c++ side

void jTest(char* result, int length) { 
const char* test = "Test";
strcpy(result,test);
}

Last Question: Why do i need the length argument? strcpy is also working if length of target is smaller than the length of the source, by doing a simple truncation...




2012/10/2 Michael Bauschert <Michael....@web.de>

Timothy Wall

unread,
Oct 2, 2012, 5:49:46 AM10/2/12
to jna-...@googlegroups.com
You should use strncpy, using the "length" input, to avoid potentially overrunning the buffer that was passed in.

If I pass you a buffer of length 4, and you try to write a string longer than that, your program will likely crash.
Reply all
Reply to author
Forward
0 new messages