473,387 Members | 1,517 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,387 software developers and data experts.

Global C Struct

Forgive me for being a C# newbie.

I have read all of the newsgroup posts, MSDN articles, and other websites on
interop and marshalling to send and receive a C struct as a parameter or
return value in a C function call from C#.

My situation is slightly different, because the C struct I have is global.

I have tried different approaches/techniques (string, String, std::string,
IntPtr, Marshal, class, etc.), but none work. I was given a DLL written in
C. It defines a structure and declares a global instance of it, such as:

typedef struct errInfo
{
long number;
char* description;
} ERRINFOSTRUCT;

PUBLIC ERRINFOSTRUCT ERRINFO = { 0, " " };

It also has two global functions:
__declspec(dllexport) char * GetErrDesc();
__declspec(dllexport) void SetErr(long, char *);

I need to set the members of ERRINFO directly from C# (not using SetErr),
because :

- I am writing a unit test for GetErrDesc
- The two functions are in two different files ("units")
- We must keep our tests isolated (they cannot depend on other tests or
functions)

In all of my failed attempts to set ERRINFO.description, all of my calls to
GetErrDesc returned a space (" "). So, it was obvious that my code did not
actually set ERRINFO. As a test, I called SetErr(1, "Test"), and GetErrDesc
then returned a garbled string, so I know SetErr actually set ERRINFO.

I declared GetErrDesc using the [DllImport("C.dll")] and wish there was a
similar attribute I could use for declaring ERRINFO, but all I could find
was to create my own ERRINFO structure and marshal a copy of it. However, I
do not understand how this concept should even work, since nothing is tying
the managed C# ERRINFO memory to the unmanaged C ERRINFO memory, because there
is no passing of the struct in a function call.

I need to know: 1) how to set the members of C's global ERRINFO from C#; and
2) why I am getting a garbled string returned. My only recourse is to use
C++.NET, and I would rather stick with C#. I am also being forced to use
VS.NET 2002 right now.

Is there someone out there willing to help me with this, please?
(I have spent two 15-hour days on this and am at a stopping point with C#.)
Nov 16 '05 #1
3 2972
Sorry, but what you're looking to do isn't going to happen (from C# anyway).
P/Invoke works only for functions. Data members can't be accessed directly
(you have to provide one or more functions for passing data in or out).

As for the garbled string, you might have to set attribute values on the
P/Invoke definition to specify whether the string is ANSI/ASCII or Unicode.
The marshaller is probably assuming the wrong type of string.

-Rob Teixeira
"Erialc Berts" <er*********@yahoo.com> wrote in message
news:13**************************@posting.google.c om...
Forgive me for being a C# newbie.

I have read all of the newsgroup posts, MSDN articles, and other websites on interop and marshalling to send and receive a C struct as a parameter or
return value in a C function call from C#.

My situation is slightly different, because the C struct I have is global.

I have tried different approaches/techniques (string, String, std::string,
IntPtr, Marshal, class, etc.), but none work. I was given a DLL written in C. It defines a structure and declares a global instance of it, such as:

typedef struct errInfo
{
long number;
char* description;
} ERRINFOSTRUCT;

PUBLIC ERRINFOSTRUCT ERRINFO = { 0, " " };

It also has two global functions:
__declspec(dllexport) char * GetErrDesc();
__declspec(dllexport) void SetErr(long, char *);

I need to set the members of ERRINFO directly from C# (not using SetErr),
because :

- I am writing a unit test for GetErrDesc
- The two functions are in two different files ("units")
- We must keep our tests isolated (they cannot depend on other tests or
functions)

In all of my failed attempts to set ERRINFO.description, all of my calls to GetErrDesc returned a space (" "). So, it was obvious that my code did not actually set ERRINFO. As a test, I called SetErr(1, "Test"), and GetErrDesc then returned a garbled string, so I know SetErr actually set ERRINFO.

I declared GetErrDesc using the [DllImport("C.dll")] and wish there was a
similar attribute I could use for declaring ERRINFO, but all I could find
was to create my own ERRINFO structure and marshal a copy of it. However, I do not understand how this concept should even work, since nothing is tying the managed C# ERRINFO memory to the unmanaged C ERRINFO memory, because there is no passing of the struct in a function call.

I need to know: 1) how to set the members of C's global ERRINFO from C#; and 2) why I am getting a garbled string returned. My only recourse is to use
C++.NET, and I would rather stick with C#. I am also being forced to use
VS.NET 2002 right now.

Is there someone out there willing to help me with this, please?
(I have spent two 15-hour days on this and am at a stopping point with

C#.)
Nov 16 '05 #2
Erialc,

This is a little tricky. First, let's address the method declarations.
The GetErrDesc function is a problem, because it returns a pointer to a
character string. Now, it could be doing one of two things. It could be
returning a copy of the string in the description field, or it could be
returning a pointer to the description field itself. My assumption is that
it is doing the former (assuming it is coded correctly).

Now, if this is the case, then you won't be able to do anything without
modifying the original C code. Basically, you would have to write a
function that would return the address of the pointer in memory, like so:

ERRINFOSTRUCT * GetErrInfoPointer()

You would import this into C# as this:

[DllImport("C.dll")]
static extern IntPtr GetErrInfoPointer();

And then you would declare your structure and marshal it back and forth
with a call to the static PtrToStructure method on the Marshal class.

You will NOT want to call GetErrDesc in this case because it will be
allocating memory, and you will have to deallocate it. The thing is, if it
is using new or malloc, you will have to create a wrapper for delete or free
and call that from C# to make sure you dispose of the memory from the string
properly.

Now, if it is not really coded correctly and it returns the pointer in
memory of the description field, then you can just declare the function like
this:

[DllImport("C.dll")]
static extern IntPtr GetErrDesc();

And call it once, storing the IntPtr in memory. Then, whenever you want
to get the result, just call the static PtrToStringAnsi to get the string.

Hope this helps.
--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com
"Erialc Berts" <er*********@yahoo.com> wrote in message
news:13**************************@posting.google.c om...
Forgive me for being a C# newbie.

I have read all of the newsgroup posts, MSDN articles, and other websites
on
interop and marshalling to send and receive a C struct as a parameter or
return value in a C function call from C#.

My situation is slightly different, because the C struct I have is global.

I have tried different approaches/techniques (string, String, std::string,
IntPtr, Marshal, class, etc.), but none work. I was given a DLL written
in
C. It defines a structure and declares a global instance of it, such as:

typedef struct errInfo
{
long number;
char* description;
} ERRINFOSTRUCT;

PUBLIC ERRINFOSTRUCT ERRINFO = { 0, " " };

It also has two global functions:
__declspec(dllexport) char * GetErrDesc();
__declspec(dllexport) void SetErr(long, char *);

I need to set the members of ERRINFO directly from C# (not using SetErr),
because :

- I am writing a unit test for GetErrDesc
- The two functions are in two different files ("units")
- We must keep our tests isolated (they cannot depend on other tests or
functions)

In all of my failed attempts to set ERRINFO.description, all of my calls
to
GetErrDesc returned a space (" "). So, it was obvious that my code did
not
actually set ERRINFO. As a test, I called SetErr(1, "Test"), and
GetErrDesc
then returned a garbled string, so I know SetErr actually set ERRINFO.

I declared GetErrDesc using the [DllImport("C.dll")] and wish there was a
similar attribute I could use for declaring ERRINFO, but all I could find
was to create my own ERRINFO structure and marshal a copy of it. However,
I
do not understand how this concept should even work, since nothing is
tying
the managed C# ERRINFO memory to the unmanaged C ERRINFO memory, because
there
is no passing of the struct in a function call.

I need to know: 1) how to set the members of C's global ERRINFO from C#;
and
2) why I am getting a garbled string returned. My only recourse is to use
C++.NET, and I would rather stick with C#. I am also being forced to use
VS.NET 2002 right now.

Is there someone out there willing to help me with this, please?
(I have spent two 15-hour days on this and am at a stopping point with
C#.)

Nov 16 '05 #3
Thank you Rob and Nicholas for replying.
I'm not a happy camper, but that is because of C#'s shortcomings, not
you guys!
Global C structs are pretty common in legacy DLLs whose source code
has fallen by the wayside.
Ah well, back to C++/C++.NET.
Nov 16 '05 #4

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
by: Bryan Parkoff | last post by:
….I would like to know which is the best optimization to use global variable or global struct. I always tell C/C++ Compiler to turn on optimization. ….I use underscore between first name and...
8
by: Fernan Bolando | last post by:
I have been going through some of the tutorials on the internet regarding coding styles in unix C programming. Most of the stuff I have read do not prefer using global variables, But for multi-file...
5
by: PCHOME | last post by:
Hello! I am working on dividing a single C file into several files. Now I encounter a problem about the global variables and can not find a way to solve it. All global variables and codes used...
13
by: Sunil | last post by:
Hi all, I want to know how good or bad it is using global variables i.e advantages and disadvantages of using global variables. Sunil.
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.