12-05-2024 12:43 AM
getting somewhere.
Output is defined as char, should be string? But at least I get either k or l for kg or lbs. Funny enough, the wizzard made it string
12-05-2024 01:57 AM
@Steffen01 wrote:
getting somewhere.
Output is defined as char, should be string? But at least I get either k or l for kg or lbs. Funny enough, the wizzard made it string
It seems to be you have corrupted memory, but hard to say in absence of the DLL and VI.
It is very important to understand who will allocate space for the string (and deallocate).
Try this way, allocate 256 chars empty string in LabVIEW and pass as C String Pointer:
12-05-2024 02:10 AM - edited 12-05-2024 02:46 AM
You attached images instead of the actual VI. While it is true that images say more than 1000 words they are far not enough to let us see all the details of your VI.
- How are the parameters in the Call Library Node configured?
Instead of attaching 10 images showing all the various aspects of your VI and Call Library Configuration, you could attach the VI and be done with it (well the error message is kind of useful although it doesn't help much in this aspect.
Things to consider:
- Are you sure your function is __cdecl? The function prototype says nothing about the calling convention and most C compilers use __cdecl by default, even the Microsoft one, but a programmer can still change the default calling convention in the project settings or in the command line when invoking the compiler tool.
- Have you properly configured the first parameter as Passed by Pointer? The declaration uses a C++ reference operator, which would make that header fail on many standard C compilers, but technically it is for all compilers I know off equivalent to a pointer variable. The C++ standard says nothing about how it has to be implemented though, a C++ compiler would be fully within specifications to pass it back to the caller through special registers if he wished so.
- Since that string is a C pointer, and not even passed by reference, the caller has to make sure to allocate enough space that the function can write into. How much space you want to know? Only the documentation can tell you that for sure. The suggestion of Andrey to allocate a 256 byte buffer is most likely huge overkill but definitely on the safer side of things. Even one byte less than what the function wants to write into, including the terminating 0 byte, and you created a crash generator.
And there is nothing funny about the wizard concluding that char* is a C string pointer. A C string pointer is exactly a char*. The opposite is not necessarily true since C does not know a separate datatype for non-string byte data. So char* can be either a pointer to a C string or a pointer to a byte array.
Extra fun is guaranteed by the C compiler being free to treat char as either signed or unsigned byte value by default. The logical thing would be to treat it as signed, and most C compilers do so as default, since for other types signed is implicitly assumed when no signed or unsigned is specified. But for ASCII characters it is more logical to use unsigned byte values. Thanks to the overloading of the char datatype by two different meanings (one being a byte and the other being a, usually 8 bit, character) you get this complication. And C does not mandate that char is 8 bit. The only thing it says is that it should be easily addressable for the underlaying hardware architecture. That pretty much all CPUs nowadays are 8-bit is a historical coincidence, not a universal law. There used to be 7-bit and 9-bit CPUs in the beginning and even 4-bit was briefly entertained by Intel with their original 4004 CPU that can be seen as the grand-grand-grand parent of the modern Intel x86/x64CPUs.
But char could also be a 16-bit datatype if a CPU architecture had that as lowest directly addressable memory location. C is about as flexible to adapt to various hardware as you can possible imagine and then some more.
12-05-2024 04:45 AM - edited 12-05-2024 04:51 AM
pointer just points at the first character. Then change to string and get the characters behind
ok, now can do the simple functions and then try structs etc
thanks for your help, guys
12-05-2024 05:48 PM - edited 12-05-2024 05:50 PM
so thats that, 8 chars is plenty for 2 letters. Runtime error is gone. Just putting it here for future readers
// getweightTCdll.cpp : This file contains the 'main' function. Program execution begins and ends there.
#include "TurboCalcLibShort.h" //Include the TurboCalc Library to access the API functions.
//This example file assumes TurboCalcLibrary is in the same directory.
#include <iostream> //used for printing results to console.
#include <array> //used to store strings returned from the TurboCalc API.
#include <cstring>
using namespace std;
//void getWeightUnits(const int& variableCode, char* unitsName); //in library
int main()
{
int variableCode{ 1 };
std::array<char, 8> unitsName;
getWeightUnits(variableCode, unitsName.data());
std::cout << "unitsname1: " << unitsName.data() << '\n';
}
we don't want this
12-06-2024 12:39 AM
@Steffen01 wrote:
so thats that, 8 chars is plenty for 2 letters. Runtime error is gone.
So, the whole discussion above is just about how to call a function with char* as an argument from C++ using STL? If so, then we could have saved 40+ messages and quickly answered with code something like this:
#include <iostream>
#include <string>
...
std::string s(8, NULL);
getWeightUnits(1, &s[0]);
std::cout << "unitsname1: " << s << std::endl;
You should be careful with .data(), because this method is not null terminated and usually .c_str() is used instead (but not in your case, because .c_str() will require const char*).
I mean if somewhere it will be used in "opposite" direction something like this:
std::string unit = "kHz";
char dest[256];
strcpy(dest, unit.data());
then this could crash someday at strcpy().
But such mixture of C and C++ in general is not good in my humble opinion.
12-06-2024 01:11 AM
no, its not just about some text. Then just would have used the wizzard.
Its about a .dll from a supplier which has some objects and what not as input and some array as output, which is beyond LV onboard capabilities.
So I need to make a wrapper dll and for that need to learn C++. There are a few simpler functions n tat dll, so I use them for testing if I get something from that dll. Also I need to learn how to compile a dll which symbolises the supplier dll, then make a 2nd one (the wrapper) which I can then call from Labview. So for a start that one did a sum, and the 2nd one just called it.
Who knows, someone later may find this useful as well, not many people get born as C++ programmers.
12-06-2024 02:47 AM
@Steffen01 wrote:
no, its not just about some text. Then just would have used the wizzard.
Its about a .dll from a supplier which has some objects and what not as input and some array as output, which is beyond LV onboard capabilities.
So I need to make a wrapper dll and for that need to learn C++. There are a few simpler functions n tat dll, so I use them for testing if I get something from that dll. Also I need to learn how to compile a dll which symbolises the supplier dll, then make a 2nd one (the wrapper) which I can then call from Labview. So for a start that one did a sum, and the 2nd one just called it.
Who knows, someone later may find this useful as well, not many people get born as C++ programmers.
Oh, sorry, I just didn't catch your "high level goal" from the initial message.
12-15-2024 10:24 PM
almost there but now no joy to connect to my dll. The results come out ok, tested same in a console app. Plus, there are 2 outputs in that function, 20 doubles and an error string. Maybe to simplify things I shove everything into some comma separated string. Then the wissard may do its thing. As it is now, just guess work. Does it not like the array?
Meanwhile some other stuff, wrestling the input from Labview into a char so supllier dll accepts it
12-16-2024 02:56 AM - edited 12-16-2024 03:02 AM
Guessing when doing C programming is about as safe as driving car with closed eyes. Unless you are psychic in some ways, it’s guaranteed to crash!
For one, string is a very specific C++ template class and the only one able to treat that properly is the C compiler who created that code. You can’t even call safely functions using that type as parameter from other C compilers than what was used to create that function.
But with only pictures we can pretty much just conclude that you have indeed problems, but we can not even start to make helpful recommendations how to go about it other than: “Get rid of that ‘string’ in parameters of functions you want to call with the LabVIEW Call Library Node””
This must be char* or LStrHandle, unless you feel confident to be a C compiler yourself. And yes if you chose for char* you have to be very careful about proper buffer allocation on the LabVIEW side for strings the function is supposed to write into. If you use LStrHandle, your C code needs to call LabVIEW memory manager functions when wanting to allocate, reallocate or deallocate them.