Home > Software design >  Use pointers in c
Use pointers in c

Time:09-07

I need to use "CreateTimerQueueTimer" to create a timer.

The parameter must be pass as pointer.

Here my code:

void sendKey(int vk, ) {

    KEYBDINPUT  kb = { 0 };
    INPUT       Input = { 0 };
    int scan = MapVirtualKey(vk, 0);

    /* Generate a "key down" */
    kb.dwFlags = KEYEVENTF_EXTENDEDKEY;
    kb.wVk = vk;
    Input.type = INPUT_KEYBOARD;
    Input.ki = kb;
    Input.ki.wScan = scan;
    SendInput(1, &Input, sizeof(Input));

    /* Generate a "key up" */
    ZeroMemory(&kb, sizeof(KEYBDINPUT));
    ZeroMemory(&Input, sizeof(INPUT));
    kb.dwFlags = KEYEVENTF_KEYUP;
    KEYEVENTF_EXTENDEDKEY;
    kb.wVk = vk;
    Input.type = INPUT_KEYBOARD;
    Input.ki = kb;
    Input.ki.wScan = scan;
    SendInput(1, &Input, sizeof(Input));

    return;
}


void CALLBACK ProcessRequests(PVOID lpParameter, BOOLEAN TimerOrWaitFired)
{
    sendKey((int)lpParameter, true);

}


void myfunc()
{
    int VirtualKey=50;

    CreateTimerQueueTimer(&m_hTimer, nullptr, &ProcessRequests, &VirtualKey, 100, 0, WT_EXECUTEONLYONCE);
}

Inside "ProcessRequests" there is the function "sendKey" that accept integer as parameter but lpParameter is a pointer. How I can pass the value of "lpParameter" and convert it in integer ?

Thanks !

CodePudding user response:

There are two problems with this:

  1. lpParameter points to an int, but you're treating it as if it is an int
  2. The int pointed to by lpParameter is local to myfunc and therefore no longer exists by the time your timer fires and your callback gets called

The first issue is simple to solve, just change the way you interpret lpParameter:

void CALLBACK ProcessRequests(PVOID lpParameter, BOOLEAN TimerOrWaitFired)
{
    int* param = static_cast<int*>(lpParameter);
    sendKey(*param, true);
}

The latter issue is a bit tougher, and how you solve it will depend on your needs. Since it looks like these functions are all members of some class (based on the name of m_hTimer), you may want to store the key code as a class data member instead of a local variable in myfunc:

class MyClass
{
    int VirtualKey;

    // ...

    void myfunc()
    {
        VirtualKey = 50;  // set the class member instead of
                          // creating a local variable

        CreateTimerQueueTimer(
            &m_hTimer,
            nullptr,
            &ProcessRequests,
            &VirtualKey,
            100,
            0,
            WT_EXECUTEONLYONCE
        );
    }

    // ...
};

If the functions aren't part of a class or you don't want to keep any sort of global state that multiple calls to myfunc could interfere with, then another approach would be to dynamically allocate the parameter. Just remember to free it when ProcessRequests is done with it:

void CALLBACK ProcessRequests(PVOID lpParameter, BOOLEAN TimerOrWaitFired)
{
    int* param = static_cast<int*>(lpParameter);
    sendKey(*param, true);
    delete param;
}

void myfunc()
{
    int* VirtualKey = new int(50);

    CreateTimerQueueTimer(
        &m_hTimer,
        nullptr,
        &ProcessRequests,
        VirtualKey,  // NOTE: no &, VirtualKey is already a pointer
        100,
        0,
        WT_EXECUTEONLYONCE
    );
}

I would recommend the former approach if possible. It would be easy to create memory leaks if you forget to free the key code in some code path (i.e. if you later add code to cancel the timer before it runs).

CodePudding user response:

You are passing CreateTimerQueueTimer() an int* pointer that points to a local int variable, but then you are treating lpParameter in ProcessRequests() as-if it were the int value instead of the int* pointer that it really is.

Passing the int value into the callback is fine, but you need to pass th value type-casted to a pointer, eg:

void CALLBACK ProcessRequests(PVOID lpParameter, BOOLEAN /*TimerOrWaitFired*/)
{
    sendKey(static_cast<int>(reinterpret_cast<intptr_t>(lpParameter)), ...);
}

void myfunc()
{
    int VirtualKey = 50;

    CreateTimerQueueTimer(..., reinterpret_cast<void*>(static_cast<intptr_t>(VirtualKey)), ...);
}

Also, calling SendInput() 2 times with 1 INPUT at a time without any delay in between the calls is a logic bug in your code that will likely cause issues with the input queue. Since there is no delay in your code, you should instead call SendInput() 1 time with 2 INPUTs, eg:

void sendKey(int vk, ... ) {

    INPUT Inputs[2] = { };
    ...

    /* Generate a "key down" */
    Inputs[0].type = INPUT_KEYBOARD;
    Inputs[0].ki.dwFlags = ...;
    Inputs[0].ki.wVk = ...;
    Inputs[0].ki.wScan = ...;

    /* Generate a "key up" */
    Inputs[1] = Inputs[0];
    Inputs[1].ki.dwFlags |= KEYEVENTF_KEYUP;

    SendInput(2, Inputs, sizeof(INPUT));
}

CodePudding user response:

You can try conversion from void* to int* and then to int like so:

void CALLBACK ProcessRequests(PVOID lpParameter, BOOLEAN TimerOrWaitFired)
{
    sendKey(*(int*)lpParameter, true);
}
  • Related