logo       

Passing byte arrays into C functions: msg#00012

windows.devel.jawin

Subject: Passing byte arrays into C functions

I give up - I must be stupid.. I have been trying to figure out how to
run something as simple as GetComputerNameW in kernel32.dll.. and I keep
getting horrible errors - Access violations, running out of memory, etc.

I am going to explain my thinking step by step, you never know, it might
help me figure out exactly what I'm doing wrong.

Well, in the tradition of answering your own questions, this is exactly
what happenned : after trying to get this right for the last many hours,
and after getting a hole bunch of errors ranging from memory access
violations (e.g. when I was passing the second param as a regular int (an
I instruction) , and no as a pointer to an int (a P4 instruction)),
running out of memory, "filename too long", I finally got it. Another
error that I didn't figure out for the longest time was that I was
creating a String with the length of 300, and then I wrote that string to
the output stream (instead of writing an array of bytes with the length of
300, I was writing an unicode string with the length of 300 - which in
bytes is probably 4 times longer) and then passing instructions that the
byte array was 300 bytes long . I realize that I might be making an ass
out of myself, but this could be helpful for some other newbie. Also, I
might try to put together something like the mini-program below, and then
provide them to the project as documentation.



Ok, this is the description of the function:

BOOL GetComputerName(
LPTSTR lpBuffer,
LPDWORD lpnSize
);

Parameters
lpBuffer
[out] Pointer to a buffer that receives a null-terminated string
containing the computer name or the cluster virtual server name. The
buffer size should be large enough to contain MAX_COMPUTERNAME_LENGTH + 1
characters.
lpnSize
[in, out] On input, specifies the size of the buffer, in TCHARs. On
output, the number of TCHARs copied to the destination buffer, not
including the terminating null character.
If the buffer is too small, the function fails and GetLastError returns
ERROR_BUFFER_OVERFLOW. The lpnSize parameter specifies the size of the
buffer required, not including the terminating null character.

So, in order to get things right, this is what I do (in Jython again, but
it should be easy to folow):

from org.jawin import *
from org.jawin.io import *
from org.jawin.marshal import *
from com.divintech.testing import *
from java.io import *

getCompName = FuncPtr("kernel32.dll","GetComputerNameW")

nbs = NakedByteStream();
leos = LittleEndianOutputStream(nbs);

# This creates a buffer, 300 bytes long writing 1 in each byte
for i in range(300):
leos.writeByte(1)

#write out the length of the buffer
leos.writeInt(300)

# It doesn't seem like I can fit this method call into any of the
"shortcut" invokes, so I go with the long one

# this instruction doesn't work - I guess because the parameter of
GetComputerName is an int pointer, and not an int
# this part of the instructions, for me it means that I am passing a byte
array with a length of 300 and a 4 byte out param - it would have been ok
if the 2nd param of the function was taking an int, and not a
# pointer to int
# instructions = "P300A"

#therefore, the correct instruction is, because the P4 basically says -
take the address this, and put the address to the native method -
essentially passing a pointer to the native method.

instructions = "P300P4"

# the return method is an int so then:
instructions = instructions + ":I:"

# at the end, we have 2 out parameter - the first is the buffer of length
300 and then an int of length 4
instructions = instructions + "n300n4"

# then, the function call is
# the first argument is the instruction string that I composed.
# the second argument is the stack size - 304 - since we passed the whole
buffer on the stack ??? - is this correct ?
# the remaining arguments really don't need an explanation
res = getCompName.invoke(instructions, 304, nbs, None,
ReturnFlags.CHECK_FALSE)

# now, construct the inputstream over the result
leis = LittleEndianInputStream(ByteArrayInputStream(res))

# read the return value - at this point I'm not using it, it gets checked
by the ReturnFlags param
b1 = leis.readInt()

# then, read the string , using the suggested length , which gives us the
correct value
## Da-Da-a-a, this is the actual result, which is correct without any
errors.
leis.readUnicodeSz(300)

# Finally , read in how many characters were put into the buffer
r2 = leis.readInt()





Regards,

Alex Kotchnev
Developer / Systems Analyst
Diversified Information Technologies

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
CONFIDENTIALITY NOTICE: If you have received this e-mail in error, please
immediately notify the sender by e-mail at the address shown. This e-mail
transmission may contain confidential information. This information is
intended only for the use of the individual(s) or entity to whom it is
intended even if addressed incorrectly. Please delete it from your files
if you are not the intended recipient. Thank you for your compliance.
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++



<Prev in Thread] Current Thread [Next in Thread>
Google Custom Search

News | FAQ | advertise