How do I provide access to the library I wrap with cgo? - c

I am trying to write bindings for a C library, specifically the libnfc. My current code is available on Github.
One of the central structures in the libnfc is the device. It is represented by the Go type Device.
type Device struct {
d *C.nfc_device
}
All functions inside the libnfc that operate on a Device are methods of it. Now, there are other C libraries (e.g. the libfreefare) whose APIs operates on nfc_devicees. For the sake of modularity, I want to place the code for each library I wrap into its own module. This leads to the problem, that I can't access private structure members from within other modules. I thought about the following solutions:
Make d a public member of Device
This would make it easy to access the underlying nfc_device from within other modules, but it makes it also easy to sidestep type safety. Additionally, I don't know whether cgo recognizes pointers to foreign types if they come from different modules. Finally, I lose flexibility if I change the structure of the Device type.
Add an accessor func (Device) GetCPtr() unsafe.Pointer
This solves the issues above but introduces the new issue that you suddently have access to an unsafe.Pointer in a module that might not even import unsafe.
Add an accessor func (Device) GetCPtr() uintptr
This solves the aforementioned issue, as you have to manually cast the result to get a proper pointer.
Are there any ways I missed? Is there a better, more idiomatic way to provide access to the underlying nfc_device?

I'm generally in favour with the third proposal of yours as this is the way the reflect package
handles this issue.
What you could also do is to expose only an interface in your libnfc wrapper, e.g.
type NFCDevice interface {
Read() ([]byte, error)
Write() ([]byte, error)
// ...
}
Now you have a public API that is safe.
Additionally, your device type implements a function
func (d *device) NfcDevice() *C.nfc_device {
return d.nfc_device
}
which you can use in your other wrappers by asserting your NFCDevice to implement the
interface
interface {
NfcDevice() *C.nfc_device
}
which you can create on the fly in the other wrappers. This way a programmer has to deliberately
do something to access the inner workings of your device.

Related

How to design generic backward compatible API for embedded software application library interface in C?

I am tasked to assist with the design of a dynamic library (exposed with a C interface) aimed to be used in embed software application on various embed platform (Android,Windows,Linux).
Main requirements are speed , and decoupling.
For the decoupling part : one of our requirement is to be able to facilitate integration and so permit backward compatibility and resilience.
My library have some entry points that should be called by the integrating software (like an initialize constructor to provide options as where to log, how to behave etc...) and could also call some callback in the application (an event to inform when task is finished).
So I have come with several propositions but as each of one not seems great I am searching advice on a better or standard ways to achieve decoupling an d backward compatibility than this 3 ways that I have come up :
First an option that I could think of is to have a generic interface call for my exposed entry points for example with a hashmap of key/values for the parameters of my functions so in pseudo code it gives something like :
myLib.Initialize(Key_Value_Option_Array_Here);
Another option is to provide a generic function to provide all the options to the library :
myLib.SetOption(Key_Of_Option, Value_OfOption);
myLib.SetCallBack(Key_Of_Callbak, FunctionPointer);
When presenting my option my collegue asked me why not use a google protobuf argument as interface between the library and the embed software : but it seems weird to me, as their will be a performance hit on each call for serialization and deserialization.
Are there any more efficient or standard way that you coud think of?
You could have a struct for optional arguments:
typedef struct {
uint8_t optArg1;
float optArg2;
} MyLib_InitOptArgs_T;
void MyLib_Init(int16_t arg1, uint32_t arg2, MyLib_InitOptArgs_T const * optionalArgs);
Then you could use compound literals on function call:
MyLib_Init(1, 2, &(MyLib_InitOptArgs_T){ .optArg2=1.2f });
All non-specified values would have zero-ish value (0, NULL, NaN), and would be considered unused. Similarly, when passing NULL for struct pointer, all optional arguments would be considered unused.
Downside with this method is that if you expect to have many new arguments in the future, structure could grow too big. But whether that is an issue, depends on what your limits are.
Another option is to simply have multiple smaller initialization functions for initializating different subsystems. This could be combined with the optional arguments system above.

Why does a System.Array object have an Add() method?

I fully understand that a System.Array is immutable.
Given that, why does it have an Add() method?
It does not appear in the output of Get-Member.
$a = #('now', 'then')
$a.Add('whatever')
Yes, I know this fails and I know why it fails. I am not asking for suggestions to use [System.Collections.ArrayList] or [System.Collections.Generic.List[object]].
[System.Array] implements [System.Collections.IList], and the latter has an .Add() method.
That Array implements IList, which is an interface that also covers resizable collections, may be surprising - it sounds like there are historical reasons for it[1]
.
In C#, this surprise is hard to stumble upon, because you need to explicitly cast to IList or use an IList-typed variable in order to even access the .Add() method.
By contrast, since version 3, PowerShell surfaces even a type's explicit interface implementations as direct members of a given type's instance. (Explicit interface implementations are those referencing the interface explicitly in their implementation, such as IList.Add() rather than just .Add(); explicit interface implementations are not a direct part of the implementing type's public interface, which is why C# requires a cast / interface-typed variable to access them).
As a byproduct of this design, in PowerShell the .Add() method can be called directly on System.Array instances, which makes it easier to stumble upon the problem, because you may not realize that you're invoking an interface method. In the case of an array, the IList.Add() implementation (rightfully) throws an exception stating that Collection was of a fixed size; the latter is an exception of type NotSupportedException, which is how types implementing an interface are expected to report non-support for parts of an interface.
What helps is that the Get-Member cmdlet and even just referencing a method without invoking it - simply by omitting () - allow you to inspect a method to determine whether it is native to the type or an interface implementation:
PS> (1, 2).Add # Inspect the definition of a sample array's .Add() method
OverloadDefinitions
-------------------
int IList.Add(System.Object value)
As you can see, the output reveals that the .Add() method belongs to the Ilist interface.
[1] Optional reading: Collection-related interfaces in .NET with respect to mutability
Disclaimer: This is not my area of expertise. If my explanation is incorrect / can stand improvement, do tell us.
The root of the hierarchy of collection-related interfaces is ICollection (non-generic, since v1) and ICollection<T> (generic, since v2).
(They in turn implement IEnumerable / IEnumerable<T>, whose only member is the .GetEnumerator() method.)
While the non-generic ICollection interface commendably makes no assumptions about a collection's mutability, its generic counterpart (ICollection<T>) unfortunately does - it includes methods for modifying the collection (the docs even state the interface's purpose as "to manipulate generic collections" (emphasis added)). In the non-generic v1 world, the same had happened, just one level below: the non-generic IList includes collection-modifying methods.
By including mutation methods in these interfaces, even read-only/fixed-size lists/collections (those whose number and sequence of elements cannot be changed, but their element values may) and fully immutable lists/collections (those that additionally don't allow changing their elements' values) were forced to implement the mutating methods, while indicating non-support for them with NotSupportedException exceptions.
While read-only collection implementations have existed since v1.1 (e.g, ReadOnlyCollectionBase), in terms of interfaces it wasn't until .NET v4.5 that IReadOnlyCollection<T> and IImmutableList<T> were introduced (with the latter, along with all types in the System.Collections.Immutable namespace, only available as a downloadable NuGet package).
However, since interfaces that derive from (implement) other interfaces can never exclude members, neither IReadOnlyCollection<T> nor IImmutableCollection<T> can derive from ICollection<T> and must therefore derive directly from the shared root of enumerables, IEnumerable<T>.
Similarly, more specialized interfaces such as IReadOnlyList<T> that implement IReadOnlyCollection<T> can therefore not implement IList<T> and ICollection<T>.
More fundamentally, starting with a clean slate would offer the following solution, which reverses the current logic:
Make the major collection interfaces mutation-agnostic, which means:
They should neither offer mutation methods,
nor should they make any guarantees with respect to immutability.
Create sub-interfaces that:
add members depending on the specific level of mutability.
make immutability guarantees, if needed.
Using the example of ICollection and IList, we'd get the following interface hierarchy:
IEnumerable<T> # has only a .GetEnumerator() method
ICollection<T> # adds a .Count property (only)
IResizableCollection<T> # adds .Add/Clear/Remove() methods
IList<T> # adds read-only indexed access
IListMutableElements<T> # adds writeable indexed access
IResizableList<T> # must also implement IResizableCollection<T>
IResizableListMutableElements<T> # adds writeable indexed access
IImmutableList<T> # guarantees immutability
Note: Only the salient methods/properties are mentioned in the comments above.
Note that these new ICollection<T> and IList<T> interfaces would offer no mutation methods (no .Add() methods, ..., no assignable indexing).
IImmutableList<T> would differ from IList<T> by guaranteeing full immutability (and, as currently, offer mutation-of-a-copy-only methods).
System.Array could then safely and fully implement IList<T>, without consumers of the interface having to worry about NotSupportedExceptions.
To "Add" to #mklement0's answer: [System.Array] implements [System.Collections.IList] which specifies an Add() method.
But to answer why have an Add() if it doesn't work? Well, we haven't looked at the other properties, i.e. IsFixedSize :
PS > $a = #('now', 'then')
PS > $a.IsFixedSize
True
So, a [System.Array] is just a [System.Collections.IList] that is a Fixed Size. When we look back at the Add() method, it explicitly defines that if the List is Read-Only or Fixed Size, throw NotSupportedException which it does.
I believe the essence is not, "Let's have a function that just throws an error message for no reason", or to expand on it, No other reason than to fulfill an Interface, but it actually is providing a warning that you are legitimately doing something that you shouldn't do.
It's the typical Interface ideas, you can have an IAnimal type, with an GetLeg() method. This method would be used 90% of all animals, which makes it a good reason for implementing into the base Interface, but would throw an error when you use it against a Snake object because you didn't first check the .HasFeet property first.
The Add() method is a really good method for a List Interface, because it is an essential method for Non-Readonly and Non-Fixed length lists. We are the ones being stupid by not checking that the list is not IsFixedSize before calling an Add() method that would not work. i.e. this falls into the category of $null checks before trying to use things.

GObject OOP Syntax

I'm looking for a GObject cheat sheet, how common OOP concepts map to GObject's facilities. Consider for example:
AnyGObject *o;
o = anygobject_new();
Now, what are the conventions for...
calling a method
calling a method declared by a base class
calling a method declared by an interface the class is implementing
calling a class method
calling a class method declared by a base class
calling a virtual method
casting to a base class
casting to a derived class
casting to an interface the class is implementing
testing whether an object is of a particular type
...
Clarification:
The GObject Reference Manual and GObject HowTo explain at length how to create a new class (class struct, object struct, private struct, various macros, conventions). Taken together these facilities allow for OOP. Yet there seems to be no tutorial on how to use them consistently.
This answer assumes you are working with C. Other (usually object-oriented) languages have special bindings built to make working with GObject seem more natural.
If you've worked with GTK+, you already have done much of that list.
GObject methods are not members themselves (there is a vtable of sorts but it's only used for assigning virtual method implementations in a derived class when the class is first created). Instead, all methods in GObject are just plain functions, usually(?) prefixed by a method name prefix, and with the this pointer as the first argument.
For example, the C++ method
namespace Lib { // short for Library; to demonstrate GObject's idiomatic naming conventions
class Foo {
public:
void Bar(int z);
};
}
would be a plain function in the global namespace declared as
void lib_foo_bar(LibFoo *foo, int z);
and you would call it directly, just like any other C function.
Class derivation in GObject occurs by having the full data structure of the parent class as the first member of the derived class's data structure. For various reasons pertaining to rarely-discussed clauses in the C standard (and possibly the System V ABI and implementation of gcc, clang, and even the Microsoft C compilers), this means that a pointer to an object of the derived class is equivalent to a pointer to the parent class!
So if LibBaz derives from LibFoo, all you would need to say is
LibFoo *foobaz = (LibFoo *) baz;
and the same applies in reverse:
LibBaz *bazfoo = (LibBaz *) foo;
(This latter approach is what GTK+ uses for GtkWidget; I don't know if other GObject libraries do the same thing.)
Idiomatic GObject declarations include a bunch of macros that make the type conversions more terse while at the same time adding runtime type safety checks. Our LibFoo class would have the following macros:
#define LIB_TYPE_FOO (lib_foo_get_type())
#define LIB_FOO(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), LIB_TYPE_FOO, LibFoo))
With this, we would instead say
LibFoo *foobaz = LIB_FOO(baz);
LibBaz *bazfoo = LIB_BAZ(foo);
and if either baz or foo isn't the correct type for the conversion, a warning will be logged to standard error, which you can break at and investigate using a debugger.
(The lib_foo_get_type() function (and LIB_TYPE_FOO neatness macro) is important: it returns a numeric ID that maps to the type of LibFoo for future reference. If LibFoo doesn't have such a mapping, it will create the mapping, registering the type and creating the virtual method mappings.)
A similar macro allows type checking:
#define LIB_IS_FOO(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), LIB_TYPE_FOO))
which is a simple expression that can be used in an if statement.
So what about calling parent class methods? Well, if we put all of the above together, we have the answer:
lib_foo_parent_method(LIB_FOO(aLibBazInstance), params);
The same applies to virtual methods. Virtual methods are implemented using the GObject approximation to vtables and are transparent to the end programmer. All you will do is
lib_foo_virtual_method(LIB_FOO(whatever), params);
(If you actually build the derived class itself, the how of virtual methods becomes important.)
There are no static methods in GObject, because methods aren't tied to a class as closely as they are in real object-oriented languages. Just create a top-level method in your library:
void lib_something_common(params);
Finally, all of the above applies to interfaces. Interfaces work the exact same way to the end user; they use the same
void lib_iface_method(LibIface *iface, params);
approach to method calling, the same casting rules, and the same LIB_IFACE() and LIB_IS_IFACE() helper macros.
Hopefully that helps! Any further explanation would have to tread into explaining how to create a GObject, which I tried to keep outside the scope of this answer for simplicity's sake, but is a useful thing to know anyway.

Encapsulation concept

I have problem with concept and implementation of encapsulation.
Can someone explain it to me?
Encapsulation is a moderately easy concept once you realise it (probably) comes from the same base word as capsule.
It's simply a containment of information.
Encapsulation means that a class publishes only what is needed for others to use it, and no more. This is called information hiding and it means classes can totally change their internals without having an effect on any of their users.
In other words, a dictionary class can begin life as a simple array and progress to a binary tree of words then even maybe to some database access functions, all without changing the interface to it.
In an object oriented world, objects hold both their data and the methods used to manipulate data and that is the pinnacle of encapsulation. One way this is done is to make sure each object knows which functions to call to manipulate its data, and ensure the correct ones are called.
As an example, here's a class for maintaining integer lists in my mythical, but strangely Python-like and therefore hopefully easy to understand, language:
class intlist:
private int val[10] # Slots for storing numbers.
private bool used[10] # Whether slot is used or not.
public constructor:
# Mark all slots unused.
for i in 0..9:
used[i] = false
public function add(int v) throws out-of-memory:
# Check each slot.
for i in 0..9:
# If unused, store value, mark used, return.
if not used[i]:
used[i] = true
val[i] = v
return
# No free slots, so throw exception.
throw out-of-memory
public function del(int v) throws bad-value:
# Check each slot.
for i in 0..9:
# If slot used and contains value.
if used[i] and val[i] == v:
# Mark unused and return.
used[i] = false
return
# Value not found in any used slot, throw exception.
throw bad-value
public function has(int v):
# Check each slot.
for i in 0..9:
# If slot used and contains value.
if used[i] and val[i] == v:
return true
# Value not found in any used slot.
return false
Now the only information published here are the constructor and three functions for adding, deleting, and checking for values (including what exceptions can be thrown).
Callers need know nothing about the internal data structures being used (val and used), or the properties of the functions beyond their "signatures" (the content of the "function" lines).
Because everything else is encapsulated, it can changed it at will without breaking the code that uses it.
I could, for example, do any of the following:
make the arrays longer;
store the data sorted, or in a binary tree instead of an array to make it faster.
change the used array into a count array (initialised to zero) so that many occurrences of a single number use just the one slot, increasing the quantity of numbers that can be stored where there are duplicates.
store the numbers in a database, located on a ZX-80 retro-computer located in outback Australia, and powered by methane produced from kangaroo droppings (though you may notice a latency change).
Basically, as long as the published API doesn't change, we am free to do whatever we want. In fact, we can also add things to the API without breaking other code, I just can't delete or change anything that users already rely on.
You should note that encapsulation isn't something new with object orientation. It's been around for ages, even in C by ensuring that information is hidden within a module (usually a source file or group thereof with private headers).
In fact, the stdio.h FILE* stuff is a good example of this. You don't care what's actually behind the pointer since all the functions which use it know how to do their stuff.
link text
I always explain it to people is think of yourself as an object. Other people can see your height, they can see if your smiling, but your inner thoughts, maybe the reason while your smiling, only you know.
Encapsulation is more than just defining accessor and mutator methods for a class. It is broader concept of object-oriented programming that consists in minimizing the interdependence between classes and it is typically implemented through information hiding.
The beauty of encapsulation is the power of changing things without affecting its users.
In a object-oriented programming language like Java, you achieve encapsulation by hiding details using the accessibility modifiers (public, protected, private, plus no modifier which implies package private). With these levels of accessibility you control the level of encapsulation, the less restrictive the level, the more expensive change is when it happens and the more coupled the class is with other dependent classes (i.e. user classes, subclasses).
Therefore, the goal is not to hide the data itself, but the implementation details on how this data is manipulated.
The idea is to provide a public interface through which you gain access to this data. You can later change the internal representation of the data without compromising the public interface of the class. On the contrary, by exposing the data itself, you compromise encapsulation, and therefore, the capacity of changing the way you manipulate the data without affecting its users. You create a dependency with the data itself, and not with the public interface of the class. You would be creating a perfect cocktail for trouble when "change" finally finds you.
There are several reasons why you might want to encapsulate access to your fields. Joshua Bloch in his book Effective Java, in Item 14: Minimize the accessibility of classes and members, mentions several compelling reasons, which I quote here:
You can limit the values that can be stored in a field (i.e. gender must be F or M).
You can take actions when the field is modified (trigger event, validate, etc).
You can provide thread safety by synchronizing the method.
You can switch to a new data representation (i.e. calculated fields, different data type)
However, encapsulation is more than hiding fields. In Java you can hide entire classes, by this, hiding the implementation details of an entire API. Think, for example, in the method Arrays.asList(). It returns a List implementation, but you do no care which implementation, as long as it satisfies the List interface, right?. The implementation can be changed in the future without affecting the users of the method.
The Beauty of Encapsulation
Now, in my opinion, to really understand encapsulation, one must first understand abstraction.
Think, for example, in the level of abstraction in the concept of a car. A car is complex in its internal implementation. They have several subsystem, like a transmission system, a break system, a fuel system, etc.
However, we have simplified its abstraction, and we interact with all cars in the world through the public interface of their abstraction. We know that all cars have a steering wheel through which we control direction, they have a pedal that when you press it you accelerate the car and control speed, and another one that when you press it you make it stop, and you have a gear stick that let you control if you go forward or backwards. These features constitute the public interface of the car abstraction. In the morning you can drive a sedan and then get out of it and drive an SUV in the afternoon as if it was the same thing.
However, few of us know the details of how all these features are implemented under the hood. Think of the time when cars did not have a hydraulics directional system. One day, the car manufactures invented it, and they decide it to put it in cars from there on. Still, this did not change the way in which users where interacting with them. At most, users experienced an improvement in the use of the directional system. A change like this was possible because the internal implementation of a car is encapsulated. Changes can be safely done without affecting its public interface.
Now, think that car manufactures decided to put the fuel cap below the car, and not in one of its sides. You go and buy one of these new cars, and when you run out of gas you go to the gas station, and you do not find the fuel cap. Suddenly you realize is below the car, but you cannot reach it with the gas pump hose. Now, we have broken the public interface contract, and therefore, the entire world breaks, it falls apart because things are not working the way it was expected. A change like this would cost millions. We would need to change all gas pumps in the world. When we break encapsulation we have to pay a price.
So, as you can see, the goal of encapsulation is to minimize interdependence and facilitate change. You maximize encapsulation by minimizing the exposure of implementation details. The state of a class should only be accessed through its public interface.
I really recommend you to read a paper by Alan Snyder called Encapsulation and Inheritance in Object-Oriented programming Languages. This link points to the original paper on ACM, but I am pretty sure you will be able to find a PDF copy through Google.
Encapsulation - wrapping of data in single unit. also we can say hiding the information of essential details.
example
You have a mobile phone.... there it some interface which helps u to interact with cell phone and u can uses the services of mobile phone. But the actually working in cell phone is hide. u don't know how it works internally.
hide/bind something : eg: a capsule (which we consume when v r ill)hide/bind some powder form in itself,, means that capsule encapsulate the powder contained it.
Binding of data and behavior i.e functionality of an object in a secured and controlled manner.
or the best example of encapsulation is a CLASS because a class hides class variables/functions from outside d class..
Encapsulation:
Wrapping up data member and method together into a single unit (i.e. Class) is called Encapsulation.
Eg: we can consider a capsule. Encapsulation means hiding the internal details of an object, i.e. how an object does something. Here capsule is a single Unit contain many things. But we cant see what is there in side capsule.
This is the technique used to protect information about an object from other objects. Like variable we can set as private and property as Public. When we access the property then we validate and set it.
We can go through some other examples. Our Laptop. We can use Laptop but what operations are happening inside that we are not knowing. But we can use that. Same like mobile, TV etc.
We can conclude that a group of related properties, methods, and other members are treated as a single unit or object.An encapsulated object is often called an abstract data type.
There are several other ways that an encapsulation can be used, as an example we can take the usage of an interface. The interface can be used to hide the information of an implemented class.
//Declare as Private
private string _LegName;
// Property Set as public
public string LegName
{
get
{
return _LegName;
}
set
{
_LegName=value;
}
public class LegMain
{
public static int Main(string[] args)
{
Leg L= new Leg();
d.LegName="Right Leg";
Console.WriteLine("The Legis :{0}",d.LegName);return 0;
}
}
Note: Encapsulation provides a way to protect data from accidental corruption.
Thank you
Encapsulation means hiding the data. In other words a class only exposes those properties or information which is authorized to be seen. Consider the below exapmle where a certain property called ConfidentialMessage is accesible only to the Admin role. This property is made private and is returned through another method which checks the role of an user and return the message only for admin.
public class Message
{
public Message()
{
ConfidentialMessage = "I am Nemo";
}
private string ConfidentialMessage { get; set; }
public string GetMessage(string name)
{
string message = string.Empty;
if (name == "Admin")
{
message = this.ConfidentialMessage;
}
return message;
}
}
Putting definition of encapsulate
enclose in a capsule, from en- "make, put in" + capsule + -ate .
now capsule meaning is box, case
In real life example if you put things on desk open then it is accessible to anyone but if you put in case then it is accessible with the key of case to open.
Same way in class if you create a variable then it accessible whenever you create object of that class.But if you create function to access the variable then you have created case and function is key to access the variable.
So in programming language we are creating wrapper of the data by using getter and setter and making it private variable.
Encapsulation is a capsule, consider it to be a class enclosing or hiding fields, properties and functions.
Please check below url encapsulation is simplified with simple programming example.
http://itsforlavanya.blogspot.com/2020/08/encapsulation.html?m=1

Supporting multiple instances of a plugin DLL with global data

Context: I converted a legacy standalone engine into a plugin component for a composition tool. Technically, this means that I compiled the engine code base to a C DLL which I invoke from a .NET wrapper using P/Invoke; the wrapper implements an interface defined by the composition tool. This works quite well, but now I receive the request to load multiple instances of the engine, for different projects. Since the engine keeps the project data in a set of global variables, and since the DLL with the engine code base is loaded only once, loading multiple projects means that the project data is overwritten.
I can see a number of solutions, but they all have some disadvantages:
You can create multiple DLLs with the same code, which are seen as different DLLs by Windows, so their code is not shared. Probably this already works if you have multiple copies of the engine DLL with different names. However, the engine is invoked from the wrapper using DllImport attributes and I think the name of the engine DLL needs to be known when compiling the wrapper. Obviously, if I have to compile different versions of the wrapper for each project, this is quite cumbersome.
The engine could run as a separate process. This means that the wrapper would launch a separate process for the engine when it loads a project, and it would use some form of IPC to communicate with this process. While this is a relatively clean solution, it requires some effort to get working, I don't now which IPC technology would be best to set-up this kind of construction. There may also be a significant overhead of the communication: the engine needs to frequently exchange arrays of floating-point numbers.
The engine could be adapted to support multiple projects. This means that the global variables should be put into a project structure, and every reference to the globals should be converted to a corresponding reference that is relative to a particular project. There are about 20-30 global variables, but as you can imagine, these global variables are referenced from all over the code base, so this conversion would need to be done in some automatic manner. A related problem is that you should be able to reference the "current" project structure in all places, but passing this along as an extra argument in each and every function signature is also cumbersome. Does there exist a technique (in C) to consider the current call stack and find the nearest enclosing instance of a relevant data value there?
Can the stackoverflow community give some advice on these (or other) solutions?
Put the whole darn thing inside a C++ class, then references to variables will automatically find the instance variable.
You can make a global pointer to the active instance. This should probably be thread-local (see __declspec(thread)).
Add extern "C" wrapper functions that delegate to the corresponding member function on the active instance. Provide functions to create new instance, teardown existing instance, and set the active instance.
OpenGL uses this paradigm to great effect (see wglMakeCurrent), finding its state data without actually having to pass a state pointer to every function.
Although I received a lot of answers that suggested to go for solution 3, and although I agree it's a better solution conceptually, I think there was no way to realize that solution practically and reliably under my constraints.
Instead, what I actually implemented was a variation of solution #1. Although the DLL name in DLLImport needs to be a compile-time constant, this question explains how to do it dynamically.
If my code before looked like this:
using System.Runtime.InteropServices;
class DotNetAccess {
[DllImport("mylib.dll", EntryPoint="GetVersion")]
private static extern int _getVersion();
public int GetVersion()
{
return _getVersion();
//May include error handling
}
}
It now looks like this:
using System.IO;
using System.ComponentModel;
using System.Runtime.InteropServices;
using Assembly = System.Reflection.Assembly;
class DotNetAccess: IDisposable {
[DllImport("kernel32.dll", EntryPoint="LoadLibrary", SetLastError=true)]
private static extern IntPtr _loadLibrary(string name);
[DllImport("kernel32.dll", EntryPoint = "FreeLibrary", SetLastError = true)]
private static extern bool _freeLibrary(IntPtr hModule);
[DllImport("kernel32.dll", EntryPoint="GetProcAddress", CharSet=CharSet.Ansi, ExactSpelling=true, SetLastError=true)]
private static extern IntPtr _getProcAddress(IntPtr hModule, string name);
private static IntPtr LoadLibrary(string name)
{
IntPtr dllHandle = _loadLibrary(name);
if (dllHandle == IntPtr.Zero)
throw new Win32Exception();
return dllHandle;
}
private static void FreeLibrary(IntPtr hModule)
{
if (!_freeLibrary(hModule))
throw new Win32Exception();
}
private static D GetProcEntryDelegate<D>(IntPtr hModule, string name)
where D: class
{
IntPtr addr = _getProcAddress(hModule, name);
if (addr == IntPtr.Zero)
throw new Win32Exception();
return Marshal.GetDelegateForFunctionPointer(addr, typeof(D)) as D;
}
private string dllPath;
private IntPtr dllHandle;
public DotNetAccess()
{
string dllDir = Path.GetDirectoryName(Assembly.GetCallingAssembly().Location);
string origDllPath = Path.Combine(dllDir, "mylib.dll");
if (!File.Exists(origDllPath))
throw new Exception("MyLib DLL not found");
string myDllPath = Path.Combine(dllDir, String.Format("mylib-{0}.dll", GetHashCode()));
File.Copy(origDllPath, myDllPath);
dllPath = myDllPath;
dllHandle = LoadLibrary(dllPath);
_getVersion = GetProcEntryDelegate<_getVersionDelegate>(dllHandle, "GetVersion");
}
public void Dispose()
{
if (dllHandle != IntPtr.Zero)
{
FreeLibrary(dllHandle);
dllHandle = IntPtr.Zero;
}
if (dllPath != null)
{
File.Delete(dllPath);
dllPath = null;
}
}
private delegate int _getVersionDelegate();
private readonly _getVersionDelegate _getVersion;
public int GetVersion()
{
return _getVersion();
//May include error handling
}
}
Phew.
This may seem extremely complex if you see the two versions next to each other, but once you've set up the infrastructure, it is a very systematic change. And more importantly, it localizes the modification in my DotNetAccess layer, which means that I don't have to do modifications scattered all over a very large code base that is not my own.
In my opinion, solution 3 is the way to go.
The disadvantage that you have to touch every call to the DLL should apply to the other solutions, too... without the lack of scalability and uglyness of the multiple-DLL approach and the unnecessary overhead of IPC.
Solution 3 IS the way to go.
Imagine, that current object oriented programming languages work similar to your 3rd solution, but only implicitly pass the pointer to the structure that contains the data of "this".
Passing around "some kind of context thing" is not cumbersome, but it is just how things work! ;-)
Use approach #3. Since the code is in C, an easy way to deal with the globals that are spread everywhere is to define a macro for each global that has the same name as the global variable, but the macro expands to something like getSession()->theGlobal where getSession() returns a pinter to a "session-specific" structure that holds all the data for your globals. getSession() would fish the right data structure out of a global map of data structures somehow, perhaps using thread-local storage, or based on process ID, etc.
Actually solution 3 is easier than it sounds. All other solutions are kind of patch and will break with time.
Create a .net class which will encapsulate all access to the legacy code. Make it IDisposable.
Change all the global variables to reside in a class named 'Context'
Have all the C++ interfaces get the context object and pass it around as the first argument. This is probably the longest stage and you can avoid it using the "thread-local-storage" method suggested by someone else, but I would vote against that solution: if your library has any working threads which it runs, the "thread-local-storage" solution will break. Just add the context object where it is needed.
Use the context object to access all global data.
Have the context object created from .net ctor (by p/invoking a new create_context function) and deleted by the .net Dispose() method.
Enjoy.
Some thoughts on suggested solution #2 (and a bit on #1 and #3).
Some sort of IPC layer might introduce lagging. It depends on the actual engine how bad that is. If the engine is a rendering engine and it is called, say, 60 times a second the overhead might be too much. But, if not, a named pipe might be quick enough and easy to create using WCF.
Are you entirely sure you will need EXACTLY the same engine multiple times or are you in danger of changing requirements that might lead to a scenario that forces your toward loading multiple versions at the same time? If so, option #2 might be a better way than option #3 as it would allow this easier.
If the IPC layer is not slowing things down too much, this architecture might allow you to distribute the engines over other PC's. This might enable you to use more hardware than you previously planned for. You could even think about hosting the engine in the Azure cloud.

Resources