Blog

PeopleCode and C Integration

We've had blog postson how integrating PeopleCode with various other languages before, but one of the things that I punted on previously was showing how to do really deep integration with C. Or more accurately, .DLLs/shared objects.

Strangely enough, I've actually had occasion recently to dig back into some of this for some work that we've been doing to integrate with another product. I'll spare you the details of that (for now - since the work isn't done yet :-), but I thought I'd share how the technical bits work. Most folks can feel safe to skip this entry - we're digging into the weeds here. But sometimes you have to really get your hands dirty to accomplish something (or so my wife says to me), so that's what we're going to do here.

In a nutshell, the problem that we're trying to solve is that when we want to access various functionality that is exposed in .DLL files (they're called shared objects on Linux/Unix, but I'm just going to refer to .DLL files here - the concepts translate well though) there are numerous occasions when the function that we're calling wants to deal with a structure (struct). The easiest way to think of a structure is that you have a single "thing" that has a bunch of fields in it.

Unfortunately, the integration that PeopleCode has for .DLLs does not support structures. What to do? Roll your own, of course!

To provide a concrete example that everyone can try on their own, I'm using the Windows API call for getting the local system time. The MSDN documentation (a great resource) shows that the GetLocalTime function returns a pointer to a SYSTEMTIME structure.

PeopleCode will support getting back the return pointer to the struct (it just ends up as a Number in PeopleCode), but we need to do some extra work to dig out the specific data values that we want. The trick is realizing that a struct is really all sequential in memory. So, since we know where the beginning of the struct is (from the return value) and we know the definition of the struct (from the doc), we can calculate how far away from the beginning of the struct the data that we want is. We can then use the Windows RtlMoveMemory function to grab the data from the appropriate place (we can also use this same function to write data into a struct, but here we're just reading data).

Let's take a look at some sample code.

Scroll bar


We start off by declaring the actual Windows API functions that we're going to use to get our work done. This is all standard stuff and documented in PeopleBooks. The only wrinkle here is that we declare the RtlMoveMemory function with the name CopyPtrToInt so that we can leverage the existing PeopleCode infrastructure for passing data back and forth. In the other code that I'm working on, there are multiple "Declare Function" statements that all reference RtlMoveMemory with different names (CopyPtrToLong, CopyLongToPtr, etc).

Next we have a little function that just maps a word that describes a struct datatype (e.g. "long", "integer", "word", etc) with how many bytes that datatype will occupy. We need this so that if we want to, say, grab the 5th field from a struct, we know how many bytes in it starts.

We follow that with a function that exists purely for sanity checking our structure definitions in PeopleCode. When you call into .DLLs, there is practically no error handling, so if you pass it bad data, then you'll quickly get to meet Doctor Watson.

Next up is a function that will tell us how large our strucuture is. We need to know this for when we actually allocate memory for the structure. Speaking of which, allocation and deallocation of memory are what the next two function handle. Very important to always deallocate any memory that you allocate (which is why we have all of these wrapper functions), but you can only deallocate it once.

OK, we're in the home stretch in now. Only two more infrastructure functions define and then we can actually do something. The first one is used to know where inside a struct a "field" is. We need this so that we can access data in the struct by fieldname, while under the covers it gets mapped to a specific memory offset in the structure.

The last infrastructure function we need is something that will return an actual PeopleCode value to us from the structure. Whew! The demo code just has something to return an Integer. If the structure had other field types in it (Longs, Strings, etc. ), then you'd want to mimic this function for those data types.

Now we're finally down to the meat of it. Or the main course of it if you're a vegetarian. We're ready to define what our SYSTEMTIME structure is, allocate the memory for it, call the GetLocalTime API function, and display our results.

Our function creates two array definitions. One is the list of field names that are in the struct. These can actually be anything that you want to refer to the fields as, but it's always good to keep them somewhat in sync with whatever "C level" documentation that you have regarding the struct. The second array has the same number of values as the first array, but it is a list of all of the data types for each field in the first array. We combine these into a single array for passing around to all of our infrastructure functions, and then we're good to go.

When we run this program, we get output similar to "2006-6-20 14:36:16". A lot of work just to get the time, eh? True enough that there are better ways of getting the time, but there are lots of other uses for this type of strategy that it makes a nice example.

Ok, now it's time for Ketan or Chili Joe to catch any of my typos :-)

Labels:

Comments (3)
3Wednesday, 22 June 2011 05:57
Ketan Kothari
This is really interesting. I had similar issue for reading values from java array. It is not documented anywhere. I will post that on my blog. Only thing documented is how to pass values to java array. How about using java instead of C to accomplish the same. Also the added benefit is it is cross platform
2Wednesday, 22 June 2011 05:57
Chris Heller
Yes, there are definitely better ways of getting the time, but I used this function because it was one of the simplest examples of working C structs from within PeopleCode.

The other code that I'm working with would have taken too much of the post just explaining what the end goal of the code is. Since this post was already pretty deep in the weeds, I didn't want to add any additional complexity.
1Wednesday, 22 June 2011 05:56
Chili Joe
Chris, this is an great followup to the other DLL article.

One limitation that I could see is that this doesn't seem to handle composite types (structs within a struct). It would have been great if there is a library that can convert a struct to xml by passing the pointer and an xml schema to define the structure of the struct. I tried searching in Google and I can't find one.

Regards -
Joe

Add your comment

Your name:
Comment:

News Archives