Getting a string value from a C function that doesn't _return_ the value

Agreed. I read that all backwards. That said, looking back at the original declare:

Private Soft Declare Function GetCameraParam Lib LibCoaxLink (byref fgHandle as int32, param as CString, byref cValue as CString) As Integer

There’s one more thing that looks wrong…

I don’t think the first parameter is supposed to be byref.

1 Like

I will try this on Monday again. I did set it up that way at first, but the result was empty unless I prepopulated the memory block with some characters.

As I posted above, the size of the variable is not pre-defined. It is resized on the fly in the C function as needed. See the code I posted in reply #5 above.

This library can’t possibly know how big it would need to be, because it’s interfacing with a generic camera control API (GenICam), which allows the manufacturers to set their own parameters as needed. If I plugged a different camera into the card, I would potentially see a whole bunch of parameters that I don’t see now. So it takes the argument in, and then figures out how big it is before putting it in a variable. At least, that’s how I’m reading it.

Hah. well it’s been a while and I haven’t worked on this since that was written, so it just disappeared from my brain I guess.

I am calling it byref in all other instances (about 30 functions that require the handle). I suppose it wouldn’t matter to me if I dropped that and it still works, as I’m storing the handle in a property once I obtain it from the grabber upon initialization so I have that available whenever I need it. But it works fine as-is though, so is there a reason I wouldn’t want to do it byref? It’d be a bunch of code to have to change and then re-test.

See

Page 38 and 46 mention string length maximum either as 128 and/or there is a function to query it.

Hmm. There are parameters that hold file paths, which could very easily go over 128 characters.

The DLL I have is unsupported, provided by the frame grabber manufacturer because they already had it - it was writtend for a customer using LabView, which has similar requirements to Xojo in terms of external libaries (namely, that it has to be C). They did send me the source code for it, but any changes to it would have to be made by me. I can find no code in the library that deals with string lengths.

I am basically working with what I have here…

That said, the DLL exposes a subset of their API. It’s possible that’s handled internally in their larger API, which is C++ maybe?

Well… the problem with doing it byref is that (as Mike mentioned above) you’re passing a pointer to a pointer. If it’s working, chances are that the driver handles that on the backend, but really the only reason to use byref is if you are expecting the thing that you are passing to change.

My take is that all 3 parameters in the function are simple pointers.

The confusion is that in a Xojo delcare, when you pass a CString it’s automatically converted to a pointer, so if you do byref x as CString you are passing a pointer to a pointer, which won’t work.

I believe you want this:

Private Soft Declare Function GetCameraParam Lib LibCoaxLinkGrabber (byref fgHandle as int32, param as Cstring, value as Cstring) As Integer

Or, if you want to use memoryBlocks:

Private Soft Declare Function GetCameraParam Lib LibCoaxLinkGrabber (byref fgHandle as int32, param as Ptr, value as Ptr) As Integer

I would probably just handle this by allocating a memoryBlock or CString which is “big enough” and then add extra for safety. Too big will not cause a problem, but if you allocate too little, you run the risk of crashing.

So at this point I need to just move on, and sending a pre-populated memoryblock works so I’m going to go with that unless someone can show me definitively how to make this work otherwise

I have tried this:

var cParam as CString = param
var cValue as new MemoryBlock(256)
returnValue = GetCameraParam(fgHandle, cParam, cValue)

//where GetCameraParam() is expecting
Private Function GetCameraParam(byref fgHandle as int32, param as CString, cValue as ptr) As int32

And the result is empty. If I put a break in my code to see what cValue contains after calling GetCameraParam, it’s all 0000s and it looks like the size is correct (256) but the value that was returned by the passed parameter is not there.

If I change cValue to have actual text in it:

var cValue as memoryblock = "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"

Then it works, but I need to parse out the excess "~~~"s

If I change cValue to an empty cstring, and pass GetCameraParam that value, my application simply quits in the debugger.

var cParam as CString = param
var cValue as CString
returnValue = GetCameraParam(fgHandle, cParam, cValue)

//where GetCameraParam() is expecting
Private Function GetCameraParam(byref fgHandle as int32, param as CString, cValue as cString) As int32

If I do the tilde trick like I did with memoryblocks, populating cValue (as a CString with tildes), then it also crashes my app.

If I pass it an empty or populated CString, and GetCameraParam passes that to the library byref, then the result is empty (but no crash).

At this point, I need to keep moving forward. The way I’m doing it is working, but ugly. But it works. Unless I’m missing something obvious here, I don’t see how I can simply pass a CString to my library and get it to update the results. And the memoryblock only works if there’s something in it when I send it to the library, not just when it’s set to the right size.

1 Like

This is only a guess, but…

  • perhaps the library checks the length of the string you passed in, so that it doesn’t try to write out more bytes than were allocated.
  • when you create an empty memoryBlock, it’s filled with bytes all with the value of 0
  • a 0 byte is the convention in C for “this is the end of my string” (aka Null terminated)
  • therefore, by passing in an empty (all zeros) memoryBlock, the library thinks you have given it a zero-length C string, and thus doesn’t write back the result.
  • if that’s the case, then your solution seems sensible.

This could be a Xojo bug, or perhaps simply undefined behavior, e.g. if you have

dim foobar as CString
or
dim foobar as CString = ""

I’m not sure what foobar should be. Nil? A pointer to a single byte of 0x00 ? Unclear.

That seems like it should work and not crash, however.

1 Like