Multiple c++ ops in the same DLL ?

Hi,

That’s probably more of a feature request now that I think about it.

In my never-ending quest to test how extensible touch is, let’s say I’d like to create a plugin that has both a TOP for visual feedback and a CHOP for outputting channels.

If they are in the same dll, both could access a static pointer to a class. If they’re not in the same dll I’m not sure how to share memory between the two ops.

This is somewhat what I did when I was playing with Maya and Houdini SDK for the cuda stuff (vimeo.com/25279899)

Found this stackoverflow.com/questions/4616 … en-modules, so maybe I would need to do another dll and have both c++ ops access it if that’s possible.

(I’m mostly still hacking my way around c++).

Not expecting many answers but maybe someone else attempted it or someone from derivative wants to comment :wink:

Thanks a lot!

Vincent

TOP and CHOP in the same Operator…mind explodes

You could also pass the pointer to your class out using an Info DAT and back in using the ‘Strings’ parameter, convert it back to a pointer value in the other .dll.

Sharing a common .dll is probably a clearner way to do it though, especially if you are talking about static data.

Passing the address around through the info DAT works, great!
That was easier than I thought and shows I should revise my basics. Makes sense though.

Thanks a lot Malcolm.

With further testing passing the pointer address around doesn’t seem really reliable.
Seems like it’s working only with the debug versions, and even then it depends on the order in which I load the different dlls. Also turning on or off debugging from visual studio seems to affect the behavior.

My current test case was trying to chain multiple chops to keep the nodal approach but only convert my data structure back to channels for instancing with the last one. (idea was to do a particle systems in chops).

Maybe I’ll try the additional dll approach, or maybe I’ll just wait for POPs in Touch :wink: and do monolithic chops for now.

Ya, the order the DLLs load will matter since you may have an incorrect pointer. However if you have a dependency on the Info DAT coming from one of the C++ nodes, that should make it cook before the user of the pointer gets the value.

Mmm I’ll dig further but since I was using chops I was doing something a bit different, just using a 1 sample channel containing the pointer address as an int. And when it’s not working I have to restart touch.

Since it’s only one process I guess the dlls should share the same address space? When debugging sometimes casting an int address back to a pointer to something I know exist still returns garbage.

A CHOP can’t accurately represent a pointer address since it’s a 32-bit float, and you need a 64-bit int to properly represent a pointer (in 64-bit TD). Even a 64-bit double isn’t enough since part of the data is for the exponent. You need to convert it to a string and back.
Yes the address space is the same since they are .dlls in the same process.

Thanks for the info. Could you expand a bit?

After a bit of googling I was doing this :

currSys = new ParticleSystem(); //pointer creation

static char tempBuffer[8];
sprintf(tempBuffer, “%p”, currSys); //convert to string

int p = (int)strtol(tempBuffer, NULL, 16); //convert to int

currSys = (ParticleSystem*)(p); //convert back to pointer in another chop

So is this line int p = (int)strtol(tempBuffer, NULL, 16); //convert to int
wrong anyway?

Thanks a lot Malcolm

After more googling, doing

sscanf (p, “%p”, &currSys);

to convert back to pointer seems to work, even when compiling release.

Now I just have to understand why touch crashes when unloading one of the dll in release but not debug!

There is a few hurdles here actually. The first part of your code is almost correct, however you only have 8 spots in your character string, you need 9 for the 8 possible hex values and a null character.
After that the issue is that strtol returns ‘long int’, which in MSVC is still just a 4-byte int (so, an int). You want 8-byte (64-bit) values here. Even if it did return a 64-bit integer you are casting it to an int anyways, so you are losing half your pointer’s address. You want to use _strtoui64() instead, which will give you an unsigned __int64, which can then be cast to a pointer.

Now just make sure you are sending this out via a string and not a CHOP channel, and you should be good.

If it’s crashing after unloading, then it’s likely using a pointer address that the unloaded .dll is deleting. You need to somehow let the other .dll know to stop using that address (by sending 0 to it for example).

Thanks for the detailed info, but it looks like

sprintf(tempBuffer, “%p”, currSys);
sscanf (p, “%p”, &currSys);

and bypassing the int conversion is fine. I think I put tempBuffer[8]; after doing a sizeof() but you’re probably right.
I’m investigating the crash.

Yup the sscanf is fine too (I finished my reply before you posted that other solution). You are correct the sizeof() a pointer will be 8, but you still need 1 character for the null character to terminate the string. sprintf() doesn’t know tempBuffer is only 8 bytes, so it’ll write past the end of your buffer and corrupt your stack potentially. sprintf_s() is a safer way of doing this, but it’ll just fail (without corruption) if it requires 9 bytes to properly output the string.

Well, the tempBuffer[8] was causing the unloading crash! Just doing tempBuffer[9] fixed it.

Just reading your new reply, so that explains it! Thanks again Malcolm.

I`m also just faced the problem,
sharing pointer to string and string to pointer functions if someone will come across the same problem.

std::string pointerToString(const void* Xi_pPointer)
{
std::stringstream ss;
ss << Xi_pPointer;
return ss.str();
}

uint64_t stringToPointer(const std::string& Xi_pointerString)
{
uint64_t pointerNumber = 0;
std::stringstream ss;
ss << std::hex << Xi_pointerString;
ss >> pointerNumber;
return pointerNumber;
}