473,406 Members | 2,698 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,406 software developers and data experts.

Interop problem

I am trying to implement an interface into a database API.
The API was originally designed for C, but has been used perfectly successfully in many programming languages (C++,Delphi/pascal even Cobol and VB)

The API is like this:
One declares a structure (actually a utility generates the declarations), which in C would be something like this

Expand|Select|Wrap|Line Numbers
  1. struct Customer
  2. {
  3.   short l;
  4.   short typenr;
  5.   /* more header fields */
  6.   /* data fields */
  7.   double cust_acc_nr;
  8.   char short_name[10];
  9.   char tel_nr[12];
  10.   char address[4][30];  
  11.   double balance;
  12.   /* more data fields */
  13. }
Then one might do something like
Expand|Select|Wrap|Line Numbers
  1. memcpy(customer.cust_ref,"XYZA1234",8);
  2. fetch(&customer,EQUAL);
The appropriate customer record is read from the database, directly into the data structure. The API also allows one to update, insert and delete records. Typically the database will have many hundreds of tables, so
the application may also have calls like

fetch(&employee) where employee is an analogous declaration for another table.

The API "knows" which table the application is working with from the header fields - in particular the
customer.l specifies the size of the customer record buffer, and the customer.typenr is a number unique to the customer table.

Now I am trying to implement this API in C#. Unfortunately C# makes it very difficult to handle fixed size character arrays. I made my program for generating declarations do the following for C#

Expand|Select|Wrap|Line Numbers
  1.   [StructLayout(LayoutKind.Explicit)]
  2.   public class _Customer: DP4.ITable
  3.   {
  4.     public static short _CUSTOMER=4117;
  5.     [FieldOffset(0)]
  6.     ushort l = 312;
  7.     [FieldOffset(2)]
  8.     short typenr = _CUSTOMER;
  9.     [FieldOffset(4)]
  10.     ushort generation;
  11.     [FieldOffset(6)]
  12.     ushort flags;
  13.     [FieldOffset(8)]
  14.     int timestamp;
  15.       [FieldOffset(16)]
  16.     internal double _cust_acc_nr;
  17.       [FieldOffset(24)]
  18.     [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
  19.     internal char [] _short_name;
  20.       [FieldOffset(34)]
  21.     [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
  22.     internal char [] _tel_nr;
  23.       [FieldOffset(48)]
  24.     double balance;
  25.     [DllImport(Provider.name, EntryPoint = Provider.rec_fetch, CharSet = CharSet.None)]
  26.     static extern int rec_fetch(IntPtr dconn,
  27.                                     [MarshalAs(UnmanagedType.LPStruct), In, Out ] _Customer rec,
  28.                                     int flags, int index, int index_role, int match_keys);
  29.  
  30.     public int Fetch(DP4.Database dconn,TableFetchFlags flags, int index,int index_role,int match_keys)
  31.     {
  32.       return rec_fetch(dconn.Dconn,this,(int)flags,index,index_role,match_keys);
  33.     }
  34.  
  35.   }
The Fetch() method, which is really generic has to be declared for every table so that C# can marshal the data. In fact there are many more similar declarations for other database methods. Provider is a class that just declares a large number of const strings, so that I can generate declarations without worrying about what the real names of the DLL and the entry points are (because, unfortunately these are different depending on whether the application is 32-bit or 64-bit, or designed to run on Windows CE). I'm only showing a low-level API here. The declarations above would be wrapped with something to provide get() and set() methods for a property corresponding to each member, and implement a more "object-oriented" API that would be to the taste of a C# programmer.

When I prototyped this, it seemed like it was going to work OK. Unfortunately when I tried it with a more complex table, although the code compiled OK, it refuses to run. I get this message:

Unhandled Exception: System.TypeLoadException: Could not load type 'Itim.DP4.Schemas.TABLES.INP._Customer' from assembly 'p4, Version=0.0.0.0, Culture=neutral,PublicKeyToken=null' because it contains an object field at offset 34 that is in correctly aligned or overlapped by a non-object field.
at Itim.NETTest2.Program.Main(String[] args)

I'm confused about this error message. I thought that the declaration I'm generating above was managing to declare the analogue of the C structure at the top. But the error message implies that what I'm really getting is something where _short_name is some kind of object being allocated in the heap, so that the name would be elsewhere. But my prototype worked fine, so that cannot be the case. So now I'm thinking that maybe C# has more onerous data alignment requirements than C/C++, and wants short_name to start on a four byte boundary or something. (There's no reason why it should - I'm laying out data in a manner that would satisfy all the alignment restrictions of any processor I've ever heard of)

I'd be really grateful for any insight and advice C# experts can offer. I'm hoping this is the only time in my life I have to write any C#, so I don't want to get into a religious debate about whether my C code should be transferring data like this. I need to implement this API, and the DLL has to be able to return some kind of customer object preferably with as little interference from C# marshalling as possible.

I know C# allows fixed char declarations. But that can only be used in unsafe code, which is not acceptable, and also they can only be used in structs and since I need a class object that would complicate things. So Layout.Explicit layout seems the way to go.

As long as I know how C# wants to lay out the data I can supply the data in that format. The API is more sophisticated that my explanation may have suggested, and can "swizzle" or "swab" data into whatever format a particular language demands. But I have to be able to return data in a single block. I can't create some complicated object containing sub-objects since the database itself is unmanaged C code.

If the worst comes to the worst I'd even be prepared to declare _tel_nr (for example) as 12 individual chars, since I can always provide get() and set() methods that turn it into a TelNr string property. But obviously, I'd prefer not to have to do that if at all possible. The code for generating C# declarations is already about five times more complex than the code for doing the C++ API, which in turn is twice as complex the C code.

Sorry this is a long post. Thanks in advance to anyone who can offer help.
Feb 11 '10 #1
4 1902
I have some more information

1) I changed my database tables so that all the fields would naturally begin on 4 byte boundaries. Then the program loads and runs correctly. So my best option may be to tell the database to lay the data out like that. It will waste some space for applications written in C/C++ but this is a fairly minor issue.

2) I then discovered the Pack=1 attribute, so I tried that on my original database. This makes no difference unless I change to LayoutKind Sequential and then the application also works! So it seems that the compiler IS enforcing an unnecessary alignment restriction.

I'm reluctant to use LayoutKind sequential because its not clear to me that I'm always going to guess right about exactly how data is arranged in memory for C# (even though I have to do exactly that for every other programming language). LayoutKind explicit is really what I should be using since it is essential the C code and C# code should agree about the contents of the structure.

It seems to me that C# should be fixed so that Pack=1 works OK with explicit classes/structures. But even then I'd probably avoid it since apparently Pack=1 is not supported on the Compact Framework one gets on Windows CE.
Feb 11 '10 #2
tlhintoq
3,525 Expert 2GB
TIP: When you are writing your question, there is a button on the tool bar that wraps the [code] tags around your copy/pasted code. It helps a bunch. Its the button with a '#' on it. More on tags. They're cool. Check'em out.
Feb 11 '10 #3
Thanks for the tip. I wrote the question in notepad and didn't realise my indentation would disappear. Next time I post I'll be sure to use the "go Advanced" button and make a bit more effort to make sure the question will look OK. I notice you can edit my posts, but I don't seem to have an "edit" button. That would be handy for correcting typos and other mistakes I notice too late.
Is that just for moderators or will I be able to do that kind of thing when I'm not a newbie any more or am I just being stupid and not seeing some obvious way of doing that?
Feb 11 '10 #4
tlhintoq
3,525 Expert 2GB
Is that just for moderators or will I be able to do that kind of thing when I'm not a newbie any more or am I just being stupid and not seeing some obvious way of doing that?
I'm embarressed to admit that I don't know.

Hello... Does one of the more experienced moderators know why this user can't edit his own posts?
Feb 11 '10 #5

Sign in to post your reply or Sign up for a free account.

Similar topics

1
by: Nadav | last post by:
Hi, Introduction *************** I have a system build of a collection of 'Native COM objects' and '.NET COM interop' objects, all of the COM objects are managed through a 'Native COM' layer,...
20
by: Razzie | last post by:
Hey all, I'm really going through a small hell right now - I've completely lost it :) I made a project, using two interop libraries from exchange (created them as in this msdn article:...
1
by: Shiro | last post by:
Hi I have read the various postings relating to Interop strong name signing and cannot find an example similar to mine. I have stringly named my AxInterops/Interops and they all work just...
8
by: Rob Edwards | last post by:
When trying to add the Microsoft CDO for Exchange Management Library (aka CDOEXM.dll) I receive the following message: "A reference to 'Microsoft CDO for Exchange Management Library' could not be...
7
by: R Reyes | last post by:
Can someone please explain to me why I can't get the MS Word Interop assembly to work in my VS2005 project? I'm trying to manipulate MS Word from my Web Form application and I can't get passed...
3
by: Hospital S.Sebastiao | last post by:
Hi, i'm in desperate need of help to fix a problem that i have, the problem is the following: I have an ASP.NET aplication that to open an word template document, this aplication is in C#(using...
2
by: JC | last post by:
Anybody knows what problem has this code? I think, in the Garbage Collector? You know the Solution? The program in the test's case, whit 350 contacts, run OK before number 86. The error is a...
1
by: Don.Leri | last post by:
Hi, I have a logger.dll (unmanaged c++ dll compiled in vs2005). I have a C# interop to use that dll in managed code implemented in Interfaces.dll (used by other C# dlls). I also have a...
1
by: allbelonging | last post by:
C#.Net Outlook 2003 automation (programmatically) with Office.Interop.Outlook Problem: I have my outlook 2003 configured with multiple mailbox on my local machine. I want to specify the mailbox...
0
by: Tina | last post by:
I've gotten this before where it says there is a problem with Interop.MSDASC but I can't remember what causes this. This is a 1.1 app I'm trying to debug in vs2005. It was running yesterday just...
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
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
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,...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

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.