11-20-2013 07:33 PM
I am trying to access the attached .dll file in Labview for a project I'm working on for a behavioral econ class that involves anticipating what another player in poker is going to do. As part of this I want to evaluate the strength of different hands of cards with different numbers of other players in a texas holdem game. Since there are a number of poker hand evaluators available, I did some research and want use the PokerSim library because it has a DLL available unlike other evaluators.
I'm new to using DLLs in labview (I mostly integrated Labview with Matlab) and the psim.dll file does not have a .h file with it. So I'm trying to use the Call Library Node Function to call the SimulateHand and SimulateHandMulti functions as well as the SimResults structure but am not having any luck so far. For example, in the psim.hpp file it defines the SimulateHandMulti function as follows:
void SimulateHandMulti(const int* hand, SimResults* results, unsigned int boards = 2000, unsigned int hands = 500, unsigned int numOpponents = 9)
So if I want to use this function, I think I need to setup parameters for call library of an int32 for hand (although I'm unclear how to turn the poker hand into an int32), a uInt32 for boards, hands and numOpponents, and I don't know what I'm supposed to setup for the results parameter. These are my guesses based on what I've figured out from reading online and on the Labview forums.
I have no idea how to use the SimResults structure but I haven't looked into that as much yet so maybe I'm missing something easy.
Any help is appreciated!
11-20-2013 10:53 PM
You do have a .h file, it just has a .hpp extension. The psim.hpp file has all the information you need in order to configure Call Library Function Node. That said, you also need to understand a bit about C pointers and structures. You will need to make clusters in LabVIEW that are approximately equivalent to the PostFlopState and SimResults structures. The latter is easy since it's just floats and ints, which map directly to LabVIEW data types. PostFlopState will be more difficult due to the use of a bitfield; you'll need to count how many bits are used, put in a data type with the same number of bits (rounded to whole bytes) and then add padding if necessary. You cannot use a LabVIEW boolean type here.
Once you have the clusters set up, calling the functions should be fairly easy. Structs/clusters are always passed by pointer. It appears that you can pass a string for hand, so you can use a LabVIEW string configured to be passed as a C string and it should work.
I hope that will at least get you started. Sorry I don't have time to provide example code for you right now, but please follow up with more questions and attach your code and I'll see if I can help.
11-21-2013 11:01 AM
Hi Nathan,
First, thanks a TON for pointing out that the psim.hpp file could be used as a header file. I copied it and changed the extension to .h and then used the import dll tool in Labview and that wizard got me to the point of successfully wrapping 3 vis for the RankHand, SimulateHand and SimulateHandMulti functions, which is a ton of help. I'm attaching that library and vis zipped so you can check them out if you'd like. I'm able to successfully run all three, I think but even when I do my vis still produce a 1097 error and I'm not sure why since I'm getting outputs based on the inputs that seem correct, although I need to do more testing.
I understand what you said about the PostFlopState structure and needing to use a bitfield, but I'm unfamilar with how that works. How do I count the bits and then create a data type with that number of bits (or with some padding, as you suggest)? Any direction on that could get me to successfully configuring the other two functions that the wizard couldn't configure for GetHandState and GetHandStateBrief. It looks like once I get the PostFlopState cluster configured I pass that into a parameter configured just like the one for SimResults, which is set up as a Type: Adapt to Type and Data Format: Handles by Value. Is that correct?
Thanks again for your help, I'm seeing some daylight at the end of the tunnel and appreciate it!
11-21-2013 11:02 AM
Sorry, here's the zip file!
11-21-2013 12:48 PM
The 1097 error is likely due to using the wrong calling convention. In the psim.hpp file, note the definition:
#define EXPORT extern "C" __declspec(dllimport) __stdcall
The "stdcall" says to use the Windows stdcall convention, but you configured the Call Library Function Nodes to use the C calling convention.
"Adapt to Type" is the correct Type for passing a cluster. Clusters are always passed by reference (see the documentation) so the Data Format choice has no effect.
The PostFlopState contains 36 bits, if I've counted correctly: 24 single-bit values, and 3 4-bit values. So you'll need a cluster that contains at least 36 bits. I'd recommend doing this as 2 32-bit values. Then you need to break out the individual values, and figure out what order they're in (I don't know if the first boolean will be in the lowest or highest bit). The Number to Boolean Array function will probably be helpful.
11-22-2013 02:38 PM
Thanks for the addtional info. You were right that the Call Library Function needed to be configured for stdcall.
I'm still not really sure how to go after assembling the cluster for the PostFlopState. Specifically, I'm not sure how I break out the invidivual values and figure out what order they are in. I've been doing some reasearch online and the best info I could find was a post you created a few years ago:
http://forums.ni.com/t5/LabVIEW/Interface-dll-function-with-struct-in-LabVIEW/td-p/1490848/page/3
In that you provide a sample cluster that someone else was looking to use as a structure for a dll call. So could my cluster look something like that in labview just with a bunch of labview data types? I'm just not sure how I create the cluster to replicate the structure and I'm not finding good info for it online.
Or, instead of doing that I keep seeing people reference creating a "wrapper" function to change dll data types into labview-friendly data types. Could I do that for the PostFlopState structure?
Thanks again for your help, I've started working with the other functions and that is proving useful, so I appreciate your guidance on this!
11-22-2013 03:20 PM
Assembling the PostFlopState cluster is easy - just provide any cluster that's at least 40 bits (5 bytes). That could be 5 U8 elements, 2 I32 elements, or various other combinations. You can also pass it a pre-allocated array of at least 5 bytes if you prefer. The DLL doesn't care how LabVIEW represents the data, it just needs a pointer to the right amount of memory so it can fill in those values.
The trickier part is what to do with those values when you get them back. As I mentioned before, the Number to Boolean Array function will be helpful. Then you just need to figure out what order the bits are in. They'll either be in the order listed in the header file, or reversed from that. If you use a cluster of 32-bit elements, LabVIEW will byte and word swap to get the correct endianness which will throw off the ordering, so you might be better off with a cluster of U8. If you try a cluster of 5 U8 and you only get data in the first 4 elements, make it an 8-element cluster and check the other elements. Sorry, I just don't know how the compiler handles the bitfield; maybe RolfK will chime in here to provide a detailed answer.
I suspect you can figure out the correct bit order with a little bit of trial and error, since if you get it wrong the results won't make sense.
11-22-2013 03:23 PM
OK, that makes sense. I'll give that a try and see if I can figure it out. From what you said it sounds like interpreting the output will be the harder part. I'll let you know if I get hung up. Thanks!