Getting updated string from unmanaged DLL

C

CapCity

We're rewritting an app using C# 2005 and it needs to read files in netCDF
format. A dll is available for this and we've had success in calling its
functions, unless it updates strings. We have tried several of the
suggestions we've found on-line: Strings, StringBuilders, IntPtr, etc., but
haven't been able to exactly pull it off.

What seem to be closest is the following. It's a function that will return a
variable name for a given file ID and variable ID. We first have this:



[DllImport("netcdf.dll", CharSet = CharSet.Unicode)] //Also have
tried all other options than Unicode - same result
public static extern int nc_inq_varname(int ncid, int varid,
[Out,MarshalAs(UnmanagedType.LPTStr)] StringBuilder varName);



Then the call:


StringBuilder varName = new StringBuilder(100);
int status = nc_inq_varname(NCID, varID, varName);



The status comes back as 0, which is a success. varName.ToString() gives us
"????m????????9" but we know the name to be "TEMP_1p5m". The file has a
another variable, TFLAG, but using that varID gives back a variable name of
"??G??????????9".

Both returned values are the same length. And oddly enough, the "m" in the
first one, and the "G" in the second one, are recognizable in the known
values. And if each of the leading "?" were to represent 2 characters of the
known value then the "m" and "G" are in the right place.

Any thoughts on how to get the string value correctly?
 
J

Jianwei Sun

CapCity said:
We're rewritting an app using C# 2005 and it needs to read files in netCDF
format. A dll is available for this and we've had success in calling its
functions, unless it updates strings. We have tried several of the
suggestions we've found on-line: Strings, StringBuilders, IntPtr, etc., but
haven't been able to exactly pull it off.

What seem to be closest is the following. It's a function that will return a
variable name for a given file ID and variable ID. We first have this:



[DllImport("netcdf.dll", CharSet = CharSet.Unicode)] //Also have
tried all other options than Unicode - same result
public static extern int nc_inq_varname(int ncid, int varid,
[Out,MarshalAs(UnmanagedType.LPTStr)] StringBuilder varName);



Then the call:


StringBuilder varName = new StringBuilder(100);
int status = nc_inq_varname(NCID, varID, varName);



The status comes back as 0, which is a success. varName.ToString() gives us
"????m????????9" but we know the name to be "TEMP_1p5m". The file has a
another variable, TFLAG, but using that varID gives back a variable name of
"??G??????????9".

Both returned values are the same length. And oddly enough, the "m" in the
first one, and the "G" in the second one, are recognizable in the known
values. And if each of the leading "?" were to represent 2 characters of the
known value then the "m" and "G" are in the right place.

Any thoughts on how to get the string value correctly?

More like an encoding issue to me.

tried all other options than Unicode - same result

What options you have tried, if you can list all the options you tired,
people here may be able to help you.

And what's the byte value of those ?, are they same ??

John
 
R

rossum

We're rewritting an app using C# 2005 and it needs to read files in netCDF
format. A dll is available for this and we've had success in calling its
functions, unless it updates strings. We have tried several of the
suggestions we've found on-line: Strings, StringBuilders, IntPtr, etc., but
haven't been able to exactly pull it off.

What seem to be closest is the following. It's a function that will return a
variable name for a given file ID and variable ID. We first have this:



[DllImport("netcdf.dll", CharSet = CharSet.Unicode)] //Also have
tried all other options than Unicode - same result
Unicode covers a multitude of sins. Have you tried being more
specific: ASCII, UTF7, UTF8? EBCDIC would be a long shot I suspect.
public static extern int nc_inq_varname(int ncid, int varid,
[Out,MarshalAs(UnmanagedType.LPTStr)] StringBuilder varName);



Then the call:


StringBuilder varName = new StringBuilder(100);
int status = nc_inq_varname(NCID, varID, varName);
Have you tried char[]? For disgnostic purposes you might also want to
try passing in a byte[] and have a look at what comes back as hex -
that might give you a better idea of what the dll is actually
returning.
The status comes back as 0, which is a success. varName.ToString() gives us
"????m????????9" but we know the name to be "TEMP_1p5m". The file has a
another variable, TFLAG, but using that varID gives back a variable name of
"??G??????????9".
Try converting the return directly to a byte array to see what is
actually in there before you start trying to convert it. After
conversion you are seeing a mix of the return and the conversion
function. You need to start by looking just at the return from the
dll. Once you know exactly what is going into the conversion function
should you have a look at what is coming out of it.
Both returned values are the same length. And oddly enough, the "m" in the
first one, and the "G" in the second one, are recognizable in the known
values. And if each of the leading "?" were to represent 2 characters of the
known value then the "m" and "G" are in the right place.
This may mean that there is UTF16 in there somewhere. UTF16 uses two
bytes per character rather than one byte for UTF7, UTF8 or ASCII. The
same length may just be due to overflow protection preventing writing
off the end of an array or string.

rossum
 
C

CapCity

Jianwei Sun said:
CapCity said:
We're rewritting an app using C# 2005 and it needs to read files in
netCDF format. A dll is available for this and we've had success in
calling its functions, unless it updates strings. We have tried several
of the suggestions we've found on-line: Strings, StringBuilders, IntPtr,
etc., but haven't been able to exactly pull it off.

What seem to be closest is the following. It's a function that will
return a variable name for a given file ID and variable ID. We first have
this:



[DllImport("netcdf.dll", CharSet = CharSet.Unicode)] //Also have
tried all other options than Unicode - same result
public static extern int nc_inq_varname(int ncid, int varid,
[Out,MarshalAs(UnmanagedType.LPTStr)] StringBuilder varName);



Then the call:


StringBuilder varName = new StringBuilder(100);
int status = nc_inq_varname(NCID, varID, varName);



The status comes back as 0, which is a success. varName.ToString() gives
us "????m????????9" but we know the name to be "TEMP_1p5m". The file has
a another variable, TFLAG, but using that varID gives back a variable
name of "??G??????????9".

Both returned values are the same length. And oddly enough, the "m" in
the first one, and the "G" in the second one, are recognizable in the
known values. And if each of the leading "?" were to represent 2
characters of the known value then the "m" and "G" are in the right
place.

Any thoughts on how to get the string value correctly?

More like an encoding issue to me.

tried all other options than Unicode - same result

What options you have tried, if you can list all the options you tired,
people here may be able to help you.

The options are Ansi, Auto, None and Unicode
And what's the byte value of those ?, are they same ??

The byte values of each of those is 63, the ascii code for "?"
 
C

CapCity

rossum said:
We're rewritting an app using C# 2005 and it needs to read files in netCDF
format. A dll is available for this and we've had success in calling its
functions, unless it updates strings. We have tried several of the
suggestions we've found on-line: Strings, StringBuilders, IntPtr, etc.,
but
haven't been able to exactly pull it off.

What seem to be closest is the following. It's a function that will return
a
variable name for a given file ID and variable ID. We first have this:



[DllImport("netcdf.dll", CharSet = CharSet.Unicode)] //Also have
tried all other options than Unicode - same result
Unicode covers a multitude of sins. Have you tried being more
specific: ASCII, UTF7, UTF8? EBCDIC would be a long shot I suspect.
public static extern int nc_inq_varname(int ncid, int varid,
[Out,MarshalAs(UnmanagedType.LPTStr)] StringBuilder varName);



Then the call:


StringBuilder varName = new StringBuilder(100);
int status = nc_inq_varname(NCID, varID, varName);
Have you tried char[]? For disgnostic purposes you might also want to
try passing in a byte[] and have a look at what comes back as hex -
that might give you a better idea of what the dll is actually
returning.
The status comes back as 0, which is a success. varName.ToString() gives
us
"????m????????9" but we know the name to be "TEMP_1p5m". The file has a
another variable, TFLAG, but using that varID gives back a variable name
of
"??G??????????9".
Try converting the return directly to a byte array to see what is
actually in there before you start trying to convert it. After
conversion you are seeing a mix of the return and the conversion
function. You need to start by looking just at the return from the
dll. Once you know exactly what is going into the conversion function
should you have a look at what is coming out of it.

The byte values for those ? are 63, so they're actual ? and not just
something to represent something unprintable
 
C

CapCity

CapCity said:
We're rewritting an app using C# 2005 and it needs to read files in netCDF
format. A dll is available for this and we've had success in calling its
functions, unless it updates strings. We have tried several of the
suggestions we've found on-line: Strings, StringBuilders, IntPtr, etc.,
but haven't been able to exactly pull it off.

What seem to be closest is the following. It's a function that will return
a variable name for a given file ID and variable ID. We first have this:



[DllImport("netcdf.dll", CharSet = CharSet.Unicode)] //Also have
tried all other options than Unicode - same result
public static extern int nc_inq_varname(int ncid, int varid,
[Out,MarshalAs(UnmanagedType.LPTStr)] StringBuilder varName);



Then the call:


StringBuilder varName = new StringBuilder(100);
int status = nc_inq_varname(NCID, varID, varName);



The status comes back as 0, which is a success. varName.ToString() gives
us "????m????????9" but we know the name to be "TEMP_1p5m". The file has a
another variable, TFLAG, but using that varID gives back a variable name
of "??G??????????9".

Both returned values are the same length. And oddly enough, the "m" in the
first one, and the "G" in the second one, are recognizable in the known
values. And if each of the leading "?" were to represent 2 characters of
the known value then the "m" and "G" are in the right place.

Any thoughts on how to get the string value correctly?

Thanks to all who put thought into this. The solution to the above was to
have LPStr as the MarshalAs type, not LPTStr.


Now we're fighting with another function in the same DLL. The signature is:

int nc_get_var_float (int ncid, int varid, float *fp). We're looking to see
what we can use in C# to hold the array of floats. Just using an array of
floats gives some error code that MS says can be fixed by installing SP2 for
Win 2000 (we're running XP).
 
M

Mattias Sjögren

Now we're fighting with another function in the same DLL. The signature is:
int nc_get_var_float (int ncid, int varid, float *fp). We're looking to see
what we can use in C# to hold the array of floats. Just using an array of
floats gives some error code that MS says can be fixed by installing SP2 for
Win 2000 (we're running XP).

A float[] should work fine. Can you post your declaration, calling
code and details on the error you get?


Mattias
 
C

CapCity

Mattias Sjögren said:
Now we're fighting with another function in the same DLL. The signature
is:

int nc_get_var_float (int ncid, int varid, float *fp). We're looking to
see
what we can use in C# to hold the array of floats. Just using an array of
floats gives some error code that MS says can be fixed by installing SP2
for
Win 2000 (we're running XP).

A float[] should work fine. Can you post your declaration, calling
code and details on the error you get?

Absolutely.


The documentation that came with the DLL has the signature as this:

int nc_get_var_float (int ncid, int varid, float *fp).



Our declaration is:

[DllImport("netcdf.dll")]
public static extern int nc_get_var_float(int ncid, int varid, ref float[]
fValues);


The call is this:

float[] fValues = { 0.0F }; //Build error if this array is not
initialized
status = nc_get_var_float(NCID, varID, ref fValues);



And the message we get on the call is:

The program '[496] EPAWA41_Dev2.vshost.exe: Managed' has exited with
code -1073741819 (0xc0000005).



We tried to add some marshalling to the declaration, but got a pop-up
'FatalExecutionEngineError'.
 
M

Mattias Sjögren

Our declaration is:
[DllImport("netcdf.dll")]
public static extern int nc_get_var_float(int ncid, int varid, ref float[]
fValues);

Try it without the ref modifier.


Mattias
 
C

CapCity

Mattias Sjögren said:
Our declaration is:

[DllImport("netcdf.dll")]
public static extern int nc_get_var_float(int ncid, int varid, ref float[]
fValues);

Try it without the ref modifier.

That worked! I also had to declare the array with a fixed size, but it is
known ahead of time, so that's not too big of a deal. I think the last is a
"feature" with the DLL and not really a rule of thumb. The "ref" thing makes
sense now that you pointed it out.

Anyway - thank you!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top