How to find paltalk commands at runtime.

Viewing 2 posts - 1 through 2 (of 2 total)
  • Author
    Posts
  • #191185
    Chike
    Member

    As a follow-up to problem locking the mic using code here is a code example of one way it can be done:

    #include
    #include
    #include
    
    struct command {
    const char *text; // in: text to look for
    int code; // out: command number
    };
    
    command my_commands[] = {
    { "lock mic", 0},
    { "push to talk", 0},
    { "console", 0},
    { "send a file", 0},
    { "all hands", 0},
    { "view webcam", 0},
    { "red dot", 0},
    { NULL, 0} // stop when null
    };
    
    struct fill_cmd_param {
    command *commands;
    int nfound;
    };
    
    static void fill_commands(HMENU hMenu, fill_cmd_param *fcpp);
    
    int main(int argc, TCHAR* argv[])
    {
    HWND hwnd = FindWindow("DlgGroupChat Window Class", NULL);
    
    if (hwnd == NULL)
    return 1;
    
    HMENU hmenu = GetMenu(hwnd);
    
    if (hmenu == NULL)
    return 2;
    
    fill_cmd_param fcp = {my_commands, 0};
    
    fill_commands(hmenu, &fcp);
    if (fcp.nfound > 0) {
    printf("found %d commands:n", fcp.nfound);
    for (command *cmd = my_commands; cmd->text != NULL; ++cmd) {
    if (cmd->code != 0) {
    printf(" %s:t%dn", cmd->text, cmd->code);
    } else {
    printf(" %s:t(not found)n", cmd->text);
    }
    }
    }
    return 0;
    }
    
    // find substring sub in string str, case-insensitive
    static
    const char *strstri(const char *str, const char *sub)
    {
    size_t str_len = strlen(str);
    size_t sub_len = strlen(sub);
    
    if (sub_len > str_len)
    return NULL;
    
    const char *end = str + str_len - sub_len + 1;
    
    for (const char *s = str; s != end; ++s) {
    if (toupper(*s) == toupper(*sub) ) {
    const char *ssub = &sub[1];
    for (const char *ss = &s[1];
    *ssub && (toupper(*ss) == toupper(*ssub)); ++ss)
    ++ssub;
    if (*ssub == '�')
    return s;
    }
    }
    return NULL;
    }
    
    // walk through all menu items/sub menues and fill the
    static
    void fill_commands(HMENU hmenu, fill_cmd_param *fcpp)
    {
    if (hmenu == NULL)
    return;
    
    int nitems = GetMenuItemCount(hmenu);
    
    for (int i = 0; i < nitems; ++i) {
    UINT mstate = GetMenuState(hmenu, i, MF_BYPOSITION);
    
    if (mstate & MF_POPUP) {
    // search sub menu - recursive
    fill_commands(GetSubMenu(hmenu, i), fcpp);
    } else if (! (mstate & (MF_BITMAP | MF_OWNERDRAW))){ // imply MF_STRING
    char str[64];
    if (GetMenuString(hmenu, i, str, sizeof(str), MF_BYPOSITION) > 0) {
    // match with one of our comma
    for (command *cmd = fcpp->commands; cmd->text != NULL; ++cmd) {
    if (strstri(str, cmd->text) != NULL) { // match
    // get menu cmd
    int code = GetMenuItemID(hmenu, i);
    if (cmd->code != 0) { // duplicate - which one to choose?
    fprintf(stderr, "%s: %d -> %dn", cmd->text, cmd->code, code);
    } else {
    cmd->code = code;
    ++fcpp->nfound;
    }
    break;
    }
    }
    }
    }
    }
    
    }

     

    output:
    found 6 commands:
    lock mic: 33340
    push to talk: 33343
    console: 32998
    send a file: 33231
    all hands: 32995
    view webcam: 33163
    red dot: (not found)

    #191186
    Chike
    Member

    One problem with that code is that the room menues do not have all the commands you may want to look for.
    So here’s a nother way to do it by reading the menu resources.
    I excluded the some of the functions you can find in the 1st post.

    struct command {
    
    const char *text;
    
    int code;
    
    };
    
    command my_commands[] = {
    
    { "lock mic", 0},
    
    { "push to talk", 0},
    
    { "console", 0},
    
    { "send a file", 0},
    
    { "all hands", 0},
    
    { "view webcam", 0},
    
    { "red dot", 0},
    
    { "bounce", 0},
    
    { NULL, 0} // stop when null
    
    };
    
    static int find_commands(const char *fname, command *commands);
    
    int main(int argc, TCHAR* argv[])
    
    {
    
    HWND hwnd = FindWindow("SEINFELD_SUPERMAN", NULL);
    
    if (hwnd == NULL)
    
    return 1;
    
    DWORD dwprocessid;
    
    // get process id - needed for OpenProcess
    
    if (GetWindowThreadProcessId(hwnd, &dwprocessid) == 0)
    
    return 2;
    
    HANDLE hprocess = OpenProcess(
    
    // access needed to enum and read resources
    
    PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
    
    // don't care about handle inharitence
    
    FALSE,
    
    dwprocessid);
    
    if (hprocess == NULL)
    
    return 3;
    
    char fname[MAX_PATH];
    
    // get paltalk process exectutable path
    
    int fnamelen = GetModuleFileNameEx(hprocess, NULL, fname, sizeof(fname));
    
    if (fnamelen > 0) {
    
    int n = find_commands(fname, my_commands);
    
    if (n > 0) {
    
    printf("found %d commands:n", n);
    
    for (command *cmd = my_commands; cmd->text != NULL; ++cmd) {
    
    if (cmd->code != 0) {
    
    printf("t%s:t%dn", cmd->text, cmd->code);
    
    } else {
    
    printf("t%s:t(not found)n", cmd->text);
    
    }
    
    }
    
    }
    
    }
    
    CloseHandle(hprocess);
    
    return (fnamelen > 0) ? 0 : 4;
    
    }
    
    // doing it the easy way - too lazy to parse menu resource structure
    
    // loads each menu resource and send it to fill_commands
    
    static
    
    BOOL CALLBACK MyEnumResProc(
    
    HMODULE hmodule,
    
    LPCTSTR lpsztype,
    
    LPTSTR lpszname,
    
    LONG_PTR lparam)
    
    {
    
    if (lpsztype == RT_MENU) { // sanity
    
    HMENU hmenu = LoadMenu(hmodule, lpszname);
    
    if (hmenu != NULL) {
    
    fill_commands(hmenu, ((fill_cmd_param*)lparam));
    
    DestroyMenu(hmenu);
    
    }
    
    }
    
    return TRUE;
    
    }
    
    static
    
    int find_commands(const char *fname, command *commands)
    
    {
    
    // load library as resource library without calling startup code
    
    HMODULE hmodule = LoadLibraryEx(fname, NULL, LOAD_LIBRARY_AS_DATAFILE);
    
    if (hmodule != NULL) {
    
    fill_cmd_param fcp = {commands, 0};
    
    // enumerate menu resources
    
    EnumResourceNames(hmodule, RT_MENU, MyEnumResProc, LONG_PTR(&fcp));
    
    FreeLibrary(hmodule);
    
    return fcp.nfound;
    
    }
    
    return 0;
    
    }

     

    output:
    view webcam: 33163 -> 32905
    send a file: 33231 -> 32902
    push to talk: 33343 -> 33343
    send a file: 33231 -> 33109
    push to talk: 33343 -> 33338
    lock mic: 33340 -> 33339
    view webcam: 33163 -> 32905
    send a file: 33231 -> 32902
    view webcam: 33163 -> 32905
    bounce: 32947 -> 32947
    red dot: 32946 -> 32946
    view webcam: 33163 -> 32905
    send a file: 33231 -> 32902
    found 8 commands:
    lock mic: 33340
    push to talk: 33343
    console: 32998
    send a file: 33231
    all hands: 32995
    view webcam: 33163
    red dot: 32946
    bounce: 32947

    There are some duplicates, part are the same codes, others differ.
    I haven’t tested to see if all duplicates work or which does or doesn’t.

Viewing 2 posts - 1 through 2 (of 2 total)
  • You must be logged in to reply to this topic.