Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

synchapi event handler? #214

Open
Mika56 opened this issue Dec 30, 2024 · 1 comment
Open

synchapi event handler? #214

Mika56 opened this issue Dec 30, 2024 · 1 comment

Comments

@Mika56
Copy link

Mika56 commented Dec 30, 2024

Hello,

I'm trying to use a DLL that was provided to us by an external entity. I'm by no mean a C developer, but I've dug into the source however I could.

The DLL exposes a few methods, most of which are "async compatible". The last argument is a HANDLE hEvent. When unset, the method works in synchronous mode, and this works ok for me.
Now I want to use this async feature. Digging into the source code, it looks like setting a hEvent does this:

  1. Use _beginthreadex to create a new thread (https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/beginthread-beginthreadex?view=msvc-170)
  2. On that thread, wait for the result
  3. Once a result is available, call SetEvent (https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-setevent)

SetEvent expects a HANDLE, which can be created from CreateEvent, and then waited with WaitForSingleObject.

I've looked around Koffi source code, and while I found references to CreateEvent and WaitForSingleObject, they did not seem to be related to Koffi.
Koffi callbacks don't seem to be working in that case either.

Can someone point me in the right direction? Or does this need an evolution of Koffi?

@Mika56
Copy link
Author

Mika56 commented Dec 30, 2024

I can actually use CreateEventA and WaitForSingleObject directly from kernel32.dll:

koffi.alias('LPCSTR', 'const char*');
koffi.alias('DWORD', 'unsigned long');
koffi.alias('LPVOID', 'void*');
koffi.pointer('HANDLE', koffi.opaque());

const kernel32 = koffi.load('kernel32.dll');
koffi.struct('SecurityAttributes', {
    nLength: 'DWORD',
    lpSecurityDescriptor: 'LPVOID',
    bInheritHandle: 'bool',
});

enum waitStatus {
    abandonned = 0x00000080,
    signaled = 0x00000000,
    timeout = 0x00000102,
    failed = 0xFFFFFFFF,
}

const createEventA = kernel32.func('CreateEventA', 'HANDLE', ['SecurityAttributes*', koffi.types.bool, koffi.types.bool, 'LPCSTR']);
const waitForSingleObject = kernel32.func('WaitForSingleObject', 'DWORD', ['HANDLE', 'DWORD']);

const cardStatusBuffer = Buffer.allocUnsafe(koffi.sizeof('OmcrCardStatus'));
const event = createEventA(null, true, false, null);
monitorCardStatus(device.pointer, 90, cardStatusBuffer, event);

const interval = setInterval(() => {
    const waitResult = waitForSingleObject(event, 0) as waitStatus;
    switch(waitResult) {
        case waitStatus.timeout:
            // Since we're waiting for 0 seconds, timeout means not signaled yet
            return;
        case waitStatus.abandonned:
            reject('Wait event was abandoned');
            clearInterval(interval);
            return;
        case waitStatus.failed:
            reject('Unable to wait for event');
            clearInterval(interval);
            return;
        case waitStatus.signaled:
            // We were signaled, we should now have data
            clearInterval(interval);
            const cardStatus = koffi.decode(cardStatusBuffer, 'OmcrCardStatus');
            resolve(cardStatus);
            return;
    }
}, 100);

Keeping this open to see if I'm making things more complicated than needed, or if Koffi should support events natively

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant