Tom L.
Tom L.

Reputation: 994

Win32 DLL / Reference storing

I've been given the task to create a DLL with a lot of functions. The specific implementation of the functions is actually quite easy but the general (or better: initial) setup gives me a headache and I wasn't able to make sense of it yet. So here are two (of the many) functions I am supposed to implement:

long initClient(long* client, char* a = "", char* b = "");
long clientSet(int client, const char* a, const char* b);

The first function will setup a client (there can be 0..n, each client has internal state data), so somehow it will need to keep track of the client related data internally. Now whenever I call clientSet (the second function) I need to pass the integer value (long* client) I get from initClient to the function so it can identify the correct client data structure and change that very data.

The actual question now is: How do I do this correctly?

My current solution would be to hold an internal list of clients with their associated data/ID and use malloc/free whenever a client is added or removed. Yet, I have the feeling that this is not a clean solution or that it could be solved in a better way.

Your help is highly appreciated.

EDIT: After re-thinking it, could it be that the first parameter of clientSet is actually the pointer I get from initClient (first parameter)? If this was the case, initClient would only need to malloc some memory and fill that with data. All other calls would then only reference that memory area. Yet, I find it highly troublesome to use different data types for the same pointer (I get a pointer to a long which I then need to interpret as int - i understand that both of them are 4 byte on Win32). Am I right here?

EDIT #2: Unfortunately I am not allowed to change the interface in any way.

EDIT #3: After more thinking about this problem, maybe this is what I am actually after:

intptr_t my_ptr;

long initClient(intptr_t* client, char* a, char* b);
long clientSet(intptr_t client, char* a, char* b);

initClient(&my_ptr, "A", "B") would basically (I will need to see how to do the de-referencing correctly) do a

*client = (intptr_t)malloc(sizeof(myDataStructure));

Now I could call

clientSet(my_ptr, "X", "Y");

Does this look like it could be what I am supposed to do?

Upvotes: 1

Views: 64

Answers (2)

Tom L.
Tom L.

Reputation: 994

After careful consideration (and some discussions), we decided to go the following way:

  • initClient creates a malloc'ed memory area and returns the pointer to that instance (which is then used as an int which might be a problem in the future but that is currently in discussion)
  • All functions work on that malloc'ed area
  • an additional endClient function was added which free's the reserved memory space.

Apparently the real issue here is using an int as storage for a pointer.

Upvotes: 0

AnatolyS
AnatolyS

Reputation: 4319

You need export C functions, but you can implement them with C++. In that case you can use all needed containers and data types (std::map, std::string) to keep data for each client. As you can see there is no any malloc:

struct client {
  std::string a;
  std::string b;
};

std::map<long, client> clients;

extern "C" {
  long initClient(long* clientid, char* a = "", char* b = "") {
    // if you need generate clientid you can use static atomic long
    static std::atomic_long id(0);
    clients[*clientid = ++id] = client{ a, b };
    return *clientid;
  }
  long clientSet(int clientid, const char* a, const char* b) {
    clients[clientid] = client{ a, b };
    return clientid;
  }
}

Upvotes: 2

Related Questions