Serial port reading in c, using WinApi functions; WaitCommEvent fails - c

I tried to write a small event-based application in C for serial port reading (sources below). My program is to use the WinApi functions. The comport.c has the functions written to handle COM-port (open, read, write), the utils.c has some helper functions.
My program produces always the following output:
COM1 is selected to be listened.
GetCommMask result: 0x00000029 (EV_RXCHAR: 0x0001, EV_CTS: 0x0008, EV_RLSD: 0x0020)
Press any key to proceed...
I/O is pending (WaitCommEvent)...
I/O is pending (WaitCommEvent)...
I/O is pending (WaitCommEvent)...
I/O is pending (WaitCommEvent)...
I/O is pending (WaitCommEvent)...
It seems, that the function WaitCommEvent fails, the GetLastError() gives back error 87 (I/O pending).
Please help me to find out what the problem is, which parameter is invalid? See below the code.
The main.c:
#include "stdafx.h"
#include "comport.h"
#include "utils.h"
#include <conio.h>
#define READ_BUFF_MAX_LENGTH 1024
int _tmain(int argc, _TCHAR* argv[])
{
DWORD dwEvtMask;
HANDLE hComPort;
OVERLAPPED oEventHandler;
int portNum;
DWORD readTotal;
BOOL bOverlappedPending = FALSE;
char readBuff[READ_BUFF_MAX_LENGTH];
if(2 > argc)
{
printf("Use the program: ZliFuerZlvbusInterface.exe XXX (where XXX is the number of com port), \r\ne.G. for COM1 -> ZliFuerZlvbusInterface.exe 1\r\n");
return 1;
}
else
{
portNum = atoi(argv[1]);
if(0 == IsValidComNumber(portNum))
{
printf("ERROR: COM port number %d is invalid (parsed from '%s').\r\n", portNum, argv[1]);
return 2;
}
else
{
printf("COM%d is selected to be listened.\r\n", portNum);
}
}
if(0 == CreateSerialConnection(&hComPort, &oEventHandler, portNum, 1200, 8, EVEN, STOP1))
{
return 3;
}
if(FALSE == GetCommMask(hComPort, &dwEvtMask))
{
printf("GetCommMask failed with error:\r\n");
PrintLastErrorText();
return 4;
}
else
{
printf("GetCommMask result: 0x%08X (EV_RXCHAR: 0x0001, EV_CTS: 0x0008, EV_RLSD: 0x0020)\r\n", dwEvtMask);
}
printf("Press any key to proceed...\r\n");
getch();
while(1)
{
if(0 != kbhit())
{
if(27 == getch()) // ESC pressed
{
printf("Key ESC pressed, exiting...\r\n");
break;
}
}
bOverlappedPending = FALSE;
readTotal = 0;
if(TRUE == WaitCommEvent(hComPort, &dwEvtMask, &oEventHandler))
{
if(dwEvtMask & EV_CTS) // Clear-to-send signal present
{
PrintCurrentDateTime();
printf("COM%d: Clear-to-send signal set\r\n", portNum);
}
if(dwEvtMask & EV_RLSD) // Data-carrier-detect signal present
{
PrintCurrentDateTime();
printf("COM%d: Data-carrier-detect signal set\r\n", portNum);
}
if(dwEvtMask & EV_RXCHAR) // Data received
{
ReadSerial(&hComPort, &oEventHandler, portNum, readBuff, READ_BUFF_MAX_LENGTH);
}
}
else
{
if(ERROR_IO_PENDING == GetLastError())
{
printf("I/O is pending (WaitCommEvent)...\r\n");
bOverlappedPending = TRUE;
}
else
{
printf("WaitCommEvent failed with error:\r\n");
PrintLastErrorText();
}
}
if(TRUE == bOverlappedPending)
{
if(FALSE == GetOverlappedResult(hComPort, &oEventHandler, &readTotal, TRUE))
{
printf("GetOverlappedResult failed with error:\r\n");
PrintLastErrorText();
}
}
}
CloseSerialConnection(&hComPort);
return 0;
}
The comport.c:
#include <stdio.h>
#include "comport.h"
#include "utils.h"
int IsValidComNumber(int com)
{
if ((com < 1) ||
(com > 256))
{
return 0;
}
return 1;
}
int IsValidBaud(int baud)
{
switch(baud)
{
case CBR_110:
case CBR_300:
case CBR_600:
case CBR_1200:
case CBR_2400:
case CBR_4800:
case CBR_9600:
case CBR_14400:
case CBR_19200:
case CBR_38400:
case CBR_56000:
case CBR_57600:
case CBR_115200:
case CBR_128000:
case CBR_256000:
{
return 1;
break;
}
default:
{
break;
}
}
return 0;
}
int IsValidBits(int bits)
{
if ((bits < 5) ||
(bits > 8))
{
return 0;
}
else
{
return 1;
}
}
int CreateSerialConnection(HANDLE* handle, OVERLAPPED* overlapped, int portNumber, int baud, int bits, enum ParType parity, enum StopType stopbits)
{
DCB dcb;
COMMTIMEOUTS timeouts;
TCHAR portVirtualFile[32];
// For serial port name this format must be used (as virtual file): "\\\\.\\COMx"
memset(portVirtualFile, 0, 32);
#ifdef _UNICODE
swprintf(portVirtualFile, 32, L"\\\\.\\COM%d", portNumber);
#else
sprintf_s(portVirtualFile, 32, "\\\\.\\COM%d", portNumber);
#endif
if(0 == IsValidBaud(baud))
{
printf("ERROR: Specified baud rate %d is invalid for serial connection to COM%d.\r\n", baud, portNumber);
return 0;
}
if(0 == IsValidBits(bits))
{
printf("ERROR: Specified number of data bits %d is invalid for serial connection to COM%d.\r\n", bits, portNumber);
return 0;
}
*handle = CreateFile(portVirtualFile, // Specify port device
GENERIC_READ | GENERIC_WRITE, // Specify mode that open device.
0, // the devide isn't shared.
NULL, // the object gets a default security.
OPEN_EXISTING, // Specify which action to take on file.
FILE_FLAG_OVERLAPPED, // Use overlapped I/O.
NULL); // default.
if(*handle == INVALID_HANDLE_VALUE)
{
printf("ERROR: Opening serial port COM%d failed\r\n", portNumber);
return 0;
}
if(FALSE == GetCommState(*handle, &dcb))
{
printf("ERROR: Getting current state of COM%d\r\n", portNumber);
PrintLastErrorText();
return 0;
}
memset(&dcb, 0, sizeof(dcb)); //zero initialize the structure
dcb.DCBlength = sizeof(dcb); //fill in length
dcb.BaudRate = baud; // baud rate
dcb.ByteSize = bits; // data size, xmit and rcv
dcb.Parity = parity; // parity bit
dcb.StopBits = stopbits; // stop bits
if(FALSE == SetCommState(*handle, &dcb))
{
printf("ERROR: Setting new state of COM%d failed.\r\n", portNumber);
PrintLastErrorText();
return 0;
}
if(FALSE == SetCommMask(*handle, EV_RXCHAR | EV_CTS | EV_RLSD))
{
printf("ERROR: Setting new COM MASK (events) for COM%d failed.\r\n", portNumber);
PrintLastErrorText();
return 0;
}
timeouts.ReadIntervalTimeout = MAXDWORD;
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.ReadTotalTimeoutConstant = 0;
timeouts.WriteTotalTimeoutMultiplier = 0;
timeouts.WriteTotalTimeoutConstant = 0;
if(FALSE == SetCommTimeouts(*handle, &timeouts))
{
printf("ERROR: Setting timeout parameters for COM%d failed.\r\n", portNumber);
PrintLastErrorText();
return 0;
}
(*overlapped).hEvent = CreateEvent(
NULL, // default security attributes
TRUE, // manual-reset event
FALSE, // not signaled
NULL // no name
);
if(NULL == overlapped->hEvent)
{
printf("ERROR: CreateEvent for COM%d failed.\r\n", portNumber);
PrintLastErrorText();
return 0;
}
// Initialize the rest of the OVERLAPPED structure to zero.
overlapped->Internal = 0;
overlapped->InternalHigh = 0;
overlapped->Offset = 0;
overlapped->OffsetHigh = 0;
return 1;
}
int CloseSerialConnection(HANDLE* handle)
{
if(FALSE == CloseHandle(*handle))
{
printf("ERROR: Cannot close handle 0x8.8%X\r\n", *handle);
PrintLastErrorText();
return 0;
}
*handle = NULL;
return 1;
}
int ReadSerial(HANDLE* handle, LPOVERLAPPED ov, int num, char* buffer, int max_len)
{
DWORD readTotal = 0;
if(FALSE == ClearCommError(*handle, NULL, NULL))
{
printf("ClearCommError failed with error:\r\n");
PrintLastErrorText();
return 0;
}
else
{
memset(buffer, 0, max_len);
if(FALSE == ReadFile(*handle, buffer, max_len, &readTotal, ov))
{
printf("ERROR: Reading from port COM%d failed\r\n", num);
if(ERROR_IO_PENDING == GetLastError())
{
printf("I/O is pending (ReadFile)...\r\n");
if(FALSE == GetOverlappedResult(*handle, ov, &readTotal, TRUE))
{
printf("GetOverlappedResult failed with error:\r\n");
PrintLastErrorText();
return 0;
}
}
else
{
PrintLastErrorText();
return 0;
}
}
else
{
PrintCurrentDateTime();
printf("Received %d characters on port COM%d: ", readTotal, num);
PrintBufferContent(buffer, readTotal);
}
}
return 1;
}
The utils.c:
#include <Windows.h>
#include <stdio.h>
#include "utils.h"
void PrintLastErrorText(void)
{
DWORD retSize;
LPTSTR pTemp = NULL;
retSize = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY, NULL, GetLastError(), LANG_NEUTRAL, (LPTSTR)&pTemp, 0, NULL);
if ((retSize > 0) &&
(pTemp != NULL))
{
printf("Last error: %s (0x%08X)\r\n", pTemp, GetLastError());
LocalFree((HLOCAL)pTemp);
}
}
void PrintCurrentDateTime(void)
{
SYSTEMTIME systime;
GetLocalTime(&systime);
printf("%04d.%02d.%02d %02d:%02d:%02d:%03d ", systime.wYear, systime.wMonth, systime.wDay, systime.wHour, systime.wMinute, systime.wSecond, systime.wMilliseconds);
}
void PrintBufferContent(char* buff, int len)
{
int i;
for(i = 0; i<len; i++)
{
printf("%02X ", buff[i]);
}
}

You're using the same OVERLAPPED structure for WaitCommEvent and ReadFile. Try using separate/independent OVERLAPPED for each.
UPDATE: Ignore that previous answer.
If your call to WaitCommEvent returns ERROR_IO_PENDING, you're not waiting for it to complete. Rather than loop around and call WaitCommEvent again, you need to wait for the operation to complete (typically via GetOverlappedResult).
You cannot have multiple pending asynchronous requests share a single OVERLAPPED structure. By looping and calling WaitCommEvent again after ERROR_IO_PENDING, that's exactly what's happening.

Related

Get mouse button state nonblocking linux

I'm trying to write a plugin for a game and I need to read the state of the mouse button and not block or "eat" the events. Directly reading /dev/input is not an options because of root access.
The closer I came to what I need is the following code:
#include <stdio.h>
#include <string.h>
#include <X11/Xlib.h>
int main (int argc, char **argv)
{
Display *display;
XEvent ev;
display = XOpenDisplay(NULL);
Window window = RootWindow(display, XDefaultScreen(display));
XSelectInput(display, window, ButtonPressMask | ButtonReleaseMask);
XGrabButton(display, Button1, AnyModifier, window, False, ButtonPressMask | ButtonReleaseMask, GrabModeSync, GrabModeAsync, None, None);
while(1) {
XAllowEvents(display, ReplayPointer, CurrentTime);
if(XCheckTypedEvent(display, ButtonPress ,&ev))
{
printf("Button pressed\n");
}
else if(XCheckTypedEvent(display, ButtonRelease ,&ev))
{
printf("Button relised\n");
}
}
return 0;
}
The problem is that by setting GrabModeSync and using XAllowEvents with ReplayPointer I am able to pass the event but I get the ButtonPress only. ButtonRelease is never captured but I need it. GrabModeAsync captures both events but "eats" the clicks.
Can anyone suggest a solution?
10x
For anyone who may stumble to this post while looking for solution on similar problem here is what worked for me.
#include <stdio.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/extensions/XInput2.h>
static void select_events(Display *dpy, Window win)
{
XIEventMask evmasks[1];
unsigned char mask1[(XI_LASTEVENT + 7)/8];
memset(mask1, 0, sizeof(mask1));
/* select for button and key events from all master devices */
XISetMask(mask1, XI_RawButtonPress);
XISetMask(mask1, XI_RawButtonRelease);
evmasks[0].deviceid = XIAllMasterDevices;
evmasks[0].mask_len = sizeof(mask1);
evmasks[0].mask = mask1;
XISelectEvents(dpy, win, evmasks, 1);
XFlush(dpy);
}
int main(){
Display *dpy;
XEvent ev;
XIEvent *xi_event;
XIRawEvent *xev;
XGenericEventCookie *cookie = &ev.xcookie;
dpy = XOpenDisplay(NULL);
select_events(dpy, DefaultRootWindow(dpy));
int count = 0;
while(1){
if (XCheckTypedEvent(dpy, GenericEvent ,&ev)){
if (cookie->type != GenericEvent ||
!XGetEventData(dpy, cookie)){
continue;
}
xi_event = (XIEvent *) cookie->data;
xev = (XIRawEvent *) xi_event;
switch (cookie->evtype) {
case XI_RawButtonPress:
printf("Button pressed %d %d\n", xev->detail, ++count);
break;
case XI_RawButtonRelease:
printf("Button released %d %d\n", xev->detail, count);
break;
}
XFreeEventData(dpy, cookie);
}
}
return 1;
}
Thanks for your solution but it heavily loads my processor. So I found how its done in xinput test command:
https://github.com/freedesktop/xorg-xinput/blob/master/src/test.c
#include "xinput.h"
#include <string.h>
#define INVALID_EVENT_TYPE -1
static int motion_type = INVALID_EVENT_TYPE;
static int button_press_type = INVALID_EVENT_TYPE;
static int button_release_type = INVALID_EVENT_TYPE;
static int key_press_type = INVALID_EVENT_TYPE;
static int key_release_type = INVALID_EVENT_TYPE;
static int proximity_in_type = INVALID_EVENT_TYPE;
static int proximity_out_type = INVALID_EVENT_TYPE;
static int
register_events(Display *dpy,
XDeviceInfo *info,
char *dev_name,
Bool handle_proximity)
{
int number = 0; /* number of events registered */
XEventClass event_list[7];
int i;
XDevice *device;
Window root_win;
unsigned long screen;
XInputClassInfo *ip;
screen = DefaultScreen(dpy);
root_win = RootWindow(dpy, screen);
device = XOpenDevice(dpy, info->id);
if (!device) {
fprintf(stderr, "unable to open device '%s'\n", dev_name);
return 0;
}
if (device->num_classes > 0) {
for (ip = device->classes, i=0; i<info->num_classes; ip++, i++) {
switch (ip->input_class) {
case KeyClass:
DeviceKeyPress(device, key_press_type, event_list[number]); number++;
DeviceKeyRelease(device, key_release_type, event_list[number]); number++;
break;
case ButtonClass:
DeviceButtonPress(device, button_press_type, event_list[number]); number++;
DeviceButtonRelease(device, button_release_type, event_list[number]); number++;
break;
case ValuatorClass:
DeviceMotionNotify(device, motion_type, event_list[number]); number++;
if (handle_proximity) {
ProximityIn(device, proximity_in_type, event_list[number]); number++;
ProximityOut(device, proximity_out_type, event_list[number]); number++;
}
break;
default:
fprintf(stderr, "unknown class\n");
break;
}
}
if (XSelectExtensionEvent(dpy, root_win, event_list, number)) {
fprintf(stderr, "error selecting extended events\n");
return 0;
}
}
return number;
}
static void
print_events(Display *dpy)
{
XEvent Event;
setvbuf(stdout, NULL, _IOLBF, 0);
while(1) {
XNextEvent(dpy, &Event);
if (Event.type == motion_type) {
int loop;
XDeviceMotionEvent *motion = (XDeviceMotionEvent *) &Event;
printf("motion ");
for(loop=0; loop<motion->axes_count; loop++) {
printf("a[%d]=%d ", motion->first_axis + loop, motion->axis_data[loop]);
}
printf("\n");
} else if ((Event.type == button_press_type) ||
(Event.type == button_release_type)) {
int loop;
XDeviceButtonEvent *button = (XDeviceButtonEvent *) &Event;
printf("button %s %d ", (Event.type == button_release_type) ? "release" : "press ",
button->button);
for(loop=0; loop<button->axes_count; loop++) {
printf("a[%d]=%d ", button->first_axis + loop, button->axis_data[loop]);
}
printf("\n");
} else if ((Event.type == key_press_type) ||
(Event.type == key_release_type)) {
int loop;
XDeviceKeyEvent *key = (XDeviceKeyEvent *) &Event;
printf("key %s %d ", (Event.type == key_release_type) ? "release" : "press ",
key->keycode);
for(loop=0; loop<key->axes_count; loop++) {
printf("a[%d]=%d ", key->first_axis + loop, key->axis_data[loop]);
}
printf("\n");
} else if ((Event.type == proximity_out_type) ||
(Event.type == proximity_in_type)) {
int loop;
XProximityNotifyEvent *prox = (XProximityNotifyEvent *) &Event;
printf("proximity %s ", (Event.type == proximity_in_type) ? "in " : "out");
for(loop=0; loop<prox->axes_count; loop++) {
printf("a[%d]=%d ", prox->first_axis + loop, prox->axis_data[loop]);
}
printf("\n");
}
else {
printf("what's that %d\n", Event.type);
}
}
}
int
test(Display *display,
int argc,
char *argv[],
char *name,
char *desc)
{
XDeviceInfo *info;
if (argc != 1 && argc != 2) {
fprintf(stderr, "usage: xinput %s %s\n", name, desc);
return EXIT_FAILURE;
} else {
Bool handle_proximity = False;
int idx = 0;
if (argc == 2) {
if (strcmp("-proximity", argv[0]) != 0) {
fprintf(stderr, "usage: xinput %s %s\n", name, desc);
return EXIT_FAILURE;
}
handle_proximity = 1;
idx = 1;
}
info = find_device_info(display, argv[idx], True);
if (!info) {
fprintf(stderr, "unable to find device '%s'\n", argv[idx]);
return EXIT_FAILURE;
} else {
if (register_events(display, info, argv[idx], handle_proximity)) {
print_events(display);
}
else {
fprintf(stderr, "no event registered...\n");
return EXIT_FAILURE;
}
}
}
return EXIT_FAILURE;
}

Access violation when getting network adapters with GetAdaptersAddresses in C

I don't know if the code from https://learn.microsoft.com/en-us/windows/desktop/api/iphlpapi/nf-iphlpapi-getadaptersaddresses is wrong but when I try to use it in my C project I keep getting the infamous
Access violation reading location 0xFFFFFFFFFFFFFFFF
I have tried increasing the buffer size but nothing seems to fix it. I think this happens after the first adapter is passed through the loop.
#include <stdio.h>
#include <string.h>
#include <locale.h>
#include <winsock2.h>
#include <iptypes.h>
#include <iphlpapi.h>
#include <windows.h>
#pragma comment(lib, "IPHLPAPI.lib")
#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
FILE* fLog = NULL;
void netinfo() {
PIP_ADAPTER_ADDRESSES pAddresses = NULL;
PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL;
DWORD dwRetVal = 0;
ULONG outBufLen = 15000;
ULONG iter = 0;
do {
pAddresses = (IP_ADAPTER_ADDRESSES*)MALLOC(outBufLen);
if (pAddresses == NULL) {
fwprintf(fLog, L"MALLOC error");
break;
dwRetVal = GetAdaptersAddresses(
AF_UNSPEC,
GAA_FLAG_INCLUDE_PREFIX,
NULL,
pAddresses,
&outBufLen
);
if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
FREE(pAddresses);
pAddresses = NULL;
fwprintf(fLog, L"GetAdaptersAddresses() error");
} else {
break;
}
iter++;
}
} while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (iter < 3));
wchar_t netAddressLog[256];
if (dwRetVal == NO_ERROR && pAddresses != NULL) {
pCurrAddresses = pAddresses;
while (pCurrAddresses) {
// this is where the debugger stops !!!
swprintf(netAddressLog, 256, L"Index: %u", pCurrAddresses->IfIndex);
fwprintf(fLog, netAddressLog);
pCurrAddresses = pCurrAddresses->Next;
}
} else {
fwprintf(fLog, L"GetAdaptersAddresses() error");
}
if (pAddresses) {
FREE(pAddresses);
}
}
int main(int argc, char **argv) {
errno_t error = _wfopen_s(&fLog, L"log.txt", L"a+");
netinfo();
fclose(fLog);
}
So, when trying to access pCurrAddresses->IfIndex it's where the program fails, after the first loop (in which it logs some weird large number for index). I am trying to compare mi slightly modified code to the one from MSDN but I can't figure it out.
I know my code needs better organization but for now this is a blocker
There is some problem in the while loop block:
do {
pAddresses = (IP_ADAPTER_ADDRESSES*)MALLOC(outBufLen);
if (pAddresses == NULL) {
fwprintf(fLog, L"MALLOC error");
break;
/* a } is missing here*/
dwRetVal = GetAdaptersAddresses(
AF_UNSPEC,
GAA_FLAG_INCLUDE_PREFIX,
NULL,
pAddresses,
&outBufLen
);
if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
FREE(pAddresses);
pAddresses = NULL;
fwprintf(fLog, L"GetAdaptersAddresses() error");
} else {
break;
}
iter++;
}
} while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (iter < 3));
The good corrected code could be:
do {
pAddresses = (IP_ADAPTER_ADDRESSES*)MALLOC(outBufLen);
if (pAddresses == NULL) {
fwprintf(fLog, L"MALLOC error");
break;
}
dwRetVal = GetAdaptersAddresses(
AF_UNSPEC,
GAA_FLAG_INCLUDE_PREFIX,
NULL,
pAddresses,
&outBufLen
);
if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
FREE(pAddresses);
pAddresses = NULL;
fwprintf(fLog, L"GetAdaptersAddresses() error");
} else {
break;
}
iter++;
} while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (iter < 3));

"cannot open port!" in a DLL project

I made a C Console Application in Visual Studio in order to access one of the COM ports with the following code and all went well.
#include <windows.h>
#include <stdio.h>
#include <conio.h>
/*DWORD dwBytesWrite = 25;
WriteFile(hSerial, "LOOOOOL", n, &dwBytesWrite, NULL);*/
/*
int main(void)
{
int n = 25;
char szBuff[25 + 1] = { 0 };
HANDLE hSerial;
DCB dcbSerialParams = { 0 };
COMMTIMEOUTS timeouts = { 0 };
DWORD dwBytesRead = 25;
dcbSerialParams.DCBlength = sizeof(DCB);
hSerial = CreateFile("COM6",
GENERIC_READ | GENERIC_WRITE,
0,
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0);
if (hSerial == INVALID_HANDLE_VALUE)
{
if (GetLastError() == ERROR_FILE_NOT_FOUND)
{
puts("cannot open port!");
return;
}
puts("invalid handle value!");
return;
}
if (!GetCommState(hSerial, &dcbSerialParams))
{
puts("error getting state");
return;
}
dcbSerialParams.BaudRate = CBR_9600;
dcbSerialParams.ByteSize = 8;
dcbSerialParams.StopBits = ONESTOPBIT;
dcbSerialParams.Parity = NOPARITY;
if (!SetCommState(hSerial, &dcbSerialParams))
{
puts("error setting port state");
return;
}
timeouts.ReadIntervalTimeout = 30;
timeouts.ReadTotalTimeoutMultiplier = 100;
timeouts.ReadTotalTimeoutConstant = 100;
if (!SetCommTimeouts(hSerial, &timeouts))
{
puts("timeouts setting fail!");
}
while (1){
if (!ReadFile(hSerial, szBuff, n, &dwBytesRead, NULL)){
puts("serial read error fail!");
return;
}
else
{
printf("%s\n", szBuff);
}
}
getchar();
return 0;
}
Now I needed to make a DLL project and it gave me the following error: "cannot open port!"
Any idea why?
Thanks

DBusWatch and DBusTimeout examples

I need to write an application in C for asynchronous sending and reading messages on the dbus message queue. I've read that for doing that I should use the DBusWatch and DBusTimeout objects that the connection provides, but I cannot find an example of how to use these anywhere...
For the moment i use dbus_connection_read_write_dispatch in order to do that, but I've read that it is not recommended for asynchronous operations, so I'll have to switch to creating my own main loop and using it...
The closest answer to my question was this one:
http://lists.freedesktop.org/archives/dbus/2007-September/008555.html ,
suggesting to look through the dbus-gmain.c file, which I did, but all I found there was a call of the dbus_connection_set_watch_functions and dbus_connection_set_timeout_functions, with other functions as parameters - should I overwrite those functions? Should I use them as they are?
I simply cannot figure out how to use these in order to read and write something to the dbus message queue...
Any idea would be more than welcome...
Here's something I wrote some time ago. I removed application specific code, you should just add your snippets where you handle DBus messages meant for your application and that should be it.
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <dbus/dbus.h>
struct dbus_ctx {
DBusConnection *conn;
struct event_base *evbase;
struct event dispatch_ev;
void *extra;
};
static void dispatch(int fd, short ev, void *x)
{
struct dbus_ctx *ctx = x;
DBusConnection *c = ctx->conn;
logger(LOG_DEBUG "dispatching\n");
while (dbus_connection_get_dispatch_status(c) == DBUS_DISPATCH_DATA_REMAINS)
dbus_connection_dispatch(c);
}
static void handle_dispatch_status(DBusConnection *c,
DBusDispatchStatus status, void *data)
{
struct dbus_ctx *ctx = data;
logger(LOG_DEBUG "new dbus dispatch status: %d\n", status);
if (status == DBUS_DISPATCH_DATA_REMAINS) {
struct timeval tv = {
.tv_sec = 0,
.tv_usec = 0,
};
event_add(&ctx->dispatch_ev, &tv);
}
}
static void handle_watch(int fd, short events, void *x)
{
struct dbus_ctx *ctx = x;
struct DBusWatch *watch = ctx->extra;
unsigned int flags = 0;
if (events & EV_READ)
flags |= DBUS_WATCH_READABLE;
if (events & EV_WRITE)
flags |= DBUS_WATCH_WRITABLE;
/*if (events & HUP)
flags |= DBUS_WATCH_HANGUP;
if (events & ERR)
flags |= DBUS_WATCH_ERROR;*/
logger(LOG_DEBUG "got dbus watch event fd=%d watch=%p ev=%d\n",
fd, watch, events);
if (dbus_watch_handle(watch, flags) == FALSE)
logger(LOG_ERROR "dbus_watch_handle() failed\n");
handle_dispatch_status(ctx->conn, DBUS_DISPATCH_DATA_REMAINS, ctx);
}
static dbus_bool_t add_watch(DBusWatch *w, void *data)
{
if (!dbus_watch_get_enabled(w))
return TRUE;
struct dbus_ctx *ctx = data;
ctx->extra = w;
int fd = dbus_watch_get_unix_fd(w);
unsigned int flags = dbus_watch_get_flags(w);
short cond = EV_PERSIST;
if (flags & DBUS_WATCH_READABLE)
cond |= EV_READ;
if (flags & DBUS_WATCH_WRITABLE)
cond |= EV_WRITE;
struct event *event = event_new(ctx->evbase, fd, cond, handle_watch, ctx);
if (!event)
return FALSE;
event_add(event, NULL);
dbus_watch_set_data(w, event, NULL);
logger(LOG_DEBUG "added dbus watch fd=%d watch=%p cond=%d\n", fd, w, cond);
return TRUE;
}
static void remove_watch(DBusWatch *w, void *data)
{
struct event *event = dbus_watch_get_data(w);
if (event)
event_free(event);
dbus_watch_set_data(w, NULL, NULL);
logger(LOG_DEBUG "removed dbus watch watch=%p\n", w);
}
static void toggle_watch(DBusWatch *w, void *data)
{
logger(LOG_DEBUG "toggling dbus watch watch=%p\n", w);
if (dbus_watch_get_enabled(w))
add_watch(w, data);
else
remove_watch(w, data);
}
static void handle_timeout(int fd, short ev, void *x)
{
struct dbus_ctx *ctx = x;
DBusTimeout *t = ctx->extra;
logger(LOG_DEBUG "got dbus handle timeout event %p\n", t);
dbus_timeout_handle(t);
}
static dbus_bool_t add_timeout(DBusTimeout *t, void *data)
{
struct dbus_ctx *ctx = data;
if (!dbus_timeout_get_enabled(t))
return TRUE;
logger(LOG_DEBUG "adding timeout %p\n", t);
struct event *event = event_new(ctx->evbase, -1, EV_TIMEOUT|EV_PERSIST,
handle_timeout, t);
if (!event) {
logger(LOG_ERROR "failed to allocate new event for timeout\n");
return FALSE;
}
int ms = dbus_timeout_get_interval(t);
struct timeval tv = {
.tv_sec = ms / 1000,
.tv_usec = (ms % 1000) * 1000,
};
event_add(event, &tv);
dbus_timeout_set_data(t, event, NULL);
return TRUE;
}
static void remove_timeout(DBusTimeout *t, void *data)
{
struct event *event = dbus_timeout_get_data(t);
logger(LOG_DEBUG "removing timeout %p\n", t);
event_free(event);
dbus_timeout_set_data(t, NULL, NULL);
}
static void toggle_timeout(DBusTimeout *t, void *data)
{
logger(LOG_DEBUG "toggling timeout %p\n", t);
if (dbus_timeout_get_enabled(t))
add_timeout(t, data);
else
remove_timeout(t, data);
}
static DBusHandlerResult handle_nameownerchanged(DBusMessage *message,
void *data)
{
struct dbus_ctx *ctx = data;
char *name, *old, *new;
if (dbus_message_get_args(message, NULL,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_STRING, &old,
DBUS_TYPE_STRING, &new,
DBUS_TYPE_INVALID) == FALSE) {
logger(LOG_ERROR "spurious NameOwnerChanged signal\n");
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
logger(LOG_DEBUG "dbus NameOwnerChanged %s -> %s\n", old, new);
if (new[0] != '\0')
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
/* XXX handle disconnecting clients */
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
static DBusHandlerResult msg_filter(DBusConnection *connection,
DBusMessage *message, void *data)
{
if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS,
"NameOwnerChanged"))
return handle_nameownerchanged(message, data);
logger(LOG_DEBUG "got dbus message %d %s -> %s %s/%s/%s %s\n",
dbus_message_get_type(message),
dbus_message_get_sender(message),
dbus_message_get_destination(message),
dbus_message_get_path(message),
dbus_message_get_interface(message),
dbus_message_get_member(message),
dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_ERROR ?
dbus_message_get_error_name(message) : "");
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
static void unregister_func(DBusConnection *connection, void *data)
{
}
static DBusHandlerResult message_func(DBusConnection *connection,
DBusMessage *message, void *data)
{
struct dbus_ctx *ctx = data;
logger(LOG_DEBUG "got dbus message sent to %s %s %s\n",
dbus_message_get_destination(message),
dbus_message_get_interface(message),
dbus_message_get_path(message));
/* XXX handle DBus message */
return DBUS_HANDLER_RESULT_HANDLED;
}
static DBusObjectPathVTable dbus_vtable = {
.unregister_function = unregister_func,
.message_function = message_func,
};
struct dbus_ctx *dbus_init(struct event_base *eb)
{
DBusConnection *conn = NULL;
struct dbus_ctx *ctx = calloc(1, sizeof(struct dbus_ctx));
if (!ctx) {
logger_perror("can't allocate dbus_ctx\n");
goto out;
}
conn = dbus_bus_get_private(DBUS_BUS_SESSION, NULL);
if (conn == NULL) {
logger(LOG_ERROR "failed to get bus\n");
goto out;
}
dbus_connection_set_exit_on_disconnect(conn, FALSE);
ctx->conn = conn;
ctx->evbase = eb;
event_assign(&ctx->dispatch_ev, eb, -1, EV_TIMEOUT, dispatch, ctx);
if (!dbus_connection_set_watch_functions(conn, add_watch, remove_watch,
toggle_watch, ctx, NULL)) {
logger(LOG_ERROR "dbus_connection_set_watch_functions() failed\n");
goto out;
}
if (!dbus_connection_set_timeout_functions(conn, add_timeout,
remove_timeout, toggle_timeout,
ctx, NULL)) {
logger(LOG_ERROR "dbus_connection_set_timeout_functions() failed\n");
goto out;
}
if (dbus_connection_add_filter(conn, msg_filter, ctx, NULL) == FALSE) {
logger(LOG_ERROR "dbus_connection_add_filter() failed\n");
goto out;
}
dbus_connection_set_dispatch_status_function(conn, handle_dispatch_status,
ctx, NULL);
char match[256];
snprintf(match,
sizeof(match),
"type='signal',interface='%s',member='NameOwnerChanged'",
DBUS_INTERFACE_DBUS);
DBusError error;
dbus_error_init(&error);
dbus_bus_add_match(conn, match, &error);
if (dbus_error_is_set(&error)) {
logger(LOG_ERROR "dbus_bus_add_match() %s failed: %s\n",
"NameOwnerChanged", error.message);
dbus_error_free(&error);
goto out;
}
snprintf(match,
sizeof(match),
"type='signal',interface='%s',member='%s'",
GNP_IPC_INTERFACE, GNP_IPC_SIGNAL_DELIVER_SA);
dbus_error_init(&error);
dbus_bus_add_match(conn, match, &error);
if (dbus_error_is_set(&error)) {
logger(LOG_ERROR "dbus_bus_add_match() %s failed: %s\n",
GNP_IPC_SIGNAL_DELIVER_SA, error.message);
dbus_error_free(&error);
goto out;
}
if (dbus_connection_register_object_path(conn, GNP_IPC_PATH, &dbus_vtable,
ctx) != TRUE) {
logger(LOG_ERROR "failed to register object path\n");
goto out;
}
return ctx;
out:
if (conn) {
dbus_connection_close(conn);
dbus_connection_unref(conn);
}
if (ctx)
free(ctx);
return NULL;
}
void dbus_close(struct dbus_ctx *ctx)
{
if (ctx && ctx->conn) {
dbus_connection_flush(ctx->conn);
dbus_connection_close(ctx->conn);
dbus_connection_unref(ctx->conn);
event_del(&ctx->dispatch_ev);
}
if (ctx)
free(ctx);
}
Based on Idx's code and examples from other sources (mainly example by Matthew Johnson and Will Ware), here is a synchronous event handling sample with a mainloop on select(). Just run in two terminals to see how events are passing around.
#define _GNU_SOURCE /* for pipe2 in unistd.h */
#include <dbus/dbus.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> /* for pipe2 */
#include <errno.h>
#include <fcntl.h> /* for O_NONBLOCK */
#include <sys/time.h> /* for gettimeofday */
#include <limits.h> /* for INT_MAX */
/* ------------------------------------------------------------ */
/* chgevt:
* when watch/timeout changes, pass a chgevt via a pipe to
* the selector loop so the loop will return from select() and
* react to the dbus change immediately. only need this when a new
* watch/timeout is added or enabled. when a watch/timeout is removed
* or disabled, immediate response is not needed.
*
* when running in single thread because those changes happen only
* in stage 2 of the selector loop, this chgevt path is not necessary.
* if running in multiple threads, e.g. calling dbus sending from
* another thread, then the path would be essential.
*/
/* events */
#define CHGEVT_ADD_WATCH (1)
#define CHGEVT_ADD_TIMEOUT (2)
static int watched_chgevt_fds[2] = {0,0}; /* [0] read, [1] write */
static void watched_chgevt_setup() {
int rc = pipe2(watched_chgevt_fds, O_NONBLOCK);
if ( rc != 0 ) watched_chgevt_fds[0] = watched_chgevt_fds[1] = 0;
}
static void watched_chgevt_send(int evt) {
if ( watched_chgevt_fds[1] ) write(watched_chgevt_fds[1], &evt, 1);
}
static int watched_chgevt_get() {
int rc = 0;
if ( watched_chgevt_fds[0] ) {
if ( (rc = read(watched_chgevt_fds[0], &rc, 1)) < 0 ) {
if ( errno != EAGAIN ) {
perror("watched_chgevt_fds pipe failed");
watched_chgevt_fds[0] = watched_chgevt_fds[1] = 0;
}
rc = 0;
}
}
return rc;
}
/* watch */
static DBusWatch * watched_watch = NULL;
static int watched_rd_fd = 0;
static int watched_wr_fd = 0;
static dbus_bool_t add_watch(DBusWatch *w, void *data)
{
if (!dbus_watch_get_enabled(w))
return TRUE;
int fd = dbus_watch_get_unix_fd(w);
unsigned int flags = dbus_watch_get_flags(w);
int old_rd_fd = watched_rd_fd;
int old_wr_fd = watched_wr_fd;
if (flags & DBUS_WATCH_READABLE)
watched_rd_fd = fd;
if (flags & DBUS_WATCH_WRITABLE)
watched_wr_fd = fd;
watched_watch = w;
printf(" WATCH: add dbus watch fd=%d watch=%p rd_fd=%d/%d wr_fd=%d/%d\n",
fd, w, watched_rd_fd, old_rd_fd, watched_wr_fd, old_wr_fd);
watched_chgevt_send( CHGEVT_ADD_WATCH );
return TRUE;
}
static void remove_watch(DBusWatch *w, void *data)
{
watched_watch = NULL;
watched_rd_fd = 0;
watched_wr_fd = 0;
printf(" WATCH: remove dbus watch watch=%p\n", w);
}
static void toggle_watch(DBusWatch *w, void *data)
{
printf(" WATCH: toggle dbus watch watch=%p\n", w);
if (dbus_watch_get_enabled(w))
add_watch(w, data);
else
remove_watch(w, data);
}
/* timeout */
static DBusTimeout * watched_timeout = NULL;
static struct timeval watched_timeout_start_tv = { 0, 0 };
/* at which timeout is enabled */
static unsigned int watched_timeout_setv = 0; /* set value */
static unsigned int watched_timeout_lastv = 0; /* last trigger */
#define TIMEOUT_MAX_MS ( 1000 * 1000 ) /* 1000 sec */
#define TIMEOUT_MOD_MS ( 8 * TIMEOUT_MAX_MS ) /* 8000 sec */
/* note: last_trigger is 0 to 7999 sec.
* next_timeout is 0 to 8999 sec.
*/
#define TIME_TV_TO_MS(x) /* convert a timeval to 0-to-7999 ms */ \
( (x.tv_sec%(TIMEOUT_MOD_MS/1000))*1000 + \
x.tv_usec/1000 )
static dbus_bool_t add_timeout(DBusTimeout *t, void *data)
{
if (!dbus_timeout_get_enabled(t))
return TRUE;
int ms = dbus_timeout_get_interval(t);
if ( ms < 0 || ms > TIMEOUT_MAX_MS ) {
ms = TIMEOUT_MAX_MS;
if ( ms < 0 || ms > INT_MAX/2-1 ) {
ms = INT_MAX/2-1;
}
}
if ( ms < 1 ) {
ms = 1;
}
struct timeval tnow = {0,0};
gettimeofday(&tnow, NULL);
unsigned int tnowms = TIME_TV_TO_MS(tnow);
printf(" TIMEOUT: add dbus timeout %p value %u ms\n", t, ms);
watched_timeout_start_tv = tnow;
watched_timeout_setv = ms;
watched_timeout_lastv = tnowms;
watched_timeout = t;
watched_chgevt_send( CHGEVT_ADD_TIMEOUT );
return TRUE;
}
static void remove_timeout(DBusTimeout *t, void *data)
{
printf(" TIMEOUT: remove timeout %p\n", t);
watched_timeout = NULL;
struct timeval tv = { .tv_sec = 0, .tv_usec = 0, };
watched_timeout_start_tv = tv;
watched_timeout_setv = 0;
watched_timeout_lastv = 0;
}
static void toggle_timeout(DBusTimeout *t, void *data)
{
printf(" TIMEOUT: toggle timeout %p\n", t);
if (dbus_timeout_get_enabled(t))
add_timeout(t, data);
else
remove_timeout(t, data);
}
/* the selector function */
/* receive */
static int dbus_selector_process_recv(DBusConnection* conn, int iswaiting_rpcreply,
DBusPendingCall** pendingargptr);
/* send rpc request */
static int dbus_selector_process_post_send(DBusConnection* conn, char * param,
DBusPendingCall** pendingargptr);
/* receive rpc reply, called by process_recv() */
static int dbus_selector_process_post_reply(DBusConnection* conn,
DBusPendingCall** pendingargptr );
/* selector */
#include <sys/select.h>
#include <time.h>
static unsigned int lastregtime = 0;
int dbus_selector(char *param, int altsel )
{
DBusConnection* conn;
DBusError err;
int ret = 1; /* default fail */
watched_chgevt_setup();
char * destarray[4] = { "test.selector.server", "test.selector.client",
"test.unknown.user1", "test.unknown.user2" };
char * deststr = destarray[0];
if ( altsel != 0 ) {
deststr = destarray[1];
lastregtime = time(NULL);
}
printf("Accepting method calls and signals\n");
// initialise the error
dbus_error_init(&err);
// connect to the bus and check for errors
conn = dbus_bus_get(DBUS_BUS_SESSION, &err);
if (dbus_error_is_set(&err)) {
fprintf(stderr, "Connection Error (%s)\n", err.message);
dbus_error_free(&err);
}
if (NULL == conn) {
fprintf(stderr, "Connection Null\n");
return ret; /* ret=1 fail */
}
// request our name on the bus and check for errors
ret = dbus_bus_request_name(conn, deststr /* "test.selector.server" */,
DBUS_NAME_FLAG_REPLACE_EXISTING , &err);
if (dbus_error_is_set(&err)) {
fprintf(stderr, "Name Error (%s)\n", err.message);
dbus_error_free(&err);
}
if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) {
fprintf(stderr, "Not Primary Owner (%d)\n", ret);
return ret; /* ret=1 fail */
}
// add a rule for which messages we want to see
dbus_bus_add_match(conn, "type='signal',interface='test.signal.Type'", &err);
// see signals from the given interface
dbus_connection_flush(conn); /* Note: this would block */
if (dbus_error_is_set(&err)) {
fprintf(stderr, "Match Error (%s)\n", err.message);
return ret; /* ret=1 fail */
}
printf("Match signal rule sent\n");
/* setup watch and timeout */
if (!dbus_connection_set_watch_functions(conn, add_watch, remove_watch,
toggle_watch, NULL, NULL)) {
printf(" ERROR dbus_connection_set_watch_functions() failed\n");
return ret; /* ret=1 fail */
}
if (!dbus_connection_set_timeout_functions(conn, add_timeout,
remove_timeout, toggle_timeout,
NULL, NULL)) {
printf(" ERROR dbus_connection_set_timeout_functions() failed\n");
return ret; /* ret=1 fail */
}
/* the selector loop */
ret = 0; /* default success */
struct timeval local_to_startv = {0,0}; /* timeout saved locally */
DBusPendingCall* pending = NULL; /* keep track of the outstanding rpc call */
while(ret == 0) {
/* the selector loop stage 1, setup for select() call.
* in this stage no dbus watch/timeout change should happen
*/
#define DEFAULT_SELECT_LOOP_MS (5500)
int modified_timeout = 0; /* yes or no */
fd_set rfds, wfds, efds;
struct timeval timeoutval = {
DEFAULT_SELECT_LOOP_MS/1000,
(DEFAULT_SELECT_LOOP_MS%1000)*1000 };
int nfds = 1;
int rc = 0;
printf("\n");
FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds);
if ( watched_watch != NULL ) {
if ( watched_rd_fd ) {
FD_SET(watched_rd_fd, &rfds);
FD_SET(watched_rd_fd, &efds);
if ( nfds <= watched_rd_fd ) { nfds = watched_rd_fd + 1; }
printf(" SELECT nfds %d rdfd %d\n", nfds, watched_rd_fd);
}
if ( watched_wr_fd ) {
FD_SET(watched_wr_fd, &wfds);
FD_SET(watched_wr_fd, &efds);
if ( nfds <= watched_wr_fd ) { nfds = watched_wr_fd + 1; }
printf(" SELECT nfds %d wrfd %d\n", nfds, watched_wr_fd);
}
}
if ( watched_chgevt_fds[0] != 0 ) {
FD_SET(watched_chgevt_fds[0], &rfds);
FD_SET(watched_chgevt_fds[0], &efds);
}
if ( watched_timeout != NULL ) {
struct timeval startv = watched_timeout_start_tv;
unsigned int setv = watched_timeout_setv;
unsigned int lastv = watched_timeout_lastv;
struct timeval tnow = {0,0};
unsigned int tnowms = 0;
unsigned int toms = 0;
unsigned int tdiff = 0;
gettimeofday(&tnow, NULL);
tnowms = TIME_TV_TO_MS(tnow);
if ( startv.tv_sec != local_to_startv.tv_sec ||
startv.tv_usec != local_to_startv.tv_sec )
{ /* new timeout */
local_to_startv = startv;
}
if ( lastv > tnowms ) {
tnowms += TIMEOUT_MOD_MS;
}
toms = lastv + setv + 1;
/* add 1 to make up for rounding loss */
if ( toms > tnowms ) {
tdiff = toms - tnowms; /* ms till timeout */
}
if ( tdiff < DEFAULT_SELECT_LOOP_MS ) {
/* revise timeout value */
timeoutval.tv_sec = tdiff/1000;
timeoutval.tv_usec = (tdiff%1000)*1000;
modified_timeout = 1; /* yes */
}
}
if ( modified_timeout ) {
printf(" SELECT with nfds %d ... modified tiemout %lu.%03lu\n",
nfds, timeoutval.tv_sec, timeoutval.tv_usec/1000);
} else {
printf(" SELECT with nfds %d...\n", nfds);
}
rc = select(nfds, &rfds, &wfds, &efds, &timeoutval);
if ( rc < 0 ) {
printf(" SELECT returned error %d\n", rc);
break;
}
/* the selector loop stage 2, dbus operation.
* in this stage dbus watch/timeout could change.
*/
/* check timeout */
if ( watched_timeout != NULL ) {
struct timeval startv = watched_timeout_start_tv;
unsigned int setv = watched_timeout_setv;
unsigned int lastv = watched_timeout_lastv;
struct timeval tnow = {0,0}; unsigned int tnowms = 0, toms = 0;
gettimeofday(&tnow, NULL);
tnowms = TIME_TV_TO_MS(tnow);
if ( startv.tv_sec == local_to_startv.tv_sec &&
startv.tv_usec == local_to_startv.tv_sec )
{ /* same timeout */
if ( lastv > tnowms ) {
tnowms += TIMEOUT_MOD_MS;
}
toms = lastv + setv + 1;
/* add 1 to make up for rounding loss */
if ( toms >= tnowms ) {
watched_timeout_lastv = tnowms%TIMEOUT_MOD_MS;
printf(" HANDLING dbus handle timeout %p\n",
watched_timeout);
dbus_timeout_handle(watched_timeout);
printf(" HANDLING dbus handle timeout %p done\n",
watched_timeout);
}
} /* else if not the same timeout as before select() skip for now */
}
/* self initiated rpc call */
if ( altsel ) {
unsigned int tmnow = time(NULL);
unsigned int tmdiff = tmnow - lastregtime;
if ( tmdiff > 10 ) { /* send a rpc evey 10 seconds */
dbus_selector_process_post_send(conn, param, &pending);
lastregtime = tmnow;
}
}
/* select() returned no event */
if ( rc == 0 ) {
printf(" SELECT returned rc 0 \n");
continue;
}
/* some event happened according to select() */
printf(" SELECT returned rc %d \n", rc);
if ( watched_watch != NULL ) {
if ( watched_rd_fd ) {
if ( FD_ISSET(watched_rd_fd, &rfds) ) {
printf(" HANDLING calls watch_handle\n");
dbus_watch_handle(watched_watch, DBUS_WATCH_READABLE);
printf(" HANDLING calls process_recv\n");
dbus_selector_process_recv(conn, pending==NULL?0:1,
&pending);
printf(" HANDLING done process_recv\n");
}
if ( FD_ISSET(watched_rd_fd, &efds) ) {
printf(" HANDLING EXCEPTION with rd fd %d \n",
watched_rd_fd);
}
}
if ( watched_wr_fd ) {
if ( FD_ISSET(watched_wr_fd, &wfds) ) {
dbus_watch_handle(watched_watch, DBUS_WATCH_WRITABLE);
}
if ( FD_ISSET(watched_wr_fd, &efds) ) {
printf(" HANDLING EXCEPTION with wr fd %d \n",
watched_wr_fd);
}
}
}
/* chgevt pipe */
if ( watched_chgevt_fds[0] != 0 && FD_ISSET(watched_chgevt_fds[0], &rfds) ) {
int chgevt = watched_chgevt_get();
switch (chgevt) {
case CHGEVT_ADD_WATCH:
printf(" HANDLING chgevt 1 consumed \n"); break;
case CHGEVT_ADD_TIMEOUT:
printf(" HANDLING chgevt 2 consumed \n"); break;
default:
printf(" HANDLING chgevt n=%d consumed \n", chgevt); break;
}
}
}
return ret;
}
static int dbus_selector_process_recv(DBusConnection* conn, int iswaiting_rpcreply,
DBusPendingCall** pendingargptr)
{
int ret = 1; /* default fail */
/* remove this call that consumes .1ms because dbus is already read
* by dbus_watch_handle():
* dbus_connection_read_write(conn, 0);
*
* according to dbus_connection_dispatch(): The incoming data buffer
* is filled when the connection reads from its underlying transport
* (such as a socket). Reading usually happens in dbus_watch_handle()
* or dbus_connection_read_write().
*/
DBusDispatchStatus dispatch_rc = dbus_connection_get_dispatch_status(conn);
if ( DBUS_DISPATCH_DATA_REMAINS != dispatch_rc ) {
printf(" ERROR recv no message in queue \n");
}
while( DBUS_DISPATCH_DATA_REMAINS == dispatch_rc ) {
DBusMessage* msg = dbus_connection_borrow_message(conn);
if ( msg == NULL ) {
printf(" ERROR recv pending check FAILED: remains but "
"no message borrowed. \n");
break;
}
int mtype = dbus_message_get_type(msg);
if ( iswaiting_rpcreply &&
( mtype == DBUS_MESSAGE_TYPE_METHOD_RETURN ||
mtype == DBUS_MESSAGE_TYPE_ERROR ) ) {
printf(" RPC REPLY pending check SUCCESS: received rpc reply \n");
dbus_connection_return_message(conn, msg);
dbus_connection_dispatch(conn);
/* dispatch so the received message at the
* head of queue is passed to the pendingcall
*/
dbus_selector_process_post_reply( conn, pendingargptr );
printf(" RPC REPLY pending check SUCCESS: processed rpc reply \n");
} else if ( mtype == DBUS_MESSAGE_TYPE_METHOD_RETURN ) {
printf(" RECV pending check FAILED: received rpc reply \n");
dbus_connection_steal_borrowed_message(conn, msg);
dbus_message_unref(msg);
} else if ( mtype == DBUS_MESSAGE_TYPE_ERROR ) {
printf(" RECV pending check FAILED: received ERROR \n");
dbus_connection_steal_borrowed_message(conn, msg);
dbus_message_unref(msg);
} else if ( mtype == DBUS_MESSAGE_TYPE_SIGNAL ) {
printf(" SIGNAL pending check SUCCESS: received and drop \n");
dbus_connection_steal_borrowed_message(conn, msg);
dbus_message_unref(msg);
} else if ( mtype == DBUS_MESSAGE_TYPE_METHOD_CALL ) {
printf(" RPC RECV check SUCCESS: received rpc call. \n");
dbus_connection_steal_borrowed_message(conn, msg);
DBusMessage* reply = NULL;
do {
/* craft a reply message */
DBusMessageIter args;
dbus_uint32_t serial = 111;
dbus_bool_t stat = TRUE;
dbus_uint32_t retval1 = 555;
const char *strval = "good";
reply = dbus_message_new_method_return(msg);
dbus_message_iter_init_append(reply, &args);
if ( !dbus_message_iter_append_basic(
&args, DBUS_TYPE_BOOLEAN, &stat) ) {
printf(" error rpc reply Out Of Memory!\n");
break;
}
if ( !dbus_message_iter_append_basic(
&args, DBUS_TYPE_UINT32, &retval1) ) {
printf(" error rpc reply Out Of Memory!\n");
break;
}
if ( !dbus_message_iter_append_basic(
&args, DBUS_TYPE_STRING, &strval) ) {
printf(" error rpc reply Out Of Memory!\n");
break;
}
if ( !dbus_connection_send(conn, reply, &serial)) {
printf(" error rpc reply Out Of Memory!\n");
break;
}
dbus_connection_flush(conn);
} while(0);
if ( reply != NULL ) { dbus_message_unref(reply); }
if ( msg != NULL ) { /* msg not consumed */
//dbus_connection_return_message(conn, msg);
dbus_message_unref(msg);
}
ret = 0; /* success */
} else {
printf(" error unknown msg type %d \n", mtype);
}
dispatch_rc = dbus_connection_get_dispatch_status(conn);
}
return ret;
}
static int dbus_selector_process_post_send( DBusConnection* conn, char * param,
DBusPendingCall** pendingargptr)
{ /* mostly a copy of query() */
DBusMessage* msg = NULL;
DBusMessageIter args = {0};
DBusError err = {0};
DBusPendingCall* pending = NULL;
int ret = 0;
* pendingargptr = NULL;
printf("Calling remote method with %s\n", param);
// initialiset the errors
dbus_error_init(&err);
msg = dbus_message_new_method_call(
"test.selector.server", // target for the method call
"/test/method/Object", // object to call on
"test.method.Type", // interface to call on
"Method"); // method name
if (NULL == msg) {
fprintf(stderr, "Message Null\n");
exit(1);
}
// append arguments
dbus_message_iter_init_append(msg, &args);
if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &param)) {
fprintf(stderr, "Out Of Memory!\n");
exit(1);
}
// send message and get a handle for a reply
if (!dbus_connection_send_with_reply (conn, msg, &pending, 300)) {
// -1 is default timeout
fprintf(stderr, "Out Of Memory!\n");
exit(1);
}
if (NULL == pending) {
fprintf(stderr, "Pending Call Null\n");
exit(1);
}
printf("Request Sent\n");
dbus_connection_flush(conn); /* Note: block until write finishes */
printf("Request flushed\n");
// free message
dbus_message_unref(msg);
* pendingargptr = pending;
return ret;
}
static int dbus_selector_process_post_reply( DBusConnection* conn,
DBusPendingCall** pendingargptr )
{
DBusMessage* msg = NULL;
DBusMessageIter args = {0};
dbus_bool_t stat = FALSE;
dbus_uint32_t level = 0;
DBusPendingCall* pending = *pendingargptr;
if ( ! dbus_pending_call_get_completed(pending) ) {
dbus_pending_call_unref(pending);
*pendingargptr = NULL;
fprintf(stderr, " error Reply incomplete\n");
exit(1);
}
// get the reply message
msg = dbus_pending_call_steal_reply(pending);
if (NULL == msg) {
fprintf(stderr, "Reply Null\n");
exit(1);
}
// free the pending message handle
dbus_pending_call_unref(pending);
*pendingargptr = NULL;
/* */
int validerror = 0;
{ int mtype = dbus_message_get_type(msg);
if ( mtype == DBUS_MESSAGE_TYPE_ERROR ) {
fprintf(stderr, " error Reply with a valid error detected!\n");
validerror = 1;
} else if ( mtype != DBUS_MESSAGE_TYPE_METHOD_RETURN ) {
fprintf(stderr, " error Reply not a valid return type!"
" received message type %d\n", mtype);
}
}
// read the parameters
if (!dbus_message_iter_init(msg, &args))
fprintf(stderr, "Message has no arguments!\n");
else if (DBUS_TYPE_BOOLEAN != dbus_message_iter_get_arg_type(&args))
{
fprintf(stderr, "Argument is not boolean!\n");
if (DBUS_TYPE_STRING == dbus_message_iter_get_arg_type(&args) ) {
fprintf(stderr, "Argument 1 is string!\n");
if ( validerror ) {
char * strval = (char*)"<init-unknown>";
dbus_message_iter_get_basic(&args, &strval);
if ( strval != NULL && strnlen(strval, 160) < 160 ) {
printf("RPC reply arg 0 is c%u %s\n", 160, strval);
} else {
printf("RPC reply arg 0 error \n");
}
}
} else if (DBUS_TYPE_UINT32 == dbus_message_iter_get_arg_type(&args) ) {
fprintf(stderr, "Argument 1 is uint32!\n");
} else {
fprintf(stderr, "Argument 1 is not recognized!\n");
}
}
else
dbus_message_iter_get_basic(&args, &stat);
if (!dbus_message_iter_next(&args))
fprintf(stderr, "Message has too few arguments!\n");
else if (DBUS_TYPE_UINT32 != dbus_message_iter_get_arg_type(&args))
fprintf(stderr, "Argument is not int!\n");
else
dbus_message_iter_get_basic(&args, &level);
printf("Got Reply: %d, %d\n", stat, level);
// free reply
dbus_message_unref(msg);
return 0;
}
/* ------------------------------------------------------------ */
int main(int argc, char** argv)
{
if (2 > argc) {
printf ("Syntax: dbus-select-watch [selector|selpost] [<param>]\n");
return 1;
}
char* param = "no cmdline param";
if (3 <= argc && NULL != argv[2]) param = argv[2];
if (0 == strncmp(argv[1], "selector", 20))
dbus_selector(param, 0);
else if (0 == strncmp(argv[1], "selpost", 20))
dbus_selector(param, 1);
else {
printf ("Syntax: dbus-select-watch [selector|selpost] [<param>]\n");
return 1;
}
return 0;
}
I have written an example for implementing main loop for dbus. I have tested it with bluez DBUS API and it works without any problem.
I have removed the bluetooth part of my application. I have used libevent to implement event loop.
Note: It is in C++. You can easily convert it to C programming language.
#include "dbus-ble/libevent.h"
#include <stdlib.h>
#include <errno.h>
#include <event2/event.h>
#include <event2/util.h>
#include <dbus/dbus.h>
struct watch_handler {
struct event *ev;
DBusConnection *dbus_cnx;
DBusWatch *watch;
};
struct timeout_handler {
struct event *ev;
DBusConnection *dbus_cnx;
DBusTimeout *timeout;
};
static struct event_base *ev_base = nullptr;
static void timeout_handler_free(void *data)
{
struct timeout_handler *to_handler = reinterpret_cast<struct timeout_handler *>(data);
if (to_handler == nullptr)
return;
if (to_handler->ev != nullptr) {
event_del(to_handler->ev);
event_free(to_handler->ev);
}
if (to_handler->dbus_cnx != nullptr)
dbus_connection_unref(to_handler->dbus_cnx);
free(to_handler);
}
static void libevent_dispatch_dbus(int fd, short event, void *data)
{
struct timeout_handler *to_handler = reinterpret_cast<struct timeout_handler *>(data);
DBusConnection *dbus_cnx = to_handler->dbus_cnx;
dbus_connection_ref(dbus_cnx);
while (dbus_connection_dispatch(dbus_cnx) == DBUS_DISPATCH_DATA_REMAINS);
dbus_connection_unref(dbus_cnx);
timeout_handler_free(to_handler);
}
static inline void throw_libevent_dispatch_dbus(DBusConnection *dbus_cnx)
{
const struct timeval timeout = {0,0};
struct timeout_handler *to_handler = reinterpret_cast<struct timeout_handler *>(calloc(1, sizeof(struct timeout_handler)));
if (to_handler == nullptr)
return;
to_handler->dbus_cnx = dbus_connection_ref(dbus_cnx);
to_handler->ev = evtimer_new(ev_base, libevent_dispatch_dbus, to_handler);
evtimer_add(to_handler->ev, &timeout);
}
static void watch_handler_dispatch(int fd, short event, void *data)
{
struct watch_handler *io_handler = reinterpret_cast<struct watch_handler *>(data);
DBusDispatchStatus status;
unsigned int flags = 0;
dbus_connection_ref(io_handler->dbus_cnx);
if (evutil_socket_geterror(fd) != 0)
flags |= DBUS_WATCH_ERROR;
if (event & EV_READ)
flags |= DBUS_WATCH_READABLE;
if (event & EV_WRITE)
flags |= DBUS_WATCH_WRITABLE;
dbus_watch_handle(io_handler->watch, flags);
status = dbus_connection_get_dispatch_status(io_handler->dbus_cnx);
if (status == DBUS_DISPATCH_DATA_REMAINS)
throw_libevent_dispatch_dbus(io_handler->dbus_cnx);
dbus_connection_unref(io_handler->dbus_cnx);
}
static void watch_handler_free(void *data)
{
struct watch_handler *io_handler = reinterpret_cast<struct watch_handler *>(data);
if (io_handler == nullptr)
return;
if (io_handler->ev != nullptr) {
event_del(io_handler->ev);
event_free(io_handler->ev);
}
dbus_connection_unref(io_handler->dbus_cnx);
free(io_handler);
}
static dbus_bool_t libevent_dbus_watch_add(DBusWatch *watch, void *data)
{
DBusConnection *dbus_cnx = reinterpret_cast<DBusConnection *>(data);
struct watch_handler *io_handler;
unsigned int flags;
short io_condition;
int io_fd;
if (dbus_watch_get_enabled(watch) == FALSE)
return TRUE;
io_handler = reinterpret_cast<struct watch_handler *>(calloc(1, sizeof(struct watch_handler)));
if (io_handler == nullptr)
return FALSE;
io_handler->dbus_cnx = dbus_connection_ref(dbus_cnx);
io_handler->watch = watch;
dbus_watch_set_data(watch, io_handler, watch_handler_free);
flags = dbus_watch_get_flags(watch);
io_condition = EV_PERSIST;
if (flags & DBUS_WATCH_READABLE)
io_condition |= EV_READ;
if (flags & DBUS_WATCH_WRITABLE)
io_condition |= EV_WRITE;
io_fd = dbus_watch_get_unix_fd(watch);
io_handler->ev = event_new(ev_base, io_fd, io_condition,
watch_handler_dispatch, io_handler);
event_add(io_handler->ev, nullptr);
return TRUE;
}
static void libevent_dbus_watch_remove(DBusWatch *watch, void *data)
{
if (dbus_watch_get_enabled(watch) == TRUE)
return;
dbus_watch_set_data(watch, nullptr, nullptr);
}
static void libevent_dbus_watch_toggled(DBusWatch *watch, void *data)
{
if (dbus_watch_get_enabled(watch) == TRUE)
libevent_dbus_watch_add(watch, data);
else
libevent_dbus_watch_remove(watch, data);
}
static void timeout_handler_dispatch(int fd, short event, void *data)
{
struct timeout_handler *to_handler = reinterpret_cast<struct timeout_handler *>(data);
dbus_timeout_handle(to_handler->timeout);
}
static inline void _set_timer(struct timeval *timer, long int milliseconds)
{
timer->tv_sec = milliseconds / 1000;
timer->tv_usec = (milliseconds % 1000) * 1000;
}
static dbus_bool_t libevent_dbus_timeout_add(DBusTimeout *timeout, void *data)
{
struct timeout_handler *to_handler;
struct timeval timer;
if (dbus_timeout_get_enabled(timeout) == FALSE)
return TRUE;
to_handler = reinterpret_cast<struct timeout_handler *>(calloc(1, sizeof(struct timeout_handler)));
if (to_handler == nullptr)
return FALSE;
dbus_timeout_set_data(timeout, to_handler, timeout_handler_free);
_set_timer(&timer, dbus_timeout_get_interval(timeout));
to_handler->ev = evtimer_new(ev_base, timeout_handler_dispatch, to_handler);
evtimer_add(to_handler->ev, (const struct timeval *) &timer);
return TRUE;
}
static void libevent_dbus_timeout_remove(DBusTimeout *timeout, void *data)
{
dbus_timeout_set_data(timeout, nullptr, nullptr);
}
static void libevent_dbus_timeout_toggled(DBusTimeout *timeout, void *data)
{
if (dbus_timeout_get_enabled(timeout) == TRUE)
libevent_dbus_timeout_add(timeout, data);
else
libevent_dbus_timeout_remove(timeout, data);
}
static void libevent_dbus_dispatch_status(DBusConnection *dbus_cnx,
DBusDispatchStatus new_status, void *data)
{
DBusDispatchStatus status;
if (dbus_connection_get_is_connected(dbus_cnx) == FALSE)
return;
status = dbus_connection_get_dispatch_status(dbus_cnx);
if (status == DBUS_DISPATCH_DATA_REMAINS)
throw_libevent_dispatch_dbus(dbus_cnx);
}
static dbus_bool_t setup_dbus_in_libevent_mainloop(DBusConnection *dbus_cnx)
{
DBusDispatchStatus status;
if (dbus_connection_set_watch_functions(dbus_cnx,
libevent_dbus_watch_add, libevent_dbus_watch_remove,
libevent_dbus_watch_toggled, dbus_cnx, nullptr) == FALSE)
return FALSE;
if (dbus_connection_set_timeout_functions(dbus_cnx,
libevent_dbus_timeout_add, libevent_dbus_timeout_remove,
libevent_dbus_timeout_toggled, dbus_cnx, nullptr) == FALSE)
return FALSE;
dbus_connection_set_dispatch_status_function(dbus_cnx,
libevent_dbus_dispatch_status, dbus_cnx, nullptr);
status = dbus_connection_get_dispatch_status(dbus_cnx);
if (status == DBUS_DISPATCH_DATA_REMAINS)
throw_libevent_dispatch_dbus(dbus_cnx);
return TRUE;
}
int setup_event_loop_for_dbus(DBusConnection *dbus_cnx)
{
if (ev_base == nullptr)
ev_base = event_base_new();
if (ev_base == nullptr)
return -1;
if (setup_dbus_in_libevent_mainloop(dbus_cnx) == FALSE) {
dbus_connection_unref(dbus_cnx);
event_base_free(ev_base);
return -1;
}
return 0;
}
int libevent_run_loop_dbus(void)
{
return event_base_loop(ev_base, 0);
}
void dbus_cleanup_event_loop(DBusConnection *dbus_cnx)
{
if (dbus_cnx == nullptr)
return;
dbus_connection_set_watch_functions(dbus_cnx,
nullptr, nullptr, nullptr, nullptr, nullptr);
dbus_connection_set_timeout_functions(dbus_cnx,
nullptr, nullptr, nullptr, nullptr, nullptr);
dbus_connection_set_dispatch_status_function(dbus_cnx,
nullptr, nullptr, nullptr);
}

Trouble using Windows MIDI API (no callbacks when playing)

I have an USB-connected MIDI-keyboard. It works fine in other applications. However, in my own program it does not. The midiInOpen() call goes through, I get one callback (from opening the device) but I don't get any callbacks when playing the keyboard.
By using midiInGetDevCaps() I can see that I'm using the correct device.
Any ideas? Could the other (commercial) applications use some other API?
static void CALLBACK myFunc(HMIDIIN handle, UINT uMsg,
DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) {
printf("Callback!"\n);
}
int main() {
unsigned long result;
HMIDIIN inHandle;
result = midiInOpen(&inHandle, 0, (DWORD)myFunc, 0, CALLBACK_FUNCTION);
if (result)
{
printf("There was an error opening MIDI\n");
}
while(1) { Sleep(1); }
}
You need to call midiInstart. You also need to pump messages. Nothing is going to happen if you're calling Sleep and not servicing input.
Here's a bit of a tutorial on Windows MIDI.
Here's an extract of a class (WinMidiIn) I wrote for Win MIDI input (lots of error handling removed, class member types can be inferred from the calls they are passed to as params):
{
MMRESULT res = ::midiInOpen(&mMidiIn, mDeviceIdx, (DWORD_PTR)MidiInCallbackProc, (DWORD_PTR)this,
CALLBACK_FUNCTION | MIDI_IO_STATUS);
if (MMSYSERR_NOERROR != res)
return;
const int kDataBufLen = 512;
int idx;
for (idx = 0; idx < MIDIHDR_CNT; ++idx)
{
mMidiHdrs[idx].lpData = (LPSTR) ::malloc(kDataBufLen);
mMidiHdrs[idx].dwBufferLength = kDataBufLen;
res = ::midiInPrepareHeader(mMidiIn, &mMidiHdrs[idx], (UINT)sizeof(MIDIHDR));
res = ::midiInAddBuffer(mMidiIn, &mMidiHdrs[idx], sizeof(MIDIHDR));
}
res = ::midiInStart(mMidiIn);
for (;;)
{
DWORD result;
MSG msg;
// Read all of the messages in this next loop,
// removing each message as we read it.
while (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
// If it is a quit message, exit.
if (msg.message == WM_QUIT)
break;
// Otherwise, dispatch the message.
::DispatchMessage(&msg);
}
// Wait for any message sent or posted to this queue
// or for one of the passed handles be set to signaled.
result = ::MsgWaitForMultipleObjects(1, &mDoneEvent, FALSE, INFINITE, QS_ALLINPUT);
// The result tells us the type of event we have.
if (result == (WAIT_OBJECT_0 + 1))
{
// New messages have arrived.
// Continue to the top of the always while loop to
// dispatch them and resume waiting.
continue;
}
else if (WAIT_TIMEOUT == result)
continue;
else if (WAIT_OBJECT_0 == result)
break; // done event fired
else
break; // ??
}
res = ::midiInReset(mMidiIn);
for (idx = 0; idx < MIDIHDR_CNT; ++idx)
{
res = ::midiInUnprepareHeader(mMidiIn, &mMidiHdrs[idx], (UINT)sizeof(MIDIHDR));
::free(mMidiHdrs[idx].lpData);
mMidiHdrs[idx].lpData = NULL;
}
res = ::midiInClose(mMidiIn);
mMidiIn = NULL;
}
void CALLBACK
MidiInCallbackProc(HMIDIIN hmi,
UINT wMsg,
DWORD dwInstance,
DWORD dwParam1,
DWORD dwParam2)
{
MMRESULT res;
LPMIDIHDR hdr;
WinMidiIn * _this = (WinMidiIn *) dwInstance;
switch (wMsg)
{
case MIM_DATA:
// dwParam1 is the midi event with status in the low byte of the low word
// dwParam2 is the event time in ms since the start of midi in
// data: LOBYTE(dwParam1), HIBYTE(dwParam1), LOBYTE(HIWORD(dwParam1))
break;
case MIM_ERROR:
break;
case MIM_LONGDATA:
// dwParam1 is the lpMidiHdr
// dwParam2 is the event time in ms since the start of midi in
hdr = (LPMIDIHDR) dwParam1;
// sysex: (byte*)hdr->lpData, (int)hdr->dwBytesRecorded
res = ::midiInAddBuffer(_this->mMidiIn, hdr, sizeof(MIDIHDR));
break;
case MIM_LONGERROR:
hdr = (LPMIDIHDR) dwParam1;
res = ::midiInAddBuffer(_this->mMidiIn, hdr, sizeof(MIDIHDR));
break;
}
}
You can find an example here https://gist.github.com/yoggy/1485181
I post the code here in case the link becomes dead
You may be missing the midiInStart()
#include <SDKDDKVer.h>
#include <Windows.h>
#include <stdio.h>
#include <conio.h>
#include <mmsystem.h>
#pragma comment(lib, "winmm.lib")
void PrintMidiDevices()
{
UINT nMidiDeviceNum;
MIDIINCAPS caps;
nMidiDeviceNum = midiInGetNumDevs();
if (nMidiDeviceNum == 0) {
fprintf(stderr, "midiInGetNumDevs() return 0...");
return;
}
printf("== PrintMidiDevices() == \n");
for (unsigned int i = 0; i < nMidiDeviceNum; ++i) {
midiInGetDevCaps(i, &caps, sizeof(MIDIINCAPS));
printf("\t%d : name = %s\n", i, caps.szPname);
}
printf("=====\n");
}
void CALLBACK MidiInProc(HMIDIIN hMidiIn, UINT wMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
{
switch(wMsg) {
case MIM_OPEN:
printf("wMsg=MIM_OPEN\n");
break;
case MIM_CLOSE:
printf("wMsg=MIM_CLOSE\n");
break;
case MIM_DATA:
printf("wMsg=MIM_DATA, dwInstance=%08x, dwParam1=%08x, dwParam2=%08x\n", dwInstance, dwParam1, dwParam2);
break;
case MIM_LONGDATA:
printf("wMsg=MIM_LONGDATA\n");
break;
case MIM_ERROR:
printf("wMsg=MIM_ERROR\n");
break;
case MIM_LONGERROR:
printf("wMsg=MIM_LONGERROR\n");
break;
case MIM_MOREDATA:
printf("wMsg=MIM_MOREDATA\n");
break;
default:
printf("wMsg = unknown\n");
break;
}
return;
}
int main(int argc, char* argv[])
{
HMIDIIN hMidiDevice = NULL;;
DWORD nMidiPort = 0;
UINT nMidiDeviceNum;
MMRESULT rv;
PrintMidiDevices();
nMidiDeviceNum = midiInGetNumDevs();
if (nMidiDeviceNum == 0) {
fprintf(stderr, "midiInGetNumDevs() return 0...");
return -1;
}
rv = midiInOpen(&hMidiDevice, nMidiPort, (DWORD)(void*)MidiInProc, 0, CALLBACK_FUNCTION);
if (rv != MMSYSERR_NOERROR) {
fprintf(stderr, "midiInOpen() failed...rv=%d", rv);
return -1;
}
midiInStart(hMidiDevice);
while(true) {
if (!_kbhit()) {
Sleep(100);
continue;
}
int c = _getch();
if (c == VK_ESCAPE) break;
if (c == 'q') break;
}
midiInStop(hMidiDevice);
midiInClose(hMidiDevice);
hMidiDevice = NULL;
return 0;
}

Resources