Coding the Wheel

How I Built a Working Online Poker Bot, Part 4: The Poker Botting Erector Set

Friday, June 27, 2008

Introduction

Today we're going to build a simple online poker bot—the simplest possible online poker bot—in just a few hundred lines of code.

But first: have you ever tinkered around with an erector set?

You remember. Colorful cardboard boxes with see-through fronts. Girders and gears, nuts and bolts, even the occasional electric motor.

A classic brand with over 90 years of building experience, Erector introduces an incredible 50-Model building set. It has a whopping 605 pieces for building 50 different models, including a helicopter, a construction truck with crane, a scooter and more. A powerful 6V motor brings life to your creations, and special mechanical functions create unique and exciting movements.

Set includes an assortment of construction materials and fasteners, plus detailed, step-by-step instructions with photographs -- no reading required. Requires 3 "AA" batteries, not included.

The thing that always appealed to me about Erector Sets? Ingredients. Dozens of components, each with a specific, and yet generic, purpose. Not to mention the recipes: instructions for assembling those components. With a little time and some careful screwdriver work, you could build just about anything. 

Charles Babbage's Difference Engine #2, Built by Tim Robinson

Charles Babbage, eat your heart out.

But what do erector sets have to do with poker, programming, and poker botting?

Well, a lot of people have written me or left comments to the effect of: show us the code, buddy. And for the past couple weeks I've struggled with how to do that.

  • First, there's a lot of code. We're talking a sizeable production code base, with various versions and branches, and a lot of half-finished one-off tools. Utility libraries, hand evaluators, history analyzers, DLL injectors, you name it.
  • Second, I don't have complete control over said code. Before too long, I'll introduce my poker buddy, botting partner, former client, and general co-conspirator, Mr. Anonymous. He has a stake in all this, too.
  • Third, the code is quite valuable on its face. Not because I'm such a superb programmer, or poker player—I've made more than my share of mistakes in both arenas—but because it's had the benefit of thousands of hours of work.

And as we start to publicize it, that value, that potential energy, depreciates.

So what to do?

Sell it? Open-source it? Discuss it?

And that's when a friend sent me a link to the above picture and I thought: aha!

Erector sets.

Self-Contained Experimental Botting Goodness

Programmers, like poker players, have a behavioral profile. They prefer a certain language, a certain methodology, a certain environment. My favorite languages are C# and C++. Yours might be Java and PHP.

When it comes to botting (or software automation in general) we're all hoping to take something different away from the table. Some come to learn. Some want to make money. Some have a product they'd like to build, or a built product they'd like to automate. Some are interested in poker, others spend their time on World of Warcraft, and still others invest their energy in the stock market. Some want specific code they can download, build, and use. Others just want the techniques.

So rather than posting isolated code samples without any context, and rather than posting a hundred thousand source lines of code without any focus, we'll take the middle ground: the software erector set. That's a self-contained package of ingredients—source code, tools, information—together with instructions for turning those ingredients into something real and, as we progress further into the series, something useful.

That means various flavors of bots:

  • FoldBots
  • TrashBots
  • Autofolders
  • ShortBots
  • DeepBots
  • General (non-poker) software automation tools

Various poker-related tools:

  • Simulators
  • Hand Evaluators
  • History Analyzers
  • Poker Calculators

And some other stuff as well.

Obviously this is a little much to handle in a single series—you'd end up with 400 articles, and I'd have to start saying things like: "In Part 267, I pointed out, for the fifty-sixth time, that DLL Injection isn't the only way to build a bot."

The poker botting series will continue indefinitely. But software automation and human emulation, poker-related and otherwise, will now be a primary content line on Coding the Wheel.

After all, that's kind of what the name means.

Or did you think I just woke up one day and decided to start blogging about poker bots?

The Simplest of All Possible Bots: Introducing the FoldBot

The first code sample/erector set I'd like to present is what happens when you start to apply iterative, incremental development to online poker botting. Before we tackle generic poker A.I., let's see if we can get a proof of concept up and running. Let's see if we can create a bot which:

  • Reads our hole cards
  • Clicks a button (it doesn't matter which)

This is what you might call the Ground Zero of software automation. It's where everything begins: software with the ability to see and touch. (And when I say "see" I don't mean image recognition, or at least, I don't mean image recognition exclusively. For a poker bot, "seeing" might be the ability to extract text from a window by snooping on window memory, sending a WM_GETTEXT, etc. But the end result is the same.)

Here's a picture of the FoldBot in action: 

Simple. The FoldBot is the simplest of all possible online poker bots. It doesn't understand, want to understand, or need to understand, poker. It doesn't understand online poker. It doesn't even know how to recognize a poker hand. It only knows how to do three things:

  • INPUT: Extract your hole cards and other table information from one or more online poker tables.
  • PROCESSING: Decide to fold every hand (yes, even pocket Aces).
  • OUTPUT: Click the Fold button when it's your turn to act.

That's the simplest possible Input stage, the simplest possible Processing stage, and the simplest possible Output stage.

And yet, with some additional work, the FoldBot can become a TrashBot (a bot intended to fold garbage hands) which in turn becomes an Autofolder (a bot intended to automate preflop play) which in turn becomes a ShortBot, which in turn becomes a DeepBot capable of playing deep-stacked poker on all rounds of betting, and so forth. We'll explore all of these at some point, and we'll follow the long-established practice of giving short, often cute or cryptic, names to our bots.

Which Online Poker Venues Does It Support?

The FoldBot is specialized for the PokerTime online poker venue (http://www.pokertime.com) so you'll need to download the (free) software and set up a (play-money) account in order to see it in action.

Why are we using PokerTime, instead of a more popular venue like PokerStars or Full Tilt?

Because it makes our Input stage very simple.

But don't worry: we'll add support for Poker Stars, Full Tilt, and other major poker venues, shortlyin case they should feel left out of the botting extravaganza. Extracting text from Poker Stars is slightly more difficult than PokerTime, but only slightly. Botting rules apply here:

Botting Rule #68: It's virtually impossible for a program to display human-readable text on the screen without exposing that text to other programs running on the machine. You might as well not even try.

This is especially the case when the text has to be easy to read, as it does in online poker, where 4x and 8x multi-tabling is commonplace. But even if we allow the text to be difficult to read, well, we're fast approaching the time where if a human can read it, software can too. As Jeff Atwood points out in CAPTCHA Is Dead, Long Live CAPTCHA!, even CAPTCHAs which were once thought to be unbreakable—Google, Yahoo, Hotmail—have since been broken.

2008 is shaping up to be a very bad year indeed for CAPTCHAs:

Which means I am now 0 for 3. Understand that I am no fan of CAPTCHA. I view them as a necessary and important evil, one of precious few things separating average internet users from a torrential deluge of email, comment, and forum spam.

In fact, I believe the text-only CAPTCHA is doomed to failure, as a long-term mechanism for separating the humans from the bots.

But I digress. On to the code.

About the Code

Download the FoldBot Source Code (C++/Windows 145KB).

The FoldBot code consists of two small projects, both implemented in C++.

The purpose of each project is straightforward:

  • XPokerBot.MfcView is the (simple and minimalistic) GUI. This is a standard Windows executable (.EXE).
  • XPokerBot.Hook is the payload containing the meat of the bot's "intelligence". This is a standard Windows dynamic-link library (.DLL).

In order to build them, you'll need:

  • Microsoft Visual Studio 2003, 2005, or 2008. VS2005 and VS2008 are both available as fully-functional, 90-day trial editions.
  • The C++ Boost libraries (for regular expression support).

This version of the bot has only been tested on Windows XP, so if you're running Vista or Windows 2000, you might have to do a little tweaking.

But far and away the most difficult part of building the source code is dealing with the Boost libraries. For step-by-step instructions, check out Boost: Getting Started on Windows. If you run into specific problems, you can try posting to the Boost Configuration forums on Nabble. And if all else fails, why, you can simply comment out the Boost code. It's only used in a couple places, for regular expression support. Rewriting that code to use plain vanilla string manipulation should be straightforward.

How It Works

The FoldBot, while simple, makes use of some interesting techniques:

  • Windows Hooks
  • DLL Injection
  • Window Subclassing
  • Rich Text Interception
  • Interprocess Communication (IPC)
  • Regular Expressions
  • Input Simulation

Here's what it does in a nutshell:

  1. Inject the botting DLL into the poker client's address space.
  2. Respond to (poker table) window create notifications via the CBT hook.
  3. Subclass the poker table's (RichEdit control) chat window.
  4. Intercept chat window text by listening for and parsing EM_STREAMIN messages.
  5. Parse the text using simple regular expressions.
  6. Simulate input (clicking the Fold button) at the right time, based on those messages.
  7. Transmit hole card and table information to the poker bot GUI via simple IPC.

Not too bad. No rocket science here. Now let's look at the individual steps.

Step 1: Inject the DLL

The first thing the bot does is inject a DLL (XPokerBot.Hook.dll) into the poker client process, using the same CBT Hook injection technique I mentioned in Part 1:

bool XPOKERBOTHOOK_API InstallHook()
{
    g_hHook = SetWindowsHookEx(WH_CBT, (HOOKPROC) CBTProc, g_hInstance, 0);

    return g_hHook != NULL;
}

That causes the DLL to be mapped into the address space of every process on the machine, including the poker client. Normally we might be concerned about overhead, but this DLL is fairly small. More to the point, it's almost completely inert when instantiated in an irrelevant (non-poker) process. As we start adding functionality to the DLL and it grows larger, we can switch to the two-stage injection approach:

But for now it's not necessary.

Step 2: Detect the opening and closing of poker windows

Another benefit of the CBT Hook approach is that it gives us a handy way to detect the opening and closing of poker table windows, and any other top-level windows of interest:

LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    if (nCode < 0)
        return CallNextHookEx(g_hHook, nCode, wParam, lParam);
    else if (!g_pClient)
        return 0;

    // Window was activated. We currently use this to detect window creation also.
    // Why not use HCBT_CREATE? Because often the window doesn't yet have a caption
    // when HCBT_CREATE is called, and our sample window-detection logic looks
    // at the window caption to determine the type.
    HWND hWnd = (HWND)wParam;
    if (!hWnd)
        return 0;

    if (nCode == HCBT_ACTIVATE)
    {
        if (!g_pClient->IsRegisteredWindow(hWnd))
            g_pClient->TryRegisterWindow(hWnd, NULL);
    }
    else if (nCode == HCBT_DESTROYWND)
    {
        if (g_pClient->IsRegisteredWindow(hWnd))
            g_pClient->UnregisterWindow(hWnd);
    }

    // Return 0 to allow window creation/destruction/activation to proceed as normal.
    return 0;
}

Here we can guess that that the HCBT_ACTIVATE message is sent when a given top-level window is activated, and that the HCBT_DESTROYWND message is sent when a given top-level window is closed. And we have some simple code to store or remove the window to or from the list of "managed" windows in each case.

The only thing to note here is that we can't really use HCBT_CREATEWND notification when we're answering the "is this a poker table window?" question by examining the window caption. That's because the window caption is usually empty at the time the HCBT_CREATEWND notification is sent. There are ways around this such as delayed creation but we don't need to go to such lengths, certainly not for this incarnation of the bot.

Step 3: Subclass the Chat Window

Now that we're able to detect when poker table windows are opened and closed, we need to extract text from the table chat window. The technique I'm describing here will only work on certain windows, such as the Windows rich edit control, so it may or may not be appropriate for a particular poker client or other gaming application.

Basically we want to subclass the chat window, listen for the EM_STREAMIN message, and replace the callback function provided by the poker client with one of our own. In this sample, I'm subclassing the window when it's first recruited into the poker botting runtime, but strictly speaking, the subclass doesn't have to be installed until the user/bot actually sits down, or even until the user issues a command saying, "okay, automate this table for me."

For each newly-created poker table window, the OnlinePokerClient::TryRegisterWindow method creates a corresponding OnlineTableWindow-derived object—in this case, a PokerTimeTableWindow object. During the construction of that object, we subclass the table's chat window, allowing us to intercept messages sent (by the PokerTime application) to this window:

PokerTimeTableWindow::PokerTimeTableWindow(HWND hWnd, PokerTimePokerClient* client) :
    OnlineTableWindow(hWnd, client)
{
    // Find the chat box...
    HWND hwndChat = ::FindWindowEx(hWnd, NULL, _T("RichEdit20W"), NULL);
    if (hwndChat)
    {
        // And subclass it!
        PokerTimeTableWindow::OldRichWndProc = (WNDPROC)::GetWindowLongPtr(hwndChat, GWL_WNDPROC);
        ::SetWindowLongPtr(hwndChat, GWL_WNDPROC, (LONG_PTR)PokerTimeTableWindow::MyRichWndProc);
    }
}

Step 4: Intercept chat window text

Technically speaking, the chat text window (on PokerTime) is a Rich Edit control. In order to fill this window with text, the Poker Time client sends it a standard EM_STREAMIN message, which our code intercepts:

LRESULT PokerTimeTableWindow::MyRichWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    EDITSTREAM* es = (EDITSTREAM*) lParam;

    if (msg == EM_STREAMIN)
    {
        // Store the original EDITSTREAMCALLBACK and replace it with our own..
        PokerTimeTableWindow::OldRichEditCB = es->pfnCallback;
        es->pfnCallback = PokerTimeTableWindow::MyEditStreamCallback;
        // Hack - keep track of current window
        PokerTimeTableWindow::CurrentChatWindow = hWnd;
    }

    // Call the original window procedure, with our new EDITSTREAMCALLBACK in place
    LRESULT lRet = ::CallWindowProc(PokerTimeTableWindow::OldRichWndProc, hWnd, msg, wParam, lParam);

    if (msg == EM_STREAMIN)
    {
        // Restore the original EDITSTREAMCALLBACK function
        es->pfnCallback = PokerTimeTableWindow::OldRichEditCB;
    }

    return lRet;
}

If you've ever worked with EM_STREAMIN before, you know that you have to provide it with a callback function—specifically, an EDITSTREAMCALLBACK function. That's just what the PokerTime client is doing. What we want to do is somehow replace that callback function (which we'll call A) with our own (which we'll call B). We want Windows to call our callback (B), which will in turn call the PokerTime callback (A) to retrieve the text. That's the purpose of these two lines of code:

// Store the original EDITSTREAMCALLBACK and replace it with our own..
PokerTimeTableWindow::OldRichEditCB = es->pfnCallback;
es->pfnCallback = PokerTimeTableWindow::MyEditStreamCallback;

We're actually overwriting the EDITSTREAMCALLBACK member of the EDITSTREAM structure passed in by the client. So as far as Windows is concerned, it's processing a perfectly normal EM_STREAMIN message. And as far as the PokerTime client is concerned, it's sending a perfectly normal EM_STREAMIN message which it expects to be handled by Windows.

Step 5: Parse the Chat Text

In the meantime, we get a chance to parse the text generated by the poker client using a couple simple regular expressions:

DWORD CALLBACK PokerTimeTableWindow::MyEditStreamCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG numberOfBytes, LONG* actualBytes)
{
    // Call the original (PokerTime-provided) callback to get the text..
    DWORD dwRet = PokerTimeTableWindow::OldRichEditCB(dwCookie, pbBuff, numberOfBytes, actualBytes);
    if (0 == dwRet && actualBytes && *actualBytes > 0)
    {
        // 
        // do some busy work...
        // 

        // We're looking for the line (in the PokerTime text window) that looks like this:
        //> Dealing Hole Cards(8d Kc )
        boost::smatch what;
        if( boost::regex_match(line, what, regHoleCards, boost::match_default|boost::match_single_line) && what.size() == 3)
        {
            string sCard1 = what[1];
            string sCard2 = what[2];

            ApplicationProxy::TransmitHoleCards((sCard1 + sCard2).c_str(), hPokerTable);
        }
        //> JohnDoe, you have 10 seconds to respond
        //> JohnDoe, you have 5 seconds to respond
        else if (boost::regex_match(line, what, regWakeUp, boost::match_default|boost::match_single_line) && what.size() == 3)
        {
            string theActor = what[1];
            if (theActor == g_pClient->LoggedInAs)
                OnlinePokerExecutor::PerformAction(hPokerTable);
        }

Specifically, we're looking for two pieces of text:

  • "Dealing Hole Cards(Ah Ad)"
  • "JohnDoe, you have 10 seconds to respond"

The equivalent regular expressions, stripped of the redundant C++ backslash escapes (really makes you long for the world of verbatim @ strings such as we enjoy in C#, doesn't it?), look like this:

  • ^\s*>\s*Dealing\ Hole\ Cards(?:\((.{2,3})\ (.{2,3})\ \))?\s*$
  • ^\s*>\s*(.*),\ you\ have\ (\d+)\ seconds\ to\ respond\s*$

There are better regular expressions out there, but these are just an example. Ultimately we'll want to create a generic regular expression engine which is powerful enough to analyze text from multiple poker venues, using named capture groups. But that's a topic for another post.

Step 6: Simulate User Input

The "JohnDoe, you have 10 seconds to respond" message is our v1.0 method of detecting when it's our turn to act. We're obviously going to have to improve on that before we turn the bot loose, but for now, it's an easy way to queue the logic to click the Fold button. Once we know it's our turn to act, we leverage our bot's impressive A.I...

Fold all hands without exception.

...and invoke our not-too-imaginatively named OnlinePokerExecutor object to perform the actual click of the Fold button.

//> JohnDoe, you have 10 seconds to respond
//> JohnDoe, you have 5 seconds to respond
else if (boost::regex_match(line, what, regWakeUp, boost::match_default|boost::match_single_line) && what.size() == 3)
{
    string theActor = what[1];
    if (theActor == g_pClient->LoggedInAs)
        OnlinePokerExecutor::PerformAction(hPokerTable);
}

The implementation of that, unfortunately, is a little messy. No matter; we can abstract the details of input simulation away into an easy-to-use class. For now, here's a hard-coded, somewhat kludgy attempt:

void OnlinePokerExecutor::PerformAction(HWND hPokerTable)
{
    // Coordinates of our click spot (relative to poker table client area)
    POINT ptCoords;
    ptCoords.x = 290;
    ptCoords.y = 513;
    //ptCoords.x = 450;
    //ptCoords.y = 354;

    // Convert client coords to screen
    ::ClientToScreen(hPokerTable, &ptCoords);

    // Get the screen resolution
    HDC hdc = ::GetDC(NULL);
    int screenWidth = ::GetDeviceCaps(hdc, HORZRES);
    int screenHeight= ::GetDeviceCaps(hdc, VERTRES);
    ::ReleaseDC(NULL, hdc);

    // Convert our screen coordinates to world coordinates
    double temp1 = 65535 * ptCoords.x;
    double dX = temp1 / screenWidth;
    temp1 = 65535 * ptCoords.y;
    double dY = temp1 / screenHeight;

    // Now lets create our mouse inputs..
    INPUT input[4];
    MOUSEINPUT mouseInput;

    // Move the mouse to the button...
    input[0].type=INPUT_MOUSE;
    mouseInput.dx = (int)dX;
    mouseInput.dy = (int)dY;
    mouseInput.mouseData = NULL;
    mouseInput.dwFlags = MOUSEEVENTF_MOVE|MOUSEEVENTF_ABSOLUTE;
    mouseInput.time = 0;
    mouseInput.dwExtraInfo = 1001;
    input[0].mi = mouseInput;

    // Left-click the mouse down
    input[1].type=INPUT_MOUSE;
    mouseInput.dx = (int)dX;
    mouseInput.dy = (int)dY;
    mouseInput.mouseData = NULL;
    mouseInput.dwFlags = MOUSEEVENTF_LEFTDOWN|MOUSEEVENTF_ABSOLUTE;
    mouseInput.time = 0;
    mouseInput.dwExtraInfo = 1001;
    input[1].mi = mouseInput;

    // ..and release it
    input[2].type=INPUT_MOUSE;
    mouseInput.dx = (int)dX;
    mouseInput.dy = (int)dY;
    mouseInput.mouseData = NULL;
    mouseInput.dwFlags = MOUSEEVENTF_LEFTUP|MOUSEEVENTF_ABSOLUTE;
    mouseInput.time = 0;
    mouseInput.dwExtraInfo = 1001;
    input[2].mi = mouseInput;

    // Move the mouse to where it was before
    input[3].type=INPUT_MOUSE;
    mouseInput.dx = (int)dX;
    mouseInput.dy = (int)dY;
    mouseInput.mouseData = NULL;
    mouseInput.dwFlags = MOUSEEVENTF_MOVE|MOUSEEVENTF_ABSOLUTE;
    mouseInput.time = 0;
    mouseInput.dwExtraInfo = 1001;
    //input[3].mi = mouseInput;

    int numberOfInputs = 3;

    // Remember which window has the focus, so we can restore it to that window.
    GUITHREADINFO info;
    ::ZeroMemory(&info, sizeof(info));
    info.cbSize = sizeof(info);
    ::GetGUIThreadInfo(NULL, &info);

    // Also get the current mouse position, so we can restore that.
    POINT ptCursor;
    if (::GetCursorPos(&ptCursor))
    {
        numberOfInputs++;

        temp1 = 65535 * ptCursor.x;
        mouseInput.dx = (int)(temp1 / screenWidth);
        temp1 = 65535 * ptCursor.y;
        mouseInput.dy = (int)(temp1 / screenHeight);
        input[3].mi = mouseInput;
    }

    // Make sure this window isn't obscured behind some other window
    ::BringWindowToTop(hPokerTable);

    // Now actually send the mouse input
    ::SendInput(numberOfInputs, input, sizeof(INPUT));

    // Reset the focus to the previous window
    if (info.hwndFocus)
        ::SetFocus(info.hwndFocus);
}

Another problem with the above input simulation is that the mouse coordinates (button locations) are hard-coded. This is really the type of data you want to "file and forget" in an external XML or other settings file—which is just what we'll do, in future versions of the bot. We'll also want to add random (or normal distribution) input timing along with a few other features. And of course, SendInput is just one way of several ways to simulate user input.

Step 7: Update the GUI

The last piece is to somehow get this data (our hole cards and open tables) to display in the bot's UI. The problem is that the bot user interface lives in one process, and our hook DLL lives in another. So whatever we do is going to involve some sort of inter-process communication or IPC. (Note, however, that you can create a full botting GUI, living entirely in the poker client's process, without a separate .EXE at all.)

For now, let's throw some "poor man's IPC" at the problem by manhandling the data into a WM_COPYDATA message. We'll look at cleaner and more robust approaches as needed.

void ApplicationProxy::TransmitHoleCards(LPCSTR cards, HWND hPokerTable)
{
    HWND hWnd = ::FindWindow(NULL, _T("FoldBot v1.0a"));
    if (hWnd)
    {
        COPYDATASTRUCT cds;
        ::ZeroMemory(&cds, sizeof(COPYDATASTRUCT));
        cds.dwData = (DWORD)hPokerTable;
        cds.lpData = (PVOID)cards;
        cds.cbData = strlen(cards) + 1;
        ::SendMessage(hWnd, WM_COPYDATA, (WPARAM)hPokerTable, (LPARAM)&cds);
    }
}

Meanwhile, the code sitting on the other side of that message can implement a WM_COPYDATA handler, extract the data, and display it appropriately.

Revisiting the Choice of Language

In Part One of this series, I suggested that the ideal language for bot-building was C++. A lot of people took that as a sort of language elitism. So I'd would now like to qualify that statement.

Build the bot in whatever language you're most comfortable with. When it comes to DLL injection, API hooking, log file snooping, stealth, and other "close to the metal" techniques, you'll find these are easier in C and C++ than in other languages (the greatest weakness of C/C++ also happens to be its greatest strength). It saves you the considerable trouble of accomplishing these things through P/Invoke or Interop or other virtualization layers. But the bot's domain modelling and A.I. aspects can and should be built in whatever langage you prefer. It depends on your level of comfort with your current language, with C/C++, and with the Windows API.

I used C++ (and later, C#) exclusively in the creation of the bot. That's C++ for the close-to-the-metal components, and C# for domain modelling and A.I. So the code samples I publish, today and in the future, will more or less reflect that. If you'd rather see these techniques in another language: what are you waiting for? The code isn't going to walk out of the compiler and migrate itself.

Disclaimer

Like many programmers, I have an almost superhuman ability to produce ugly, buggy, downright evil code. While the "production" botting source code has had the benefit of constant use and refactoring, the same can't be said for all of the samples I'll be publishing. In order to highlight particular techniques without burying innocent bystanders under an avalanche of sloc, I've had to manhandle the source in various ways:

  • By removing error handling.
  • By collapsing objects or object hierarchies into global variables or removing them entirely.
  • By occasionally introducing classes, methods, etc., which we'll end up throwing away as we put together more powerful abstractions.
  • By relying on quick hacks and naive solutions when necessary to keep the code samples relevant.
  • By severing important dependencies.
  • By ignoring bugs when they're irrelevant to the topic at hand.

And so forth. So it should go without saying that the code is intended to illustrate practical techniques, rather than proper coding style.

Using the FoldBot

The instructions for use are bundled with the software, but here are the basic steps.

  1. Build the FoldBot.
  2. Download the PokerTime client. Create a play-money account.
  3. Launch the FoldBot.
  4. Launch the PokerTime client.
  5. Open one or more poker table windows.
  6. The table name(s) should appear in the Fold Bot GUI.
  7. Sit down at one or more tables and wait for a hand.
  8. Your hole cards should appear in the FoldBot GUI.
  9. When it's your turn to act, don't do anything. Wait.
  10. Continue waiting until the PokerTime client prompts you with the message "so-and-so, you have 10 seconds to respond".
  11. Your hand should now be folded.
  12. Leave the table(s).
  13. The table(s) should disappear from the FoldBot GUI.

The acid test for whether or not the FoldBot is actually working, is whether it displays PokerTime tables as you open them.

Look Ma! No Hands!

Even if you shut the FoldBot application (.EXE) down, it will continue folding your hands on any table which you opened up when the FoldBot was running. Any tables opened after you close the FoldBot GUI won't be folded.

This has to do with the fact that, although we "pin" the Hook DLL in the poker client's address space via a redundant call to LoadLibrary, the Windows CBT hook itself dies when the FoldBot GUI shuts down. So the Hook DLL is still mapped, but you no longer receive CBT notifications, which means new windows don't get subclassed. This behavior is pretty easy to change but it's good to see an EXE-less, GUI-less bot in practice.

Conclusion

Believe it or not, we covered a lot of ground today. Although this code isn't going to be too useful for established botters, except perhaps as a way to compare notes, it's illustrative. We'll take these techniques and add them to our arsenal for the next incarnation of the bot: the TrashBot, a.k.a., the first "useful" bot.

We'll also reintroduce Detours, with a twist. We'll talk about what poker has to do with the Fastest Gun in the West. And I might even tell you about how the Twelve of Spades changed my life, though I have a hard and fast rule to never, ever tell a bad beat story over the web. And at some point we'll have to take a stroll through the underbelly of poker, before too long. Unscrupulous business practices; routinely poor quality of service; and the fact that yes, sometimes your opponents really CAN see your hole cards.

Until then: thanks for reading, as always, and good luck to you in your poker and programming struggles.

Tags: DLL Injection, poker bot, Windows API, Win32 Hooks, online poker, poker

234 comment(s)

Finally! I fired up google reader and saw your entry and I was so happy! Just in time for the weekend. I got a hold of Windows Via C/C++ and I'm gonna try to extend this before your next article for learning/hacking purposes. Thanks man.

James- Just ran it over here. Haven't spent too much time with it but looks good. I for one would like to see some C# as well... any of that in the pipeline?

How whould you read the hole cards, in case the client doesnt display them in the chat.

Thanks for the continuation of this most interesting series! I know people told you before, you do have a clear writing style even when you're writing about code.

Excellent series of articles. I have been following your analysis since the first article and I am looking forward for the next ones. I became nostalgic of my student days and the late night talks with friends after reading 'Bringing Down the House' ;)

Thanks for another well-written and captivating article. Hope to see them coming :)

One question: What do you think about VS 2008 Express Edition as the coding platform of choice? Is it functional enough?

Man!! you really rock!!!, dont show me the code, show me the money!!

Really good work, i am very glad to read your blog!

Eugenio from Argentina

A nice set of articles and easy to read. I'm not a C++ programmer, although i understand most code and regularly port C++ into my language of choice: VB6. I have developed several bots in VB6 and they've been quite successful. The evaluation code is probably slow by today's standards due to VB6's Rnd() function, however i'm happy with the ~80,000 Monte Carlo simulations per sec. 10,000 simulations has proven to be plenty fast enough to get an accurate result.

I'm now getting deeper into C++ as i hate the whole framework/managed code thing and ms have killed off VB6. My own bots used BitBlt() to take screen captures, however that was a kludgy fix and i'm now researching deeper methods, with the intention of hooking into the SSL packet decryption. Finding it hard work but it'll be worth it.

Keep up the good work, it's sites like this that inspire "hobby" coders like me...

As always excellent article. I look forward to seeing how you implement this for PokerStars. What I would like to do is create the DLL in C++ and do all of my logic and interface in C#. Can't wait for the next article!

great article!!! Finally some code

Thanks for interesting read and for showing what can be done to noobs in programming world like me. I like to learn through "live" examples and this one is perfect. Thanks!

Dude! PokerBots so totally ROCK! www.FireMe.To/udi

I have to say "You Rock!!". Thank you for sharing your hard earned knowledge. You are bringing together a considerable amount of valuable and difficult to find information. This Blog has the potential of becoming a cornerstone for extending existing applications of all kinds! I am now going to google "botting rule #68" to find the rest!

Please quit your day job and continue the series full time. I can't wait another couple weeks for part 5.

Great post James. I look forward to more!

Hi James. Another great post you have there but can I ask what client you're using in the FoldBot picture? I've never seen it before.

Thanks

^^^^^ If you actually READ the articles, he tells you!!

I can't help but wonder: Is it legal to use a bot to earn you money in online poker rooms?

And by legal i mean, legal in the sense that you will not get thrown to jail - not whether the poker room allows it or not. And of course laws can differ a great deal depending on where you are, but i'd be interested in hearing what you think is the case in europe and the US. I am personally from Denmark, but any european country where you have knowledge of the laws will be of interest. (I asked this on reddit as well, so sorry for being a bit spammy :))

Great articles. Thank you for taking the time writing these :)

So I built your FoldBot and it can detect holecars from the tables i join, but it doesn't seem to fold them. Do i need to setup the client in a specific way to make it work?

The hard part is programming a winning (or break even) poker bot... was that achieved ? That's the question ;) Still a great tutorial about advanced stuff. Thanks.

I'm an experienced developer (although in the very different world of web development), and I have to say this is a fantastic series. I can't wait to read more.

I enjoyed this article very much. I built it (you're right, the boost was the trickiest part, but not very) and it works well except the table names aren't erased from the list when I leave the table. Speaking of boost, vb.NET has a regular expression library. I haven't used C++ in a long (like 10 years) time and it's not as easy for me to follow as other languages. What are the disadvantages to writing it all in vb.NET? Also, I'm trying to follow it in the debugger and it doesn't work when I set breakpoints in the dll section. Any tips? Now I'm trying to add Stars to the equation. I figure I'll learn more trying to do it first and when you show how you do it, I can absorb it even more quickly. Thanks again.

"Give a man a fish and he'll eat for a day, teach a man to fish and you have fed him for a lifetime"

Perhaps instead of providing bulk code you should instead providing us with the logic behind developing that code. How you decided on what messages to intercept, how you figured out what you needed to do. That would be far more useful!

The regular expression only seems to match the Hold'em game table so the bot will only work with the Hold'em game. The other problem is when you leave a table it is not removed from the "open tables" list.

I do so love WM_COPYDATA.... ;) So if that's your "just do it approach" which IPC mechanisms do you actually use? Not that there's much difference for this purpose... even with many tables running that's a relatively small amount of data floating across process boundaries.

@ Casper, James pokerbots are not illegal, you'll not go to jail or will be prosecuted. But on every better known pokersite like Full Tilt,UB, Party,Stars, with opening an account you agree not to collude,cheat and use software thats blacklisted or gives you an advantage to other players (Pokertracker and other stat software are allowed because you have the information that other players have too). Botting is not allowed on these sites and if they catch you they will freeze your account with the money on it. That's ok if you're botting for sport or small amounts. Not much money to take. Besides colluding, thew sites put much of they resources in bot-searching. Party has sometimes a window to pt some numbers in it, they scan the memory and so on. Often people tell them suspicious players and they check the history. Conclusion: Not illegal by law but you're risking your bankroll. So don't try with an account with much money on it

After compiling in VS 2008 (if it helps any other readers. you can get a full copy if you have a .edu email) in Vista, when I run it and open a window, the window does not show in the list. I am assuming that this is due to the increased security in Vista that apparently disables DLL injections.

Fold bots are evil! However, it's amazing how some players can simply "sit out" to let their hand fold, and still OFTEN make it into the payout in play money sit & go tournaments. There are usually 2 or 3 players auto-sitting out at all of those tables, amassing play money for unknown reasons...

I enjoyed the article and forward to reading future parts of the series! Keep it up.

May I suggest you show HOW you find out what processes or objects you need to 'hook into' in Poker application to get the info you need. What tools, etc.? Thanks, it's a great series.

I hope you don't plan on including any .NET :( I like the old school way of doing things as it shows more actual how-to than all the shortcuts you can take within that massive framework; and I don't need to mention the footprint...

great article though. I've been toying around since the first article and I got to a stopping point with PStars so was hoping you could give a little insight. I used detours to grab all text being passed (with drawtext) and actually am seeing everything but I can't figure out which window it is being pointed to since all I get is a HDC. any help here? or some more detail on subclassing and figuring out WHAT messages are being passed in? as 1esproc said, more "how" you are figuring stuff out would be great. I don't think releasing functional bots is helping as much...

thanks

Someone ... Anyone...

I have Winspector and Detours Express but have not figured out how to grab dealer text messages from PStars. I would welcome any specific advice or example.

hello, james i really appreciate your good work and looking forward to new interesting topics.

F. Bueller: take a look at the Detours examples, especially at traceapi and simple. if you compiled the detours tidily, you will find a withdll.exe in the bin directory. this dll is injecting a giving dll into a proess and starts it (e.g. withdll.exe /d:traceapi.dll "C:\Program Files\PokerStars\PokerStars.exe"). traceapi will output the calls into a logging client(syelogd.exe). if you dont want to trace all api calls included in the traceapi dll, you can simplfy write your own using the source code of the traceapi.dll(especially in the _win32.cpp file). i copied some code which writes all TextOutW calls in C:\a.txt: [url=http://rafb.net/p/rMgHd916.html]click[/url]. compile this as a dll an run: withdll.exe /d:mydll.dll "C:\Program Files\PokerStars". i hope i could help you and if you have problems with compiling detours with vs2008, take a look at http://forums.msdn.microsoft.com/en-US/vcgeneral/thread/fcb5a809-5404-481f-82c0-40ffa6f58c9b/. greets

oh i'm sorry for the typing and grammar mistakes, but i can't edit my previous post. if anyone compile the code above, then please concern that withdll expects an export function. i declared the NullExport function, but it's important to add "/export:NullExport" into the Additional Options at the Linker Properties of your project.

thanks Anon!

I will give it a try.

Bueller

Great article. I am also trying to get started. Also downloaded Detour, but am having trouble running the initial "nmake" command.

Read the readme.txt which says "To build the libraries and the sample applications, type "nmake"." I assume this is from a command prompt (is that correct?) Open Command Prompt in Windows Accessories cd to Program Files\Microsoft Research\Detours Express 2.1type nmake (enter) and got "'rc' is not recognized as an internal or external command, program or batch file" NMAKE Fatal Error U1077 return code '0x1' and '0x2'

I admit to being weak in programming, but would like to at least be able to complete this simple step.

Bot Envy... when you're in the cmd window, you've got to run a file called vsvars32.bat to set your environment variables before you run nmake. That file is located in c:\program files\microsoft visual studio 8\common7\tools on my machine.

@Bot Envy I have not tried it yet, but found this at http://www.devsource.com/c/a/Using-VS/Working-at-the-Visual-Studio-Command-Line/

"You might think that accessing the command line is a simple matter of clicking the Start\Programs\Accessories\Command Prompt shortcut. That shortcut opens a command prompt, but it's not the right one. This command prompt lacks the required environment variables, especially the path information to Visual Studio.

Instead, open a development command line by clicking the \Start\Programs\Microsoft Visual Studio\Visual Studio Tools\2005 Visual Studio 2005 Command Prompt shortcut."

Hope that helps

Excellent series and really educational. I am reaaaaly looking forward to knowing exactly how you detect the whole cards of PT and FT. I am a professional programmer, but I know next to nothing about graphics and I have a hard time imaging how to do screen scraping in a timely manner.

Michael, you wrote "I used detours to grab all text being passed (with drawtext) and actually am seeing everything". What does seeing everything means? Does it include the whole cards which isn't written to the status window???

HI. In my computer, the FoldBot perfectly works with Windows vista, without making any change.

In fact, the most tricky part, is building the boost library, but any programmer can do it :)

Thanks for sharing all this stuff, but I have a question for you.

Do you think tha amount of BOTs will dramatically increase because of this blog?? What will be the result of this? I think the poker rooms will increase their security. Will it be possible to do all this stuff in the future?

Thanks for your work

Thank you to Pro Bot and EnviroMan. Following your advice, I was able to do the nmake properly, and now have withdll.exe, simple, traceapi, etc.

Will attempt to run some detours examples, including the one provided by Anonymous.

Interesting stuff.

Where can I download detours? MS-download-link seems to be broken. reg. popo

Detours is at http://research.microsoft.com/sn/detours/

Cool. We have evolved from just waiting for the next article to actually helping each other understand the tools and concepts better.

Thx James. I don't know the first thing about codes or programming, so for me this seems like a crazy hard task, but I am determined to build a fold bot, and keep up with the series. I would love to ask some questions, but I'm going to exhaust the research first. Peace and elbow grease.

The link to the mydll.dll code by Anonymous above has stopped working, but here is the excellent code that he provided as an example:

include <windows.h>

include <detours.h>

include <stdio.h>

BOOL (_stdcall * RealTextOutW)(HDC a0, int a1, int a2, LPCWSTR a3, int a4) = TextOutW;

BOOL _stdcall MineTextOutW(HDC a0, int a1, int a2, LPCWSTR a3, int a4) { FILE *file; file = fopen("C:\a.txt","a+"); fprintf(file, "TextOutW(%p,%p,%p,%ls,%p)\n", a0, a1, a2, a3, a4);

BOOL rv = 0;
__try {
    rv = Real_TextOutW(a0, a1, a2, a3, a4);
} __finally {
    fprintf(file, &quot;TextOutW(,,,,) -&gt; %p\n&quot;, rv);
};
fclose(file);
return rv;

}

VOID NullExport() { }

BOOL WINAPI DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID reserved) { if (dwReason == DLLPROCESSATTACH) { printf("simple.dll: Starting.\n"); DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); DetourAttach(&(PVOID&)RealTextOutW, MineTextOutW); DetourTransactionCommit(); } else if (dwReason == DLLPROCESSDETACH) { DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); DetourDetach(&(PVOID&)RealTextOutW, MineTextOutW); DetourTransactionCommit(); } return TRUE; }

Anonymous wrote: oh i'm sorry for the typing and grammar mistakes, but i can't edit my previous post. if anyone compile the code above, then please concern that withdll expects an export function. i declared the NullExport function, but it's important to add "/export:NullExport" into the Additional Options at the Linker Properties of your project.

Thank you for the clarification, but I have just started using VS (following James Devlin's suggestion) and am not sure where to add the "/export:NullExport". Is it in the code you supplied, near the

VOID NullExport() { }

or is it in the Mydll Property Pages, Configuration Properties, General, Output File?

Thank you for your patience.

almost

It is found in mydll Properties, Configuration Properties, Linker, General, Output File (type /export:NullExport here)

Don't give up.

1esproc said

""Give a man a fish and he'll eat for a day, teach a man to fish and you have fed him for a lifetime"

Perhaps instead of providing bulk code you should instead providing us with the logic behind developing that code. How you decided on what messages to intercept, how you figured out what you needed to do. That would be far more useful!"

i also would love to hear about how you know which ones to intercept. ive been working on a bot like this but sometimes figureing out which to intercept are hard. anyhelp on that would be appreicated.

Any commandline compiler for the foldbot out there? Currently not enough diskspace for VS ;-).

Anybody tried the foldbot on stars without issues/anoying e-mail-notifications?

Hope we stay on C++ not NET :-).

Thank you Bueller, the detours-download-link on MS ist ftp, therefore I had to prepair my browser.

Thanks for the effort James, it is being a really instructional trip for me :)

In the line of those requesting more information on how to collect information on how the poker clients work, I have tried to build a tool for BossMedia that maps keystrokes to mouse actions like folding and raising for faster interaction while multitabling and ran into some weird stuff. The sendInput command works because I have tried it in other clients, but on BossMedia it only moves the mouse but doesn't perfoms the MOUSEEVENTFLEFTDOWN and MOUSEEVENTFLEFTUP events.

Any guidelines on how to follow up in my research of whats happening?

Great!. Need the next article. I'm stopped now. I need catch text from textout or drawtext. The window only shows 'wmpaint' event. 'Wmpaint' is generated for everything, not useful for my program. I need another way.

I am trying to compile the dll example posted by Code Warrier above, but am getting the following errors during linking:

1>Linking... 1>detourcode.obj : error LNK2019: unresolved external symbol _DetourDetach@8 referenced in function _DllMain@12 1>detourcode.obj : error LNK2019: unresolved external symbol _DetourTransactionCommit@0 referenced in function _DllMain@12 1>detourcode.obj : error LNK2019: unresolved external symbol _DetourAttach@8 referenced in function _DllMain@12 1>detourcode.obj : error LNK2019: unresolved external symbol _DetourUpdateThread@4 referenced in function _DllMain@12 1>detourcode.obj : error LNK2019: unresolved external symbol _DetourTransactionBegin@0 referenced in function _DllMain@12 1>/export:NullExport : fatal error LNK1120: 5 unresolved externals

Would appreciate any advice on how to resolve these.

I just installed the Boost Regex library and added it to VS 2008, when I compile the solution I get some warnings about strcpy being unsafe and that I should use a strcpy_c, and also I get a warning about a command line option Wp64 being deprecated. Then at the end I get this:

Linking... LINK : C:\Users\kasra\Desktop\XPokerBot\XPokerBot\bin\XPokerBot.MfcView.exe not found or not built by the last incremental link; performing full link Embedding manifest... Microsoft (R) Windows (R) Resource Compiler Version 6.0.5724.0 Copyright (C) Microsoft Corporation. All rights reserved. Build log was saved at "file://c:\Users\kasra\Desktop\XPokerBot\XPokerBot\XPokerBot.MfcView\Debug\BuildLog.htm" XPokerBot.MfcView - 0 error(s), 4 warning(s) ========== Rebuild All: 2 succeeded, 0 failed, 0 skipped ==========

When I run the exe that this creates, and then run the PokerTime app and join a table, the table does not show up in the list at all and nothing happens.

I successfully build detours, now I am trying to compile the dll example posted by Code Warrier above too!

I physicaly copied the detours.h into my project-dir and added it to the header tree on the left side of the VS IDE.

In PHP it would include it as long as the include-file exists but I m not an include professional on VS...what ist wrong, any idea?

It says:

------ Build started: Project: mydll, Configuration: Debug Win32 ------ Compiling... mydll.cpp c:\dokumente und einstellungen\popop\eigene dateien\visual studio 2008\projects\mydll\mydll\mydll.cpp(2) : fatal error C1083: Cannot open include file: 'detours.h': No such file or directory Build log was saved at "file://c:\Dokumente und Einstellungen\popo\Eigene Dateien\Visual Studio 2008\Projects\mydll\mydll\Debug\BuildLog.htm" mydll - 1 error(s), 0 warning(s) ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

Anonymous:

The strcpy_s functions are version of strcpy with [url=http://msdn.microsoft.com/en-us/library/8ef0s5kh(VS.80).aspx]security enhancements[/url]. You can ignore the warning for this purpose. in your open poker table windows, make sure you're using Normal or Large table views and that the chat window is visible and set to Full Detail. Sometimes you have to click an up-arrow to get it to appear.

Hope that helps...

Juan, should wie link something, thought only build/compile mydll.dll? What is the exact procedure? And what is linking ;-)?

Anonymouse wrote "oh i'm sorry for the typing and grammar mistakes, but i can't edit my previous post. if anyone compile the code above, then please concern that withdll expects an export function. i declared the NullExport function, but it's important to add "/export:NullExport" into the Additional Options at the Linker Properties of your project."

I think I was doing this correct, but may be not.

Juan, the problem is that the linking of your detours lib isnt working. you probably forgot to add the detours libs to the linker options. if you add the detours include dir to the VC++ include dir, it's also important to tell the linker that he should link detours.lib and detoured.lib to your project. for that, add "detours.lib detoured.lib" to die Additional Dependencies at the Linker -> Input configuration properties of your project (VS2008).

========== Build: 0 succeeded, 0 failed, 1 up-to-date, 0 skipped ==========

Thank you Anonymous. That was it.

I added the two .libs to my Input because I was having the same problem Juan was having, but one of the errors I got before adding them did not go away; mydll.obj : error LNK2005: _DllMain@12 already defined in dllmain.obj >mydll.dll/export:NullExport : fatal error LNK1169: one or more multiply defined symbols found

Juan says; "Thank you Anonymous. That was it."

Another Anonymous later: "I added the two .libs to my Input because..."

Could someone tell more? Or better give a small summery how to get mydll.dll working. May a step by step tut. how to include or what to link to get it.

Im using VC Express and when I go to project>mydll property pages>linker>input there are several fields which could have user-text-input.

Would be nice to get a short perfect formulated advice (all menu-items and input-fields) for vc newbies.

So we all can benefit from the great mydll.dll - script.

I m not using VC Express. I m using VS Express sorry ;-).

OK, did some research... we have to tell vc the detours include path by going to tools>options>vc++directories...then choose pulldown show directories for include path...and then add a new path for example: c:\Programme\Microsoft Research\Detours Express 2.1\include we can do the same for the library files...so linking is no longer a problem...and remeber not to type any backslash for output file like "/export:NullExport", seems to be "export:NullExport"

  1. create an emty dll-project
  2. copy paste the code
  3. set the include and library pathes for detours as metioned above
  4. build and compile

mydll - 0 error(s), 0 warning(s) ========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

Thanks Popo (and others). That helped me.

I found three files in C:\Documents and Settings\Terry\My Documents\Visual Studio 2008\Projects\mydll they are: mydll (VC+++ Intellisense Database) mydll (Microsoft Visual Studio Solution) mydll (Visual Studio User Options)

Is the second one the desired dll?

The example says to run: withdll.exe /d:mydll.dll "C:\Program Files\PokerStars".

is that done from the Start\Programs\Accessories\Command Prompt or from withine VS?

and when i rebuild:

LINK : fatal error LNK1104: cannot open file '/export:NullExport'

what the heck we are doing here?

popo: When compiled, the files go to /bin/debug in the folder where your project lies. Anonymous before popo: You first compile the solution (or recompile if you already have and encountered errors), then go to /bin/debug in your Projects/mydll folder to find your .dll

everyone breathe normally!

thank you Anonymous, I will look there

oh thx i did not noticed that i have two debug folders into my project-dir what did you typed in the linker/general/Output File - Field "/export:NullExport" or "export:NullExport" ?

Still get the error: LINK : fatal error LNK1104: cannot open file '/export:NullExport'

i have two mydll folders and two debug folders!

using export:NullExport

looks like the second one is created if you select Build, Rebuild Solution

after rebuild i get

mydll : error PRJ0021 : Tool 'Linker', Property 'Output File' contains invalid file name.

and you do the same without any error-messages? i use vs 2008 express, and you?

i still don't have a mydll.dll file

not exactly intuitive, but making some progress

may someone is kidding us.

i am using micro VS pro edition

========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

just can't find mydll.dll !

it is possible

but i think it should compile into a dll

how about this?

if anyone has compiled the above code into a dll, please post the file size here

the location of mydll.dll varies but it depends on using the export:NullExport hint or not. i get a mydll.dll when i m not using the export:NullExport. But then i get a prompt message: mydll.dll does not export function with ordinal #1

after hours of research...its so disappointing...was someone successfull? pleas make a detailed post.

compare settings and code:

in Solution Explorer i have 1 header file: header.h 0 resource files 1 source file: detourcode.cpp (or whatever you want to call it)

what do you have in your source file?

this is all "extra credit" anyway

as a further hint, once youve gotten detours running like James describes, open up the TRACEAPI.DLL source code and start commenting out the functions you don't want. you can selected from the top and scroll down to the bottom, comment them all using edit->advanced->comment Selection, and then go in and turn on the individual funcs you want to trace.

Thank you folks, unfortunately I get this strange message on my command

prompt wenn triggering withdll:

LoadLibraryEx(TRACEAPI.DLL) failed with error 126

TRACEAPI.DLL does not export function with ordinal #1

I m trying to rebuild XPokerBot and get the following output:

------ Rebuild All started: Project: XPokerBot.Hook, Configuration: Debug Win32 ------ Deleting intermediate and output files for project 'XPokerBot.Hook', configuration 'Debug|Win32' Compiling... cl : Command line warning D9035 : option 'Wp64' has been deprecated and will be removed in a future release ApplicationProxy.cpp c:\00000pokeraibauen\xpokerbot\xpokerbot\xpokerbot.hook\tablesummary.h(91) : warning C4996: 'strcpy': This function or variable may be unsafe. Consider using strcpys instead. To disable deprecation, use CRTSECURENOWARNINGS. See online help for details. c:\programme\microsoft visual studio 9.0\vc\include\string.h(74) : see declaration of 'strcpy' c:\00000pokeraibauen\xpokerbot\xpokerbot\xpokerbot.hook\tablesummary.h(92) : warning C4996: 'strcpy': This function or variable may be unsafe. Consider using strcpys instead. To disable deprecation, use CRTSECURENOWARNINGS. See online help for details. c:\programme\microsoft visual studio 9.0\vc\include\string.h(74) : see declaration of 'strcpy' c:\00000pokeraibauen\xpokerbot\xpokerbot\xpokerbot.hook\applicationproxy.cpp(132) : warning C4996: 'strcpy': This function or variable may be unsafe. Consider using strcpys instead. To disable deprecation, use CRTSECURENOWARNINGS. See online help for details. c:\programme\microsoft visual studio 9.0\vc\include\string.h(74) : see declaration of 'strcpy' OnlinePokerClient.cpp c:\00000pokeraibauen\xpokerbot\xpokerbot\xpokerbot.hook\tablesummary.h(91) : warning C4996: 'strcpy': This function or variable may be unsafe. Consider using strcpys instead. To disable deprecation, use CRTSECURENOWARNINGS. See online help for details. c:\programme\microsoft visual studio 9.0\vc\include\string.h(74) : see declaration of 'strcpy' c:\00000pokeraibauen\xpokerbot\xpokerbot\xpokerbot.hook\tablesummary.h(92) : warning C4996: 'strcpy': This function or variable may be unsafe. Consider using strcpys instead. To disable deprecation, use CRTSECURENOWARNINGS. See online help for details. c:\programme\microsoft visual studio 9.0\vc\include\string.h(74) : see declaration of 'strcpy' OnlinePokerExecutor.cpp OnlineTableWindow.cpp PokerTimeCaptionDecoder.cpp c:\00000pokeraibauen\xpokerbot\xpokerbot\xpokerbot.hook\tablesummary.h(91) : warning C4996: 'strcpy': This function or variable may be unsafe. Consider using strcpys instead. To disable deprecation, use CRTSECURENOWARNINGS. See online help for details. c:\programme\microsoft visual studio 9.0\vc\include\string.h(74) : see declaration of 'strcpy' c:\00000pokeraibauen\xpokerbot\xpokerbot\xpokerbot.hook\tablesummary.h(92) : warning C4996: 'strcpy': This function or variable may be unsafe. Consider using strcpys instead. To disable deprecation, use CRTSECURENOWARNINGS. See online help for details. c:\programme\microsoft visual studio 9.0\vc\include\string.h(74) : see declaration of 'strcpy' c:\00000pokeraibauen\xpokerbot\xpokerbot\xpokerbot.hook\pokertimecaptiondecoder.cpp(78) : warning C4996: 'strcpy': This function or variable may be unsafe. Consider using strcpys instead. To disable deprecation, use CRTSECURENOWARNINGS. See online help for details. c:\programme\microsoft visual studio 9.0\vc\include\string.h(74) : see declaration of 'strcpy' c:\00000pokeraibauen\xpokerbot\xpokerbot\xpokerbot.hook\pokertimecaptiondecoder.cpp(86) : warning C4996: 'strcpy': This function or variable may be unsafe. Consider using strcpys instead. To disable deprecation, use CRTSECURENOWARNINGS. See online help for details. c:\programme\microsoft visual studio 9.0\vc\include\string.h(74) : see declaration of 'strcpy' PokerTimePokerClient.cpp c:\00000pokeraibauen\xpokerbot\xpokerbot\xpokerbot.hook\tablesummary.h(91) : warning C4996: 'strcpy': This function or variable may be unsafe. Consider using strcpys instead. To disable deprecation, use CRTSECURENOWARNINGS. See online help for details. c:\programme\microsoft visual studio 9.0\vc\include\string.h(74) : see declaration of 'strcpy' c:\00000pokeraibauen\xpokerbot\xpokerbot\xpokerbot.hook\tablesummary.h(92) : warning C4996: 'strcpy': This function or variable may be unsafe. Consider using strcpys instead. To disable deprecation, use CRTSECURENOWARNINGS. See online help for details. c:\programme\microsoft visual studio 9.0\vc\include\string.h(74) : see declaration of 'strcpy' PokerTimeTableWindow.cpp c:\00000pokeraibauen\xpokerbot\xpokerbot\xpokerbot.hook\tablesummary.h(91) : warning C4996: 'strcpy': This function or variable may be unsafe. Consider using strcpys instead. To disable deprecation, use CRTSECURENOWARNINGS. See online help for details. c:\programme\microsoft visual studio 9.0\vc\include\string.h(74) : see declaration of 'strcpy' c:\00000pokeraibauen\xpokerbot\xpokerbot\xpokerbot.hook\tablesummary.h(92) : warning C4996: 'strcpy': This function or variable may be unsafe. Consider using strcpys instead. To disable deprecation, use CRTSECURENOWARNINGS. See online help for details. c:\programme\microsoft visual studio 9.0\vc\include\string.h(74) : see declaration of 'strcpy' stdafx.cpp XPokerBot.Hook.cpp Generating Code... Compiling manifest to resources... Microsoft (R) Windows (R) Resource Compiler Version 6.0.5724.0 Copyright (C) Microsoft Corporation. All rights reserved. Linking... LINK : fatal error LNK1104: cannot open file 'libboostregex-vc90-mt-gd-135.lib' Build log was saved at "file://c:\00000pokeraibauen\XPokerBot\XPokerBot\XPokerBot.Hook\Debug\BuildLog.htm" XPokerBot.Hook - 1 error(s), 14 warning(s) ------ Rebuild All started: Project: XPokerBot.MfcView, Configuration: Debug Win32 ------ Deleting intermediate and output files for project 'XPokerBot.MfcView', configuration 'Debug|Win32' Compiling... cl : Command line warning D9035 : option 'Wp64' has been deprecated and will be removed in a future release stdafx.cpp c:\00000pokeraibauen\xpokerbot\xpokerbot\xpokerbot.mfcview\stdafx.h(57) : fatal error C1083: Cannot open include file: 'afxwin.h': No such file or directory Build log was saved at "file://c:\00000pokerai_bauen\XPokerBot\XPokerBot\XPokerBot.MfcView\Debug\BuildLog.htm" XPokerBot.MfcView - 1 error(s), 1 warning(s) ========== Rebuild All: 0 succeeded, 2 failed, 0 skipped =========

Think the main errors are include-erros, but i pointed VS to the boost-dir.

Could someone help, please?

Environment: WinXP, VS Express, Boost 1.35.0

Hm, yes I would do so...but right now I have to less diskspace ;-)...have to wait to buy some DVD's to free some space...but since several days I play break even by hand, may I will earn some money to get it ;-).

Thanks for your advise james.

I figured out that there is an installer for boost (was realtivly hidden on the page you mentioned), fo first I got the source-distribution ;-). The Link is: http://www.boostpro.com/products/free

exciting stuff. this site is the tip of the spear

@james: you > me

Could someone bring up an example how to point Visual Studio correctly to boost?

to avoid such things like this: c:\00000pokerai_bauen\xpokerbot\xpokerbot\xpokerbot.hook\stdafx.h(100) : fatal error C1083: Cannot open include file: 'regex.hpp': No such file or directory OnlinePokerClient.cpp

my boost is located in: C:\Programme\boost

[...] This directory (XPokerBot/boost) contains Debug and Release versions of the Boost regex library. You can link to these binaries assuming you've installed the Boost header files, even if you haven't gone to the trouble of building Boost yourself. [...] ...and which header-files should I put where...any idea? I used the boost installer.

popo, you need to add the following two directories to your IDE options (Tools->Options):

-C:\Programme\Boost\boost1331-C:\Programme\Boost\boost1331\boost

In VS2008, go to Tools->Options. Select 'Projects and Solutions' followed by 'VC++ Directories'. Then change the dropdown to say 'Show Directories for: INCLUDE files'. And add the above two lines to the list. Not sure how to get at this setting in VC Express but thats in VS2008.

You can also if worst comes to worst add the full path to the include:

include "c:\programs...etc\regex.hpp"

Kind of a hack. Oh and if you've installed some other version of Boost you'll need to tweak the above directories approp.

Thank you Jeremyx, I forgot that I solved this problem befor playing with the dir-locations. You rembered me the right notation.

I know VC Express is not the right IDE but can someone tell me where this files normaly resist when using VS Pro.?

LINK : fatal error LNK1104: cannot open file 'libboostregex-vc90-mt-gd-135.lib'

c:\00000pokerai_bauen\xpokerbot\xpokerbot\xpokerbot.mfcview\stdafx.h(57) : fatal error C1083: Cannot open include file: 'afxwin.h': No such file or directory

XPokerBot.MfcView - 1 error(s), 1 warning(s)

For all VS Express user, I found this comment which underlines James idea:

You're missing MFC to get afxwin.h and the Platform SDK for <windows.h>. They don't come included with the Express edition. MFC is a no-go but you can get the Platform SDK; search this forum for "SDK".

when trying WITHDLL /D:TRACEAPI.DLL C:\PROGRAM FILES\POKERSTARS\POKERSTARS.EXE I got the same message as Popo.

withdll.exe: LoadLibraryEx(TRACEAPI.DLL) failed with error 126. withdll.exe: Error: TRACEAPI.DLL does not export funtion with ordinal #1.

also, does it matter if it is? WITHDLL /D:TRACEAPI.DLL C:\PROGRAM FILES\POKERSTARS\POKERSTARS.EXE or WITHDLL /D:TRACEAPI.DLL "C:\PROGRAM FILES\POKERSTARS\POKERSTARS.EXE"

Hello James, what is the syntax to nmake a traceapi?

open ms-dos cmd prompt, navigate to the detour "samples" folder.. then it is good for you to type 'nmake' and it will build the samples..

(you may get some error during nmake. as with me it was a problem with the "RC" tool. i had to find rc.exe on the machine and add it to system path. maybe this is not happening for you.)

Thank you Rammohan...what a wonder it does not work ;-):

cd &quot;E:\Programme\Microsoft Research\Detours Express 2.1\samples\syelog&quot;
if not exist ..\include mkdir ..\include
if not exist ..\lib mkdir ..\lib
if not exist ..\..\bin mkdir ..\..\bin
cd &quot;E:\Programme\Microsoft Research\Detours Express 2.1\samples\simple&quot;
if not exist ..\..\bin mkdir ..\..\bin
cd &quot;E:\Programme\Microsoft Research\Detours Express 2.1\samples\slept&quot;
if not exist ..\..\bin mkdir ..\..\bin
cd &quot;E:\Programme\Microsoft Research\Detours Express 2.1\samples\setdll&quot;
if not exist ..\..\bin mkdir ..\..\bin
cd &quot;E:\Programme\Microsoft Research\Detours Express 2.1\samples\withdll&quot;
if not exist ..\..\bin mkdir ..\..\bin
cd &quot;E:\Programme\Microsoft Research\Detours Express 2.1\samples\cping&quot;
if not exist ..\..\bin mkdir ..\..\bin
cd &quot;E:\Programme\Microsoft Research\Detours Express 2.1\samples\disas&quot;
if not exist ..\..\bin mkdir ..\..\bin
cd &quot;E:\Programme\Microsoft Research\Detours Express 2.1\samples\dtest&quot;
if not exist ..\..\bin mkdir ..\..\bin
cd &quot;E:\Programme\Microsoft Research\Detours Express 2.1\samples\dumpe&quot;
if not exist ..\..\bin mkdir ..\..\bin
cd &quot;E:\Programme\Microsoft Research\Detours Express 2.1\samples\dumpi&quot;
if not exist ..\..\bin mkdir ..\..\bin
cd &quot;E:\Programme\Microsoft Research\Detours Express 2.1\samples\einst&quot;
if not exist ..\..\bin mkdir ..\..\bin
cd &quot;E:\Programme\Microsoft Research\Detours Express 2.1\samples\excep&quot;
if not exist ..\..\bin mkdir ..\..\bin
cd &quot;E:\Programme\Microsoft Research\Detours Express 2.1\samples\commem&quot;
if not exist ..\..\bin mkdir ..\..\bin
cd &quot;E:\Programme\Microsoft Research\Detours Express 2.1\samples\findfunc&quot;
cl /nologo /Zi /MT /Gm- /W4 /WX /O1 &quot;/I..\..\include&quot; &quot;/I..\include&quot; /Gs /DDETOURS_X86=1 /D_X86_ /Fe..\..\bin\symtest.exe /Fd..\..\bin\symtest.pdb symtest.cpp  /link /release /machine:x86 &quot;..\lib\syelog.lib&quot; &quot;..\..\lib\detours.lib&quot; &quot;..\..\lib\detoured.lib&quot;  kernel32.lib gdi32.lib user32.lib shell32.lib  /subsystem:console /incremental:no /fixed:no ..\..\bin\target.lib

symtest.cpp symtest.cpp(270) : error C2664: 'BOOL (HANDLE,PSYMENUMMODULESCALLBACK64,PVOID)' : cannot convert parameter 2 from 'overloaded-function' to 'PSYMENUMMODULESCALLBACK64' None of the functions with this name in scope match the target type

...but thank you for your tip.

Nice posts, all of them! tried to open the solutin in VS2005 (after convert) but couldnt build them: Error 1 fatal error C1083: Cannot open include file: 'regex.hpp': No such file or directory c:\documents and settings\brian_h\desktop\xpokerbot\xpokerbot.hook\stdafx.h 100

if i comment out the above line then it says that the line: map<HWND, OnlineTableWindow*> myTables; is wrong: Error 4 error C2143: syntax error : missing ';' before '<' c:\documents and settings\brian_h\desktop\xpokerbot\xpokerbot.hook\onlinepokerclient.h 54

along with 92 other errors..

Anyone???

Sry but im not so much into C++. Love to see the solution in C# though..

H4mm3rHead...take a look at post: "JeremyX on 7/6/2008 4:32:37 PM (17 hours ago)". Solves the regex-include problem.

When I try nmake of Detours I get error U1077. I have standard default installs of Detours 2.1 Express and Visual Studio 2008 version 9.0, running Win XP.

Google of "nmake U1077" shows that this is a widespread problem. Have not found a solution that works for me yet.

I think that there is some config setting in VS that is wrong but still looking.

"i hope i could help you and if you have problems with compiling detours with vs2008, take a look at http://forums.msdn.microsoft.com/en-US/vcgeneral/thread/fcb5a809-5404-481f-82c0-40ffa6f58c9b/. greet" especially the 2nd post from austin.

I stumbled on your articles here and I cant say much else than WOW...Im currently building a poker bot and have reach quite much further than you'r articles so faar. But its still damn interesting reading. Im doing my bot in pure c# and its just as you mention. You cant do the really lowlevel programming with that language. But so faar its no problems.

I just wanted to ask about your opinion when it comes to DLL-injection. Isnt it "fairly" easy to just run a hash check on your own application ( poker client's in this case ). If the hash does not match an DLL injection has been made? Or? Guess the real question is if Im doing a lot of uneccessary work when Im working without DLL injections.

Would love to see you combining both C# and C++ in your application.

Thanks for great reading!

Hey Jim...looks like you've been busy...

Very impressive posts!

Give me a call or shoot me an email

traceapi.dll is 96.0 KB (98,366 bytes) on my system

"It looks like Visual Studio 2008 ships with standard libraries with different types to what detours expects. At this stage, I'm not sure what the best work-around is: you could always try building with VS 2005." http://forums.msdn.microsoft.com/en/vcgeneral/thread/fcb5a809-5404-481f-82c0-40ffa6f58c9b/

If any of you players or bot writers need hand histories for your stats (PT, HM etc) databases you should head to HandHQ.com.

Hi there. I'm pretty interested in this project as long as I'm making my way to a pro-style playing, but also I enjoy coding.

I'm not intended to cheat on poker sites, but I would like to make this bot a personal coach approach. I'd love to make him evaluate my sessions and discovering my leaks or any similar approach.

I'll be tune to this blog ... thanks.

hi,

I have a small problem with folderbot, I get an error (0xc0150002), I am using visual net 2005, I am using windows vista

Thanks

hi! maybe we should create some sort of forum for this?

i'm sure tons of people will have questions or ideas to bring up. if we had a more organized way to deal with this, we could answer each other's questions and have set areas to discuss new ideas and so forth.

what do you guys think?

I would agree a forumn could be good. I would like to trade code with people that are hoooking into other sites. My action bot is working with this one but no one really seems to play on this site.

There are already other forums out there, but this is where the action is now. If you don't like it here leave.

fold bot works, but I lost all my $$$...

wtf?

looking forward to part 5, when can we expect it?

J.D.: on http://www.codingthewheel.com/image.axd?picture=multitabling_safe.jpg you use muliple Screens, one screen only for the bot. Is it a mult-screen environment or a multiple computer-environment? Is it a special save environment?

and can wie expect such I nice ready to go GUI like: http://www.codingthewheel.com/image.axd?picture=pokerbotprofile.gif

I love you :-) popo

I have managed to capture the text chat Pokerstars, but I would like to obtain information from users nro playing, who is the one who wins.

how to get the events of the pokerstarstableframeclass.

if someone knows some method to obtain it.

another option

http://www.codeplex.com/easyhook/Release/ProjectReleases.aspx?ReleaseId=15155

Hello James. Phenominal info here. I have really enjoyed all your recent information, but as many here, I am most interested in your poker bot. I am hoping you may be able to help me. I am a fairly proficient c# programmer and will probably be recoding much of your examples in c# as that is my current language of choice. I downloaded the DetoursExpress install and when I attempted the install I get an error code 2908. Exact error message: "The installer has encountered an unexpected error installing this package. This may indicate a problem with this package. The error code is 2908." Tried uninstall/reinstall, repair, redownloading, etc. all to no avail. Any ideas where to start? TIA.

Jim, is your Detours Express Download 544KB?

sorry..it is exactly 566,544 bytes

yes

Well...actually...I checked the files size from windows explorer and it shows 544KB, but when I check the file's properties, it shows 556,544 (where you asked if it was 566,544), so the answer is yes ... and ... no.

;)

Ahhhhhh need the new article. How do you read hole cards in PS? I can't find the log file.

PokerStars.log

donde carajo esta el pokerstars.log, i dont find

Hi all,

still got this errors:

LINK : fatal error LNK1104: Datei "libboostregex-vc90-mt-gd-135.lib" kann nicht geöffnet werden. LINK : fatal error LNK1104: Datei "..\bin\XPokerBot.Hook.lib" kann nicht geöffnet werden.

I've added the paths as shown above but nothing helps.... I'm using vista+vs2008

I've tested boost with that little program an the boost homepage and it seems to work.

I would be pleased for any help

Alex its PokerStars.log.0 on my comp, in the pokerstars folder.

Cant wait till part 5!

Fritz, in addition to the two Boost include folders, add the Boost/lib folder to your IDE options.

In VS2008, go to Tools->Options. Select 'Projects and Solutions' followed by 'VC++ Directories'. Then change the dropdown this time to say 'Show Directories for: LIBRARY files'. Add "C:\Boost\lib" (or your equivalent) to this list.

And let's see.. you might want to make sure the file

libboostregex-vc90-mt-gd-135.lib

exists in this location, and copy it over to XPokerBot/boost just for the fun of it (not sure if this is necessary or not).

Thanks Jeremy,

I just saw that the first file

"libboostregex-vc90-mt-gd-135.lib"

does not exist in ..boost\lib

there is only a file called "libboostregex-vc90-mt-sgd-135"

do I have to install additional libs for boost?

Bloody hell, its saturday afternoon and I am sitting at my PC looking to see if the next bot article was up. I need at bot to kick my ass out of here (and why isn't it up yet :-D)...

Hi, now everything is fine, I did not install all variants from boostpro.....

Fritz,

Visit http://www.quantnet.org/forum/showpost.php?p=20569&postcount=41

I think that this can be your solution because i had the same problem.

You have to put the paths for include files

C:\Boost\include\boost-135 C:\Boost\include\boost-135\boost C:\Boost\lib

and in library path

C:\Boost\lib

this work for me

good luck


This articles are the best. Thanks a lot for all and sorry about my english!!!!!

Waiting for the next chapter!!!

Thanks Somatxigun,

with my last post I wanted to express that I already fixed my problem ;-)

I know Fritz :D!!!!

I didnt see your last post!!!!

Waiting for the next chapter!!!!!

Thanks very much for the article and the idea. Over the I was able to put together a Trashbot in AutoIt and it abso-frickin-lutely rocks. Tonight I'm going to add some PixelChecksum functions to screenscrape the flop cards.

Awesome. Many Thanks.

EH

I have a question for anyone reading... How are you handling the case in which a message is duplicated? Here is an example from a hooked ExtTextOutW to illustrate...

Hooked Function - Table Name = Message MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=Dealer: The flop is [Ts 7s 8h] MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=Dealer: Pritt95 bets $5 MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=Dealer: bordos calls $5 MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=Dealer: Pritt95 bets $5 MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=Dealer: bordos calls $5 MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=Dealer: The turn is [3c] MyExtTextOutW-Alto (6 max) - $5/$10 - Limit Hold'em=Dealer: SwimmingPool raises to $10 MyExtTextOutW-Alto (6 max) - $5/$10 - Limit Hold'em=Dealer: gambleallday folds MyExtTextOutW-Alto (6 max) - $5/$10 - Limit Hold'em=Dealer: MGAMW calls $5 MyExtTextOutW-Alto (6 max) - $5/$10 - Limit Hold'em=Dealer: The flop is [Js 5d 6s] MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=Dealer: bordos calls $5 MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=Dealer: The turn is [3c] MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=Dealer: Pritt95 bets $10 MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=Dealer: The turn is [3c] MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=Dealer: Pritt95 bets $10 MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=Dealer: bordos calls $10

Notice how the turn is "dealt" several times? Also how several bets are duplicated. How can we handle this sort of thing?

Robert,

Interesting. I wonder if that is spoofing.

Are you using Detours to hook?

Looks like you will need to write a filtering routine. The extent of the filtering will be determined by the frequency and extent of the duplicates. Do the duplicates occur on every hand? Is it always the turn?

You are 100% on the money James...

Another Example with more data: Hooked Process - Window Name = int x int y (lprc).top (lprc).left (lprc).bottom (lprc).right = Message MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=64 top=64 left=0 bottom=80 right=412 =Dealer: Hand #7224220307 MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=0 top=0 left=0 bottom=16 right=412 =Dealer: Uncalled bet of $5 returned to sundog123 MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=16 top=16 left=0 bottom=32 right=412 =Dealer: sundog123 mucks MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=32 top=32 left=0 bottom=48 right=412 =Dealer: sundog123 wins the pot ($19) MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=48 top=48 left=0 bottom=64 right=412 =Dealer: Hand #7224220307 MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=64 top=64 left=0 bottom=80 right=412 =Dealer: E-money posts the small blind of $2.50 MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=0 top=0 left=0 bottom=16 right=412 =Dealer: sundog123 mucks MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=16 top=16 left=0 bottom=32 right=412 =Dealer: sundog123 wins the pot ($19) MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=32 top=32 left=0 bottom=48 right=412 =Dealer: Hand #7224220307 MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=48 top=48 left=0 bottom=64 right=412 =Dealer: E-money posts the small blind of $2.50 MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=64 top=64 left=0 bottom=80 right=412 =Dealer: MrGames posts the big blind of $5 MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=0 top=0 left=0 bottom=16 right=412 =Dealer: sundog123 wins the pot ($19) MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=16 top=16 left=0 bottom=32 right=412 =Dealer: Hand #7224220307 MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=32 top=32 left=0 bottom=48 right=412 =Dealer: E-money posts the small blind of $2.50 MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=48 top=48 left=0 bottom=64 right=412 =Dealer: MrGames posts the big blind of $5 MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=64 top=64 left=0 bottom=80 right=412 =Dealer: Zegai folds MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=0 top=0 left=0 bottom=16 right=412 =Dealer: Hand #7224220307 MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=16 top=16 left=0 bottom=32 right=412 =Dealer: E-money posts the small blind of $2.50 MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=32 top=32 left=0 bottom=48 right=412 =Dealer: MrGames posts the big blind of $5 MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=48 top=48 left=0 bottom=64 right=412 =Dealer: Zegai folds MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=64 top=64 left=0 bottom=80 right=412 =Dealer: Keysmark folds MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=0 top=0 left=0 bottom=16 right=412 =Dealer: E-money posts the small blind of $2.50 MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=16 top=16 left=0 bottom=32 right=412 =Dealer: MrGames posts the big blind of $5 MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=32 top=32 left=0 bottom=48 right=412 =Dealer: Zegai folds MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=48 top=48 left=0 bottom=64 right=412 =Dealer: Keysmark folds MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=64 top=64 left=0 bottom=80 right=412 =Dealer: Tamburlaine folds MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=0 top=0 left=0 bottom=16 right=412 =Dealer: MrGames posts the big blind of $5 MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=16 top=16 left=0 bottom=32 right=412 =Dealer: Zegai folds MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=32 top=32 left=0 bottom=48 right=412 =Dealer: Keysmark folds MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=48 top=48 left=0 bottom=64 right=412 =Dealer: Tamburlaine folds MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=64 top=64 left=0 bottom=80 right=412 =Dealer: sundog123 raises to $10 MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=0 top=0 left=0 bottom=16 right=412 =Dealer: Zegai folds MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=16 top=16 left=0 bottom=32 right=412 =Dealer: Keysmark folds MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=32 top=32 left=0 bottom=48 right=412 =Dealer: Tamburlaine folds MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=48 top=48 left=0 bottom=64 right=412 =Dealer: sundog123 raises to $10 MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=64 top=64 left=0 bottom=80 right=412 =Dealer: E-money folds MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=0 top=0 left=0 bottom=16 right=412 =Dealer: Keysmark folds MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=16 top=16 left=0 bottom=32 right=412 =Dealer: Tamburlaine folds MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=32 top=32 left=0 bottom=48 right=412 =Dealer: sundog123 raises to $10 MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=48 top=48 left=0 bottom=64 right=412 =Dealer: E-money folds MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=64 top=64 left=0 bottom=80 right=412 =Dealer: MrGames calls $5 MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=0 top=0 left=0 bottom=16 right=412 =Dealer: Tamburlaine folds MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=16 top=16 left=0 bottom=32 right=412 =Dealer: sundog123 raises to $10 MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=32 top=32 left=0 bottom=48 right=412 =Dealer: E-money folds MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=48 top=48 left=0 bottom=64 right=412 =Dealer: MrGames calls $5 MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=64 top=64 left=0 bottom=80 right=412 =Dealer: The flop is [6d Jd Jh] MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=0 top=0 left=0 bottom=16 right=412 =Dealer: sundog123 raises to $10 MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=16 top=16 left=0 bottom=32 right=412 =Dealer: E-money folds MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=32 top=32 left=0 bottom=48 right=412 =Dealer: MrGames calls $5 MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=48 top=48 left=0 bottom=64 right=412 =Dealer: The flop is [6d Jd Jh] MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=64 top=64 left=0 bottom=80 right=412 =Dealer: MrGames checks MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=0 top=0 left=0 bottom=16 right=412 =Dealer: E-money folds MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=16 top=16 left=0 bottom=32 right=412 =Dealer: MrGames calls $5 MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=32 top=32 left=0 bottom=48 right=412 =Dealer: The flop is [6d Jd Jh] MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=48 top=48 left=0 bottom=64 right=412 =Dealer: MrGames checks MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=64 top=64 left=0 bottom=80 right=412 =Dealer: sundog123 bets $5 MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=0 top=0 left=0 bottom=16 right=412 =Dealer: MrGames calls $5 MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=16 top=16 left=0 bottom=32 right=412 =Dealer: The flop is [6d Jd Jh] MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=32 top=32 left=0 bottom=48 right=412 =Dealer: MrGames checks MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=48 top=48 left=0 bottom=64 right=412 =Dealer: sundog123 bets $5 MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=64 top=64 left=0 bottom=80 right=412 =Dealer: MrGames folds MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=0 top=0 left=0 bottom=16 right=412 =Dealer: The flop is [6d Jd Jh] MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=16 top=16 left=0 bottom=32 right=412 =Dealer: MrGames checks MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=32 top=32 left=0 bottom=48 right=412 =Dealer: sundog123 bets $5 MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=48 top=48 left=0 bottom=64 right=412 =Dealer: MrGames folds MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=64 top=64 left=0 bottom=80 right=412 =Dealer: Uncalled bet of $5 returned to sundog123

Now that you've mentioned it it makes sense. Account for new text only entering when Y=64 (in this case for a maximized window)...

MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=64 top=64 left=0 bottom=80 right=412 =Dealer: Hand #7224220307

MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=64 top=64 left=0 bottom=80 right=412 =Dealer: E-money posts the small blind of $2.50

MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=64 top=64 left=0 bottom=80 right=412 =Dealer: MrGames posts the big blind of $5

MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=64 top=64 left=0 bottom=80 right=412 =Dealer: Zegai folds

MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=64 top=64 left=0 bottom=80 right=412 =Dealer: Keysmark folds

MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=64 top=64 left=0 bottom=80 right=412 =Dealer: Tamburlaine folds

MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=64 top=64 left=0 bottom=80 right=412 =Dealer: sundog123 raises to $10

MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=64 top=64 left=0 bottom=80 right=412 =Dealer: E-money folds

MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=64 top=64 left=0 bottom=80 right=412 =Dealer: MrGames calls $5

MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=64 top=64 left=0 bottom=80 right=412 =Dealer: The flop is [6d Jd Jh]

MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=64 top=64 left=0 bottom=80 right=412 =Dealer: MrGames checks

MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=64 top=64 left=0 bottom=80 right=412 =Dealer: sundog123 bets $5

MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=64 top=64 left=0 bottom=80 right=412 =Dealer: MrGames folds

MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=X=3 Y=64 top=64 left=0 bottom=80 right=412 =Dealer: Uncalled bet of $5 returned to sundog123

Huzzah! The game makes sense!

Thanks for sharing your thoughts, I hope some other individuals can dervice some benefit from this.

Hi James,

first let me congratulate you on your very interesting article series. Really great work.

I'm a professional programmer and interested in poker bots since about two years. Actually I'm doing it right now more and more professionally.

For your readers who are not so deep in programing I have an interesting site.

Openholdem is an open source project.

You can download it for free and contribute code when you want.

Forum here: http://www.maxinmontreal.com/forums/index.php?c=34

Advantages:

  • you can concentrate on the poker logic

  • autoplayer, table scraping, etc. already included

  • a lot of in-built functions like for example Pokertracker usage

  • as said free and source code available

  • you can write the poker logic for Limit Holdem, NL Holdem, PL Holdem, SNGs or MTTs

  • big forum with many experts

Disadvantages:

  • supports currently only Texas Holdem - not Omaha or 7 Stud

  • you still need to write the poker logic which is the most difficult part (most pokerbots are losers estimated 10% are winners)

Hi James,

first of all, thank you for this very intresting articles!

I'm actualy working on a poker tool too, not a bot, or maybe not yet. This program is for 7-stud, not for hold'em and thats my biggest problem. The informations in the chat box dont have all infos on stud games (pokerstars).

Long time ago, I've tried to get some infos with API Hook, but it's failed. So I was working with screen-capturing, but it frusrating me!

I'm not a Windows API and C++ expert. Java and .NET is more my corner. Maybe u can help me, or some one else, to solve this problem and pointing that in the next part. I know one commercial program, that can do this well, Poker Pal. So I think it's possible.

Thank you!

Whens the new part coming?

Sorry Ive refreshed this page a million times over the last week, just curious:P

^^ Yeah, tyler's right!

When will be the new part released?

My F5 key is dying...

Please, save my F5 key :)

Hi!

I'm also working on a poker bot and I have a question for you.

I'm building my bot in .NET (C#) and decided to use screen scraping to get the info i need to build my domain model. I found a pretty god ocr sdk that I'm currently using. But now I'm leaning more and more to using dll injection.

So my question is: .NET doesn't support global hooks (according to a several articles on msdn), do I have to use a global hook? I know that you are talking in favor of using C++ for the dll injection but I'm want to know if it's even possible to use .NET to accomplish this?

Sorry if my English is weird but I'm from Sweden and I took for granted that your Swedish is worse than my English :)

I finally got something up and running, i decided to translate the C++ part into Delphi (thats what i know best after C#) and managed to get a global hook into processes. My plan is to send everything from the client chat to my managed C# application, but problems: Pokerstars doesnt seem to display holecards any longer??? or have i missed something?? Tried Full Tilt they have rigged their chat control to return an empty string when doing GetWindowText, any suggestions on how to get the information? I know u guys probably will say "Detours" but isnt there someway manual to get the same information? I am really not that good with C++ and dont know where to start with detours... any help will be appreciated.

Cheers...

"...dont know where to start with detours... "

welcome to the club. can't do the nmake

Woohoo! New parts later today!

wait a minute, have to prepare some disk space...;-)

@H4mm3rHead & Oscar

Detours really is a nice software package, At full tilt it can be used in order to hook into ExtTextOutW to get the chat window text as it is output (thought it does require some buffering to ensure you are not processing the same text over and over again). There is a ton of sample code on how to use the detour's library and you really should consider giving it a shot.

The problem you are having with nmake is that you are not exporting the variables from the visual studio environment properly. You can solve this by either launching the command shell from within visual studio or you can execute vcvars32.bat (it's inside of the visual studio directory) which will add the path of nmake to your path as well as correcting several other possible problems with compilation.

Hope that helps! In my opinion the hardest thing was the dll injection (I used the CreateRemoteThread method) so the API hooking shouldn't be beyond your skill levels.

You are correct H4mm3rHead, Pokerstars no longer passes the hole cards to the chat window. Could be they got wind of this series? ;) ...And if that is so, I don't know that a hook or Detours will help if you are looking to hook the chat window. I am sure there is a memory location (variable) that contains a value for each of your current hole cards. If there is a way to "peek" into that it would be a simple interpretation. Otherwise, you may be back to a kludgy screen scraper as they have to let the user "see" their hole cards one way or another.

current hole cards shown in PokerStars.log or PokerStars.log.0

I got everything compiled. I did get a number of warnings during the compilation process, but everything did build.

I am using VS.NET 2005 Professional on XP.

I set PokerBot.MfcView to be the main application, and started it. It fails. I get "The application failed to initialize properly..." dialog.

The output window gives the following information: LDR: LdrpWalkImportDescriptor() failed to probe c:\Documents and Settings\Administrator\Desktop\XPokerBot\XPokerBot\bin\XPokerBot.Hook.dll for its manifest, ntstatus 0xc0150002 Debugger:: An unhandled non-continuable exception was thrown during process load The program '[332] XPokerBot.MfcView.exe: Native' has exited with code -1072365566 (0xc0150002).

Any ideas?

[quote]We'll be at part 8 or 9 in the series within 24 hours.. knock on wood.[/quote]

Just 6 hours left...

I can barely see the text written on my F5 key...

My F5 key is dead....

Now using CTRL + R :)

I was able to build it successfully, but somehow the Xpokerbot doesn't detect Poker time window. I'm assuming there's something that I need to change with the

"LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam) ..."

Unfortunately, my programming exp is limited to Freshman and Sophomore level. I did understand most of the theory and a decent amount of the code, but I'm wondering how do I change the code so it'll detect pokertime.

I only saw CBTproc used one other time at

"bool XPOKERBOTHOOKAPI InstallHook() { ghHook = SetWindowsHookEx(WHCBT, (HOOKPROC) CBTProc, ghInstance, 0);

return g_hHook != NULL;

}"

Thanks!

I won't bother u with yet more praise on your articles... U seem to be getting enuf to know they're well appreciated, I just want to ask one non poker or programming realted Q, and provide (hopefully) something helpful for poker botting..

1st) That photo of the Difference Engine build with connector set... Can u lay your hands on the plans... that would be so sweet to build...

2nd) PokerAcademyPro is perfect for testing your poker logic, although u need to code it in Java... U can play it against the UofA bots, and play it yourself... so I find this a good tool for workin on my poker logic (which I am cutting in Java anyway so that restriction not bother me) [and before I get all the comments about Java not being fast enough... Its all Visual J# compatible code, so it does get native compiled, not to mention gcj]

Actually on second thought... You dont need to code a PokerAcademy Bot in Java at all... just use the JNI a write a small Java class to interface with PA and then call into your native code poker logic... This is the approach a mate of mine is using... Works perfectly, and only took him about an hour to get the JNI workin, and he never has to touch it again...

Hi - very cool set of examples and some great code and architecture ideas, thanks!!

For those of you looking for a forum to discuss this further in a more structed manner I've set up one specifically for this topic at:

[url]http://www.pokerbot.org/index.php/Coding-the-Wheel/[/url]

cheers!

So I just got started on this and I am running into this: 2>Linking... 2>LINK : fatal error LNK1104: cannot open file '..\bin\XPokerBot.Hook.lib'

and

1>LINK : fatal error LNK1104: cannot open file 'libboostregex-vc90-mt-gd-135.lib'

This is a great series and it's nice to see all these code snippets brought together as a useful series. But now i'm kinda throwing a spanner in the works, because i'm not in the majority. Some of use Linux (or MAC) rather than Windows. And that means that we play poker via none-download browser versions which use either Java Applets or Flash. Hell, i'm sure there are also loads of Windows users out there who prefer not to download poker software...

So the question is: How do you read game info from a browser client? I know that it's possible to download an Applet, decompile the Jar, modify it and then re-compile so that you run the Applet as a localised file, but is there a more generic method? Can we perhaps hook into the JVM or catch the SSL encrypt/decrypt as it passes through memory? Has anyone successfully built a browser-based game monitor/bot??

Here's a dumb question, but in Visual Studio 2005 if I was going to create a new .Hook what project type would it be? MFC DLL?

Hi, I'm having some trouble with PokerStars when analyzing a table:

¿How can I know how many players are sitting at the table, who is the dealer, and where am I sitting? I can't find that information in chat window or in log file. And I do need that information when it's my turn to decide my next action.

The log file has some lines like these:

MSGTABLESUBSCR_DEALPLAYERCARDS sit0 nCards=2 sit1 nCards=2 sit2 nCards=2 sit3 nCards=2 sit4 nCards=2 sit8 nCards=2 dealerPos=8

But they are not associated to a window handle, so I can't know which table has those players and dealer pos. Anyway, from those lines I still don't know which my position is.

Any ideas?

This is what i get in the log file:

MSGTABLESUBSCR_DEALPLAYERCARDS ::: 11c sit0 ::: 14d nCards=2 ------ 000E0C50 sit1 Table::OnPlayerCards, myCards.changed=0, n=2, flags=0 nCards=2 myCards.changed=1 sit2 nCards=2 sit4 nCards=2 sit5 nCards=2 sit6 nCards=2 sit7 nCards=2 sit8 nCards=2

dealerPos=7

Having sit0 displayed with my hole cards [AdJc] i assume that would be my position? and the number of players is the number of sitX lines in the log... (not the highest X) In your example it seems there are 6 other players than you, and i would guess you are seated somewhere 6-7-8 (as they are missing from the list, and whichever you are, the other 2 are empty.

I dont know all of this for sure, but it seems logical to me...

Hope something here helps

btw: I actually used the XMonitorBot tool to grab that info...

Interesting, thank you. I think it could help, but seems not to be always that way. I'll try some things...

I'm a graduate-level programmer, yet not too familiar with both the windows API and C++ for that matter. During reading the code I came across function calls which start with a double colon. Like:

return ::GetModuleHandle(_T("MPPOKER.EXE")) != NULL;

Could anyone enlighten me what that means? [removing the colons does not break the application]

Great article

James, first - thanks! This is exactly what I've been searching for. It was easy to set up and ran exactly as you said it would.

Did you ever cover the duplicate elimination approach that you mentioned on 7/14?

The users of this forum are very helpful. It took me a 10 minutes to download and install the boost stuff, and get this thing working.

The following posts were all I needed...

1) BOOST INSTALLER -> popo on 7/6/2008 12:33:20 PM 2) VS doesn't find boost header files -> JeremyX on 7/6/2008 4:32:37 PM 3) LINKing boost libs fails -> JeremyX on 7/11/2008 8:25:30 PM

Search for those three posts and you should have no problem.

Thanks everyone!

PokerTime does not accept US accounts - is there a way to create an account for PLAY MONEY only, or does everyone have to have a house in Europe wink wink

Nice breakdown on creating a foldbot, thanks for yet another highly interesting article on creating an online poker bot! :)

Hi , i'm ate very starting level of c++ programming at so low level so maybe i will make a stupid question.... From what i can undestand i can say that the MFCview starts the process of dllinjection and api hooking but i don't understand where is delcared wich dll will be injected ( in our case XPokerBot.Hook.dll )???

Ok now i found it .... there is the includsion of XPokerBot.Hook.h ... And if i would like to use this dll from c# ? Should i write a dll just to be used in conjunction with c#?

As a Java programmer, with ZERO Visual Studio or C++ experience, I'm struggling (if that's what you call 2.5 hours of trying everything I can think of) to do what Robert posted on 7/14/08.

Can someone tell me what (*lprc) is referring to? My guess is that lprc is a pointer to something. The question is what is that something?

Which kind of object is he using that has a .top, .bottom, .left and .right that I can use?

I'd really appreciate it if someone would post a snippet of code to eliminate the duplicates in Full Tilt Chat.

I plan on sending the data to a seperate Java application. It'll be in the Java app that I do all of my "fun stuff" - I just want to eliminate the dupicates in the C++ code before sending it to the Java app for processing.

Thanks in advance

Built the bot at work but it run under

OS Name Microsoft Windows XP Professional
Version 5.1.2600 Service Pack 2 Build 2600

Any idea what tweak it needs?

I get these two errors: X 15 fatal error LNK1104: cannot open file 'libboostregex-vc90-mt-gd-137.lib X 16 fatal error LNK1104: cannot open file '..\bin\XPokerBot.Hook.lib'

How do I fix this

Someone please help me.

Error 1 fatal error LNK1104: cannot open file 'libboostregex-vc90-mt-gd-136.lib' Error 2 fatal error LNK1104: cannot open file '..\bin\XPokerBot.Hook.lib'

I have built boost to get rid of its errors, I have Visual Studio Pro, I have built detours through the VS command prompt <<

f:\Program Files\Microsoft Visual Studio 9.0\VC>nmake "F:\Program Files\Microsof t Research\Detours Express 2.1\makefile"

Microsoft (R) Program Maintenance Utility Version 9.00.21022.08 Copyright (C) Microsoft Corporation. All rights reserved.

'"F:\Program Files\Microsoft Research\Detours Express 2.1\makefile"' is up-to-da te

>>

I am still getting the errors after doing all of that and cant think of anything else to do please help.

Can anyone confirm me that this code is still working today ? The bot is running but when I join a table, nothing happens, the Fold Bot GUI is empty.

James, great work !! Thanks

yes it still works. just tested it.

Hi!

while compiling project I had some mistake: 1)cannot open file include: regex.hpp

would you be so kind to explaine me how to solve this problem? thanx ^^

It's amazing! We almost wrote the bot for the other poker room. And now I find people who does the same things. I'll test FoldBot today.

Nice Series. Does anyone have a copy of the boost version boost133_1. I would love to try this out and see it work. anyone please. I tried the boost.org site and it gives me an error message.

Could someone help?

Can anybody confirm that this app is still working ? The bot is running but the Fold Bot GUI is empty - I have opened 1-3 tables.

Great pictures well done!

OK for those that want explicit instructions to get it to build:

(I am using VS2008 pro on vista) Step1: go to http://www.boostpro.com/products/free and install latest version of boost. I wasn't sure which variants to choose so just selected all of them.

Step2: open solution with VS

Step3: Select Tools->Options... on left-hand side select "Projects and Solutions", then "VC++ Directories".

Step4: Under "Show directories for:" dropdown list select "Include files" and add the following two lines: C:\Program Files\boost\boost137 C:\Program Files\boost\boost137\boost (may vary depending on library version)

Step5: Under "Show directories for:" dropdown list select "Library files" and add the following:

           C:\Program Files\boost\boost_1_37\lib      (again, may vary slightly)

Step6: Build

"So I just got started on this and I am running into this: 2>Linking... 2>LINK : fatal error LNK1104: cannot open file '..\bin\XPokerBot.Hook.lib'

and

1>LINK : fatal error LNK1104: cannot open file 'libboostregex-vc90-mt-gd-135.lib'"

(just-starting on 8/20/2008 9:11:12 AM)

Step5 above solves the second issue. To solve the first, simple re-extract the bin files from the XPokerBot.zip file and rebuild.

"Can anybody confirm that this app is still working ? The bot is running but the Fold Bot GUI is empty - I have opened 1-3 tables."

(pepe on 2/2/2009 1:07:16 PM)

I am running on vista and I also have this issue. James you mention that "This version of the bot has only been tested on Windows XP, so if you're running Vista or Windows 2000, you might have to do a little tweaking."

Has anyone worked out specifically what this tweaking is? Thanks :)

Nice job!

We did something similar here: http://www.pokerbot-smart.com/

[b]* EMPTY TABLE SOLUTION *[b]

I have worked out why the information doesn't populate the app window and why it doesn't fold. You will be pleased to hear it is an easy fix:

Step 1: (PokerTimeCaptionDecoder::decode method)

replace [i]boost::regex regA("^Poker\ Time\ \-\ (?:[i] etc... with [i]boost::regex regA("^PokerTime\.net\ \-\ (?:[i] etc...

..the rest of the regex is correct.

Step 2: (CXPokerBotMfcViewDlg::OnCopyData method)

replace [i]int itemIndex = FindListItemByParam((HWND)pCopyDataStruct->dwData);[i] with [i]int itemIndex = FindListItemByParam(hWnd);[i]

..this just ensures the table info is deleted when you leave a table.

[b]NB[b] Clearly these changes are independent of the OS you are running and I am running Vista. I can therefore confirm the bot still works on both XP [b]and[b] Vista. Kudos to James. Enjoy.

[b]* EMPTY TABLE SOLUTION *[/b]

I have worked out why the information doesn't populate the app window and why it doesn't fold. You will be pleased to hear it is an easy fix:

Step 1: (PokerTimeCaptionDecoder::decode method)

replace [i]boost::regex regA("^Poker\ Time\ \-\ (?:[/i] etc... with [i]boost::regex regA("^PokerTime\.net\ \-\ (?:[/i] etc...

..the rest of the regex is correct.

Step 2: (CXPokerBotMfcViewDlg::OnCopyData method)

replace [i]int itemIndex = FindListItemByParam((HWND)pCopyDataStruct->dwData);[/i] with [i]int itemIndex = FindListItemByParam(hWnd);[/i]

..this just ensures the table info is deleted when you leave a table.

[b]NB[/b] Clearly these changes are independent of the OS you are running and I am running Vista. I can therefore confirm the bot still works on both XP [b]and[/b] Vista. Kudos to James. Enjoy.

[b]DETOURS HELP[/b]

I have had a nightmare of a day trying to get my project to build but have finally worked it out and so thought I would share my solution to save anyone else this time.

[b]To Build..[/b]

i) Download installer [url=http://research.microsoft.com/en-us/downloads/d36340fb-4d3c-4ddd-bf5b-1db25d03713d/default.aspx]here[/url].

ii) Instructions say to run 'nmake' but if you use the standard command prompt to do this you won't have the right environment variables. Use VS's command prompt instead (Tools->Visual Studio 2008 Command Prompt).

NB if you are using VS2008 you will still run into some errors - see [url=http://social.msdn.microsoft.com/forums/en-US/vcgeneral/thread/fcb5a809-5404-481f-82c0-40ffa6f58c9b/]this[/url] for the required fixes.

iii) Build should now succeed and therefore you should have the required [i]detours.lib[/i] and [i]detoured.lib[/i] files in the lib directory. Done! :)

[b]Integration with VS (2008)[/b]

i) Select [i]Tools->Options[/i].

ii) Select [i]Projects and Solutions->VC++ Directories[/i] (on the left).

iii) Select [i]Include files[/i] from the [i]Show directories for:[/i] drop-down list and add the following line, (may be slightly different on your machine), and the select OK.

C:\Program Files\Microsoft Research\Detours Express 2.1\include

iv) Right-click on the project in [i]Solution Explorer[/i] and select [i]Properties[/i] at the bottom.

v) Select [i]Configuration Properties->Linker->General[/i] (on the left) and add the following line to the [i]Additional Library Directories[/i] field:

"C:\Program Files\Microsoft Research\Detours Express 2.1\lib"

vi) Select [i]Configuration Properties->Linker->Input[/i] and add [i]detours.lib detoured.lib[/i] to the [i]Additional Dependencies[/i] field and finally select OK.

vii) Ensure your .cpp file has the following line:

include <detours.h>

You should now be able to call detours methods without any compilation errors! Phew..

It would have been nice if someone at any point in this thread corrected Fred on 7/2/2008 8:03:04 PM. The "/export:NullExport" text does NOT get written in "mydll Properties, Configuration Properties, Linker, General, Output File" textbox - that is for the name of your compiled DLL. This explains why popo and a small army of Anons could not find their compiled DLLs. The "/export:NullExport" text should be written in "mydll Properties, Configuration Properties, Linker, Command Line, Additional Options" textbox.

Some of the comments are a little over my head, but this isn't your regular blog audience, I guess.

James,

Is there a particular reason you choose to use a CBT hook as opposed to spawning a remote thread in the poker client's process to call LoadLibraryEx?

Thanks, Marc.

[quote] But in practice, you really want to hook the poker client at load time and suspend it, getting prima nocta on the target process so your code always runs first. In that case neither CBT Hooks nor CreateRemoteThread are really ideal. [/quote]

Any hints about what I should look into in order to achieve that? My initial guess would be to spawn a poker client process in suspended mode, and hook it at that point, but I bet there is a better way. BTW, I love the use of [url=http://www.urbandictionary.com/define.php?term=Prima%20Nocta] prime nocta[/url] in this context :-)

Hi James,

A question concerning the approach of subclassing the chat window. If we attach the application to multiple windows, specially when we are working with two clients using the same software, there exists race conditions on the static callback for the EDITSTREAM callback, in your approach you've used a static HWND to save the handle to the chatbox every time you use the callback. However, when multiple windows access this callback at the same time, it would've overwritten the value of HWND and "could" proxy the intercepted message to the client app as part of the wrong window?

Is there an easy way around this? I've been playing with trampoline functions to map the callback to a non-static member function on the class itself, however inside an EDITSTREAMCALLBACK we have no detail about the window itself, nor can we pass this information to the function?

Clearly a bit early in the morning for me, ignore the working with two clients part, that would be impossible :P seeing as we are in different address spaces. But hopefully you catch my drift...

Hi James, can I have your e-mail adress or can you contact me on this one a-x-c@hotmail.fr ?

I've some questions and ideas about the poker bot... So is it possible to talk with you by e-mail ?

(sorry for my faults, I'm french ^^)

Thanks, Alex

Can someone verify the program still works? Built the solution, ran the exe, launched PokerTime, sat down, lists the tables I'm at, but doesn't see the hole cards or fold them during a hand. I'm playing 1 table, large view, with the Full Detail chat maximized on the right side. Any ideas?

CJ: My program also stopped working sometime in the past few days. Like you said, windows are recognized but it seems that no messages are recieved via the chat window. Something funky is happening in MyRichWndProc where it doesn't go ahead and call MyEditStreamCallback... Will try to look into it tomorrow.

Looks like Pokertime's been on the agressive lately. The EM_STREAMIN message which is normally 1097 is now 1092, but simply looking for 1092 instead doesn't seem to fix the problem...

that is the point of the OO design. my implementation uses the Windows API to switch between windows as required to make actions on multiple tables

Okay, I successfully compiled, got my PokerTime Account, and nothing. I dont think Im launching the application correctly. I can find an executable /bin/XPokerBot.MfcView.exe that produces a gui and will populate some fields (table names) when I am on the PokerTable site, but the autofolding that I expect does not occur. 1. how to correctly launch the app? 2. does it matter that PokerTable message is "...15 seconds to act" and not "...10 seconds to act" as per readme file that came with code?

Hopefully someone is still reading this post and knows what Im talking about... Thanks, Craig

I have the same problem as above poster. How do we remedy this?

Hey, I haven't programmed since I was a sophmore in college (1998) when I was programming in C++. So I don't remember a lot, and dont know a lot of the newer windows stuff, but I'm getting back into it. A couple things: 1. Is this article finished or will some more stuff be put out on this? 2. I was thinking about some ways to get around the poker site finding your program and freezing your account. A couple ideas I'm not sure whether they would work or not, but could you write a program that hooks the poker client, and just read the whole cards, board cards, evaluate your hand, and maybe give pot odds, something similar to some approved programs, then write the bot AI and automation stuff into a program that hooks into the first program, then hide that program with a rootkit? Another option would maybe be to hook into an approved poker program that reads the cards and get the information needed from that program, then you aren't hooking into the poker client at all. Not sure if that would work or not, but am curious about your opinions. Thanks and great article.

Hi everyone,

I would like to congratulate James Devlin because your web site is really amazing. From the technical point of view, it is 7 stars, not 5. It is outstanding.

Right now, I would like to find someone to cooperate with me on a poker software project whose goal is to improve SNG table selection (Pokerstars). As James Devlin states, table selection is very, very important and I need to improve that area. What I am looking for is someone that is able to develop a software that retrieves the content of any listbox on Pokerstars. I have already developed all the software needed to evaluate if we should or should not register on each specific tournament taking into account some statistic criteria ....

If you are interested, please post your email on a comment and I will contact you afterward.

Hey Poker of Aces, I work on another Poker project. I focus on cash games. But maybe we could exchange some knowledge and how to investigate new Poker rooms.

Feel free to write me an email: Klabautermann176@web.de

Cool pictures its is really fun.

Hi, I tried to use detours with PokerTime. It works, meaning that I can see chat text and so on. But I cannot see the text that is being printed on a game table. Could you comment on that: what do they use to draw text there?

Hi!

I'm trying to follow your tutorial, when I compile the code under Windows 7 and VS2008 it has one error:

Error 1 fatal error LNK1104: cannot open file 'libboostregex-vc90-mt-gd-142.lib' XPokerBot.Hook XPokerBot.Hook

Before it I had problems with regex but I installed boost, added the reference and put:

include <boost\regex.hpp>

and no more problems with this

Thanks for sharing about the ingredients of online poker bot, so helpful it is. Online poker games is really a new step forward for science. Now [url=http://www.pokerrakeback.com/]rakeback poker[/url] games is the newest addition of poker industry. In this field a top rated site offers an unbelievable [url=http://www.pokerrakeback.com/]rakeback[/url] for all of us. Just enjoy it!

Hi all, very interesting and great feedback. I'm only at the Foldbot stage. And, I can't get it to work. It built properly and runs but it doesn't appear to interact with the PokerTime tables. I open a table and nothing happens with the app, I sit down and nothings happens either. I'm using XP Media Center SP 3. Using VS 2008 Full 90 day trial. Today is Feb. 17, 2010. Has anyone had this work for them recently and if so what are the tricks? Thanks.

Hi DBH,

I have the same problem; no population of de GUI-fields at all. I am using Vista, MVS2008, detours ex2.1, boost142.

  • Boost build and tested
  • Detours build and tested
  • XPokerbot succesfull build
  • replaced; boost::regex regA("^Poker\ Time\ with boost::regex regA("^PokerTime\.netCan someone confirm the app is still running today on pokertime? thx

Hi,

I'm a bit late to the game here, and this post seems to be infested by spam, but I wonder if someone could give me a hand with getting a Hook to work, I am having problems.

I am trying to make a basic console application install a hook. I can check to see if it has worked by putting a breakpoint in the CBTProc function, and as it is, it seems the dll is not being called at all.

Running the code supplied in this post, the CBTProc function is called over and over once the hook has been installed. I tried to cut out the GUI by using the following code:

int _tmain(int argc, _TCHAR* argv[]){ bool bbbb = InstallHook(); Sleep(2000); return 0; }

Short I know, but I am just trying to get it to do anything at all.

I know that this code is installing the Hook correctly (bbbb returns true, and a breakpoint inside the InstallHook function is hit) but the CBTProc function is not called at all. By comparison, the call in the supplied GUI code is buried in the function: BOOL CXPokerBotMfcViewApp::InitInstance()

This code runs fine - it installs the hook, and the CBTProc function gets multiple hits.

I have made no other changes to the code, all I am trying to do is set it up so that the hook dll sends its information to a little program running in console rather than a gui (I am planning to use networking/sockets and stuff.)

I am still learning C++, and the Windows API is new to me. Could someone explain where I am going wrong here? Why does it seem that the hook is being installed, by not maintained? What do I have to do to get the hook working when installed from a console application?

Many thanks, Oliver

The foldbot is not working for me either. Builds ok but no tables are added to the gui. Windows XP SP3. VS2008 trial. Please heeeeeelp!

ASP.NET (prerequisite for installing Visual Studio 2008, as instructed)

Went to IIS Manager as the READ ME instructed on the Visual Studio 2008... But could not "ENABLE ASP.NET 2.0.5727" as instructed because I could not find any ASP.NET to enable. Am I missing something?

How do I enable ASP.NET 2.0.5727?

Please advise. Much thanks.

I can not capture the PokerStar chat windows or FullTilt. chat windows Does anyone know how?

This works well - it installs the hook, and the function is CBTProc multiple occurrences. logo design

Your blog provided us with valuable information to work with. Each & every tips of your post are awesome. Thanks a lot for sharing. Keep blogging.

Hi folks, I facing the problem that SendInput does not working with PokerStars anymore. Any ideas?

Can someone confirm that this is still working? Installed boost Builded the application Joined table

And then, nothing is displayed in the fields.

Anyone?

Right now, I would like to find someone to cooperate with me on a poker software project whose goal is to improve SNG table selection (Pokerstars). As James Devlin states, table selection is very, very important and I need to improve that area. What I am looking for is someone that is able to develop a software that retrieves the content of any listbox on Pokerstars. I have already developed all the software needed to evaluate if we should or should not register on each specific tournament taking into account some statistic criteria placement papers of TCS

This simple online poker bot is awesome. Thank you for sharing it! adjustable beds

Hi,

I've built the FoldBot, but am having a problem. I run it, then run PokerTime, but PokerTime immediately crashes. It asks me if I want to debug it, so I do and get the error message:

The thread 'Win32 Thread' (0x13c4) has exited with code 0 (0x0). Unhandled exception at 0x00348552 (XPokerBot.Hook.dll) in MPPoker.exe: 0xC0000005: Access violation writing location 0x76dc2d12.

That corresponds to this line:

if (d.decode(szTemp, *pTableInfo))

which is line 73 in PokerTimePokerClient.cpp

Any ideas?

Use the form below to leave a comment.






Subscribe to Coding the Wheel over email or through any RSS reader. Coding the Wheel has been published since 2008.

Home | About | Contact | Subscribe Copyright © 2011 | All Rights Reserved