X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Usermode%2FApplications%2Faxwin3_src%2FWM%2Fipc.c;h=44601841890e5f966e1f869d5ca9c2858be8b99f;hb=bdefac5f54668fcccff11a69619ff31b25595eeb;hp=da56149bde6ef88400eede4c98f829f4ca67b9f4;hpb=5057414aefd4d2c869fc9937b48dfdd1910fb573;p=tpg%2Facess2.git diff --git a/Usermode/Applications/axwin3_src/WM/ipc.c b/Usermode/Applications/axwin3_src/WM/ipc.c index da56149b..44601841 100644 --- a/Usermode/Applications/axwin3_src/WM/ipc.c +++ b/Usermode/Applications/axwin3_src/WM/ipc.c @@ -12,6 +12,9 @@ #include #include #include +#include +#include // Hotkey registration +#include // Renderer IPC messages #define AXWIN_PORT 4101 @@ -37,6 +40,8 @@ struct sIPC_Client tWindow **Windows; }; +// === IMPORTS === +extern tWindow *gpWM_FocusedWindow; // Needed for _FocusWindow // === PROTOTYPES === void IPC_Init(void); @@ -48,7 +53,11 @@ void IPC_Type_Datagram_Send(const void *Ident, size_t Length, const void *Data); int IPC_Type_Sys_GetSize(const void *Ident); int IPC_Type_Sys_Compare(const void *Ident1, const void *Ident2); void IPC_Type_Sys_Send(const void *Ident, size_t Length, const void *Data); -void IPC_Handle(const tIPC_Type *IPCType, const void *Ident, size_t MsgLen, tAxWin_IPCMessage *Msg); + int IPC_Type_IPCPipe_GetSize(const void *Ident); + int IPC_Type_IPCPipe_Compare(const void *Ident1, const void *Ident2); +void IPC_Type_IPCPipe_Send(const void *Ident, size_t Length, const void *Data); +tIPC_Client *IPC_int_GetClient(const tIPC_Type *IPCType, const void *Ident); +void IPC_Handle(tIPC_Client *Client, size_t MsgLen, tAxWin_IPCMessage *Msg); // === GLOBALS === const tIPC_Type gIPC_Type_Datagram = { @@ -60,9 +69,14 @@ const tIPC_Type gIPC_Type_SysMessage = { IPC_Type_Sys_GetSize, IPC_Type_Sys_Compare, IPC_Type_Sys_Send +}; +const tIPC_Type gIPC_Type_IPCPipe = { + IPC_Type_IPCPipe_GetSize, + IPC_Type_IPCPipe_Compare, + IPC_Type_IPCPipe_Send }; int giNetworkFileHandle = -1; - int giMessagesFileHandle = -1; + int giIPCPipeHandle = -1; int giIPC_ClientCount; tIPC_Client **gIPC_Clients; @@ -71,41 +85,86 @@ void IPC_Init(void) { int tmp; // TODO: Check this - giNetworkFileHandle = open("/Devices/ip/loop/udp", OPENFLAG_READ); - tmp = AXWIN_PORT; ioctl(giNetworkFileHandle, 4, &tmp); // TODO: Don't hard-code IOCtl number + giNetworkFileHandle = _SysOpen("/Devices/ip/loop/udp", OPENFLAG_READ); + if( giNetworkFileHandle != -1 ) + { + tmp = AXWIN_PORT; + _SysIOCtl(giNetworkFileHandle, 4, &tmp); // TODO: Don't hard-code IOCtl number + } + + giIPCPipeHandle = _SysOpen("/Devices/ipcpipe/axwin"/*-$USER*/, OPENFLAG_CREATE); + _SysDebug("giIPCPipeHandle = %i", giIPCPipeHandle); + if( giIPCPipeHandle == -1 ) + _SysDebug("ERROR: Can't create IPCPipe handle"); +} + +void _setfd(int fd, int *nfds, fd_set *set) +{ + if( fd >= 0 ) + { + if( fd >= *nfds ) *nfds = fd+1; + FD_SET(fd, set); + } } void IPC_FillSelect(int *nfds, fd_set *set) { - if( giNetworkFileHandle > *nfds ) *nfds = giNetworkFileHandle; - FD_SET(giNetworkFileHandle, set); + _setfd(giNetworkFileHandle, nfds, set); + _setfd(giIPCPipeHandle, nfds, set); + for( int i = 0; i < giIPC_ClientCount; i ++ ) + { + if( gIPC_Clients[i] && gIPC_Clients[i]->IPCType == &gIPC_Type_IPCPipe ) + _setfd( *(int*)(gIPC_Clients[i]->Ident), nfds, set ); + } } void IPC_HandleSelect(fd_set *set) { - if( FD_ISSET(giNetworkFileHandle, set) ) + if( giNetworkFileHandle != -1 && FD_ISSET(giNetworkFileHandle, set) ) { char staticBuf[STATICBUF_SIZE]; int readlen, identlen; char *msg; - readlen = read(giNetworkFileHandle, staticBuf, sizeof(staticBuf)); + readlen = _SysRead(giNetworkFileHandle, staticBuf, sizeof(staticBuf)); identlen = 4 + Net_GetAddressSize( ((uint16_t*)staticBuf)[1] ); msg = staticBuf + identlen; - IPC_Handle(&gIPC_Type_Datagram, staticBuf, readlen - identlen, (void*)msg); -// _SysDebug("IPC_HandleSelect: UDP handled"); + IPC_Handle( IPC_int_GetClient(&gIPC_Type_Datagram, staticBuf), readlen - identlen, (void*)msg); + //_SysDebug("IPC_HandleSelect: UDP handled"); + } + + if( giIPCPipeHandle != -1 && FD_ISSET(giIPCPipeHandle, set) ) + { + int newfd = _SysOpenChild(giIPCPipeHandle, "newclient", OPENFLAG_READ|OPENFLAG_WRITE); + _SysDebug("newfd = %i"); + IPC_int_GetClient(&gIPC_Type_IPCPipe, &newfd); + } + + for( int i = 0; i < giIPC_ClientCount; i ++ ) + { + if( gIPC_Clients[i] && gIPC_Clients[i]->IPCType == &gIPC_Type_IPCPipe ) + { + int fd = *(const int*)gIPC_Clients[i]->Ident; + if( FD_ISSET(fd, set) ) + { + char staticBuf[STATICBUF_SIZE]; + size_t len; + len = _SysRead(fd, staticBuf, sizeof(staticBuf)); + IPC_Handle( gIPC_Clients[i], len, (void*)staticBuf ); + } + } } - while(SysGetMessage(NULL, NULL)) + size_t len; + int tid; + while( (len = _SysGetMessage(&tid, 0, NULL)) ) { - pid_t tid; - int len = SysGetMessage(&tid, NULL); char data[len]; - SysGetMessage(NULL, data); + _SysGetMessage(NULL, len, data); - IPC_Handle(&gIPC_Type_SysMessage, &tid, len, (void*)data); + IPC_Handle( IPC_int_GetClient(&gIPC_Type_SysMessage, &tid), len, (void*)data ); // _SysDebug("IPC_HandleSelect: Message handled"); } } @@ -130,7 +189,7 @@ void IPC_Type_Datagram_Send(const void *Ident, size_t Length, const void *Data) memcpy(tmpbuf, Ident, identlen); // Header memcpy(tmpbuf + identlen, Data, Length); // Data // TODO: Handle fragmented packets - write(giNetworkFileHandle, tmpbuf, sizeof(tmpbuf)); + _SysWrite(giNetworkFileHandle, tmpbuf, sizeof(tmpbuf)); } int IPC_Type_Sys_GetSize(const void *Ident) @@ -145,7 +204,23 @@ int IPC_Type_Sys_Compare(const void *Ident1, const void *Ident2) void IPC_Type_Sys_Send(const void *Ident, size_t Length, const void *Data) { - SysSendMessage( *(const tid_t*)Ident, Length, Data ); + _SysSendMessage( *(const tid_t*)Ident, Length, Data ); +} + +int IPC_Type_IPCPipe_GetSize(const void *Ident) +{ + return sizeof(int); +} +int IPC_Type_IPCPipe_Compare(const void *Ident1, const void *Ident2) +{ + return *(const int*)Ident1 - *(const int*)Ident2; +} +void IPC_Type_IPCPipe_Send(const void *Ident, size_t Length, const void *Data) +{ + size_t rv = _SysWrite( *(const int*)Ident, Data, Length ); + if(rv != Length) { + _SysDebug("Sent message oversize %x", Length); + } } // --- Client -> Window Mappings @@ -153,7 +228,10 @@ int _CompareClientPtrs(const void *_a, const void *_b) { tIPC_Client *a = *(tIPC_Client**)_a; tIPC_Client *b = *(tIPC_Client**)_b; - + + ASSERT(a); + ASSERT(b); + if(a->IPCType < b->IPCType) return -1; if(a->IPCType > b->IPCType) return 1; @@ -230,7 +308,6 @@ tWindow *IPC_int_GetWindow(tIPC_Client *Client, uint32_t WindowID) return NULL; if( WindowID >= Client->nWindows ) { -// _SysDebug("Window %i out of range for %p (%i)", WindowID, Client, Client->nWindows); return NULL; } @@ -256,10 +333,88 @@ void IPC_int_SetWindow(tIPC_Client *Client, uint32_t WindowID, tWindow *WindowPt } // --- IPC Message Handlers --- +int IPC_Msg_Ping(tIPC_Client *Client, tAxWin_IPCMessage *Msg) +{ + ASSERT(Msg->ID == IPCMSG_PING); + + if( !(Msg->Flags & IPCMSG_FLAG_RETURN) ) return 0; + + if( Msg->Size < 4 ) return -1; + + tIPCMsg_ReturnInt *ret = (void*)Msg->Data; + Msg->ID = IPCMSG_PING; + Msg->Size = sizeof(*ret); + ret->Value = AXWIN_VERSION; + Client->IPCType->SendMessage(Client->Ident, sizeof(*Msg)+sizeof(*ret), Msg); + return 0; +} + +int IPC_Msg_GetDisplayCount(tIPC_Client *Client, tAxWin_IPCMessage *Msg) +{ + tAxWin_IPCMessage *ret_hdr; + tIPCMsg_ReturnInt *ret; + char buf[sizeof(*ret_hdr)+sizeof(*ret)]; + + ASSERT(Msg->ID == IPCMSG_GETDISPLAYCOUNT); + + if( !(Msg->Flags & IPCMSG_FLAG_RETURN) ) return 0; + + ret_hdr = (void*)buf; + ret_hdr->ID = IPCMSG_GETDISPLAYCOUNT; + ret_hdr->Flags = 0; + ret_hdr->Window = -1; + ret_hdr->Size = sizeof(*ret); + ret = (void*)ret_hdr->Data; + ret->Value = 1; // HARD CODE - Current version only supports one display + + Client->IPCType->SendMessage(Client->Ident, sizeof(buf), buf); + return 0; +} + +int IPC_Msg_GetDisplayDims(tIPC_Client *Client, tAxWin_IPCMessage *Msg) +{ + tIPCMsg_GetDisplayDims *info; + tAxWin_IPCMessage *ret_hdr; + tIPCMsg_RetDisplayDims *ret; + char buf[sizeof(*ret_hdr)+sizeof(*ret)]; + + ASSERT(Msg->ID == IPCMSG_GETDISPLAYDIMS); + + if( !(Msg->Flags & IPCMSG_FLAG_RETURN) ) return 0; + + info = (void*)Msg->Data; + + ret_hdr = (void*)buf; + ret_hdr->ID = IPCMSG_GETDISPLAYDIMS; + ret_hdr->Flags = 0; + ret_hdr->Window = -1; + ret_hdr->Size = sizeof(*ret); + ret = (void*)ret_hdr->Data; + + // HARD CODE! Only one display supported + if( info->DisplayID == 0 ) + { + ret->X = 0; + ret->Y = 0; + ret->W = giScreenWidth; + ret->H = giScreenHeight; + } + else + { + ret->X = 0; ret->Y = 0; + ret->W = 0; ret->H = 0; + } + + Client->IPCType->SendMessage(Client->Ident, sizeof(buf), buf); + return 0; +} + int IPC_Msg_SendMsg(tIPC_Client *Client, tAxWin_IPCMessage *Msg) { tIPCMsg_SendMsg *info = (void*)Msg->Data; tWindow *src, *dest; + + ASSERT(Msg->ID == IPCMSG_SENDMSG); // - Sanity checks if( Msg->Size < sizeof(tIPCMsg_SendMsg) ) @@ -282,6 +437,8 @@ int IPC_Msg_CreateWin(tIPC_Client *Client, tAxWin_IPCMessage *Msg) tIPCMsg_CreateWin *info = (void*)Msg->Data; tWindow *newwin, *parent; + ASSERT(Msg->ID == IPCMSG_CREATEWIN); + // - Sanity checks // > +1 is for NULL byte on string if( Msg->Size < sizeof(*info) + 1 ) { @@ -312,18 +469,83 @@ int IPC_Msg_CreateWin(tIPC_Client *Client, tAxWin_IPCMessage *Msg) return 0; } +int IPC_Msg_DestroyWin(tIPC_Client *Client, tAxWin_IPCMessage *Msg) +{ + tWindow *win; + + ASSERT(Msg->ID == IPCMSG_DESTROYWIN); + + win = IPC_int_GetWindow(Client, Msg->Window); + if( !win ) + return 0; + + WM_DestroyWindow(win); + return 0; +} + +int IPC_Msg_SetWindowTitle(tIPC_Client *Client, tAxWin_IPCMessage *Msg) +{ + tWindow *win; + + ASSERT(Msg->ID == IPCMSG_SETWINTITLE); + + if( Msg->Size < 1 ) return -1; + if( Msg->Data[ Msg->Size-1 ] != '\0' ) return -1; + + win = IPC_int_GetWindow(Client, Msg->Window); + if(!win) return 1; + + WM_SetWindowTitle(win, Msg->Data); + + return 0; +} + int IPC_Msg_ShowWindow(tIPC_Client *Client, tAxWin_IPCMessage *Msg) { - tIPCMsg_ShowWindow *info = (void*)Msg->Data; + tIPCMsg_Boolean *info = (void*)Msg->Data; + tWindow *win; + + ASSERT(Msg->ID == IPCMSG_SHOWWINDOW); + + if( Msg->Size < sizeof(*info) ) return -1; + + win = IPC_int_GetWindow(Client, Msg->Window); + if(!win) return 1; + + WM_ShowWindow(win, !!info->Value); + + return 0; +} + +int IPC_Msg_DecorateWindow(tIPC_Client *Client, tAxWin_IPCMessage *Msg) +{ + tIPCMsg_Boolean *info = (void*)Msg->Data; tWindow *win; if( Msg->Size < sizeof(*info) ) return -1; win = IPC_int_GetWindow(Client, Msg->Window); if(!win) return 1; + + WM_DecorateWindow(win, !!info->Value); + return 0; +} - WM_ShowWindow(win, !!info->bShow); +int IPC_Msg_FocusWindow(tIPC_Client *Client, tAxWin_IPCMessage *Msg) +{ + tWindow *win; + + ASSERT(Msg->ID == IPCMSG_FOCUSWINDOW); + // Don't allow the focus to be changed unless the client has the focus +// if(!gpWM_FocusedWindow) return 1; +// if(gpWM_FocusedWindow->Client != Client) return 1; + + win = IPC_int_GetWindow(Client, Msg->Window); + if(!win) return 1; + + WM_FocusWindow(win); + return 0; } @@ -332,6 +554,8 @@ int IPC_Msg_SetWinPos(tIPC_Client *Client, tAxWin_IPCMessage *Msg) tIPCMsg_SetWindowPos *info = (void*)Msg->Data; tWindow *win; + ASSERT(Msg->ID == IPCMSG_SETWINPOS); + if(Msg->Size < sizeof(*info)) return -1; win = IPC_int_GetWindow(Client, Msg->Window); @@ -347,136 +571,102 @@ int IPC_Msg_SetWinPos(tIPC_Client *Client, tAxWin_IPCMessage *Msg) return 0; } -int IPC_Msg_GetDisplayCount(tIPC_Client *Client, tAxWin_IPCMessage *Msg) +int IPC_Msg_RegisterAction(tIPC_Client *Client, tAxWin_IPCMessage *Msg) { - tAxWin_IPCMessage *ret_hdr; - tIPCMsg_ReturnInt *ret; - char buf[sizeof(*ret_hdr)+sizeof(*ret)]; - - if( !(Msg->Flags & IPCMSG_FLAG_RETURN) ) return 0; - - ret_hdr = (void*)buf; - ret_hdr->ID = IPCMSG_GETDISPLAYCOUNT; - ret_hdr->Flags = 0; - ret_hdr->Window = -1; - ret_hdr->Size = sizeof(*ret); - ret = (void*)ret_hdr->Data; - ret->Value = 1; // HARD CODE - Current version only supports one display + tIPCMsg_RegAction *info = (void*)Msg->Data; + tWindow *win; - Client->IPCType->SendMessage(Client->Ident, sizeof(buf), buf); - return 0; -} + ASSERT(Msg->ID == IPCMSG_REGACTION); -int IPC_Msg_GetDisplayDims(tIPC_Client *Client, tAxWin_IPCMessage *Msg) -{ - tIPCMsg_GetDisplayDims *info; - tAxWin_IPCMessage *ret_hdr; - tIPCMsg_RetDisplayDims *ret; - char buf[sizeof(*ret_hdr)+sizeof(*ret)]; + if( Msg->Size < sizeof(*info) + 1 ) + return -1; - if( !(Msg->Flags & IPCMSG_FLAG_RETURN) ) return 0; + win = IPC_int_GetWindow(Client, Msg->Window); + if(!win) return 1; - info = (void*)Msg->Data; + if( strnlen(info->Action, Msg->Size - sizeof(*info)) == Msg->Size - sizeof(*info) ) + return 1; + + _SysDebug("RegisterAction %p:%i [%i]\"%s\"", + Client, Msg->Window, info->Index, info->Action + ); + + WM_Hotkey_RegisterAction(info->Action, win, info->Index); - ret_hdr = (void*)buf; - ret_hdr->ID = IPCMSG_GETDISPLAYDIMS; - ret_hdr->Flags = 0; - ret_hdr->Window = -1; - ret_hdr->Size = sizeof(*ret); - ret = (void*)ret_hdr->Data; - - // HARD CODE! Only one display supported - if( info->DisplayID == 0 ) - { - ret->X = 0; - ret->Y = 0; - ret->W = giScreenWidth; - ret->H = giScreenHeight; - } - else - { - ret->X = 0; ret->Y = 0; - ret->W = 0; ret->H = 0; - } - - Client->IPCType->SendMessage(Client->Ident, sizeof(buf), buf); return 0; } -void IPC_Handle(const tIPC_Type *IPCType, const void *Ident, size_t MsgLen, tAxWin_IPCMessage *Msg) +int (*gIPC_MessageHandlers[])(tIPC_Client *Client, tAxWin_IPCMessage *Msg) = { + IPC_Msg_Ping, + IPC_Msg_GetDisplayCount, + IPC_Msg_GetDisplayDims, + IPC_Msg_SendMsg, + IPC_Msg_CreateWin, + IPC_Msg_DestroyWin, // Destroy window + IPC_Msg_SetWindowTitle, + IPC_Msg_ShowWindow, + IPC_Msg_DecorateWindow, + IPC_Msg_FocusWindow, + IPC_Msg_SetWinPos, + IPC_Msg_RegisterAction +}; +const int giIPC_NumMessageHandlers = sizeof(gIPC_MessageHandlers)/sizeof(gIPC_MessageHandlers[0]); + +void IPC_Handle(tIPC_Client *Client, size_t MsgLen, tAxWin_IPCMessage *Msg) { - tIPC_Client *client; int rv = 0; - _SysDebug("IPC_Handle: (IPCType=%p, Ident=%p, MsgLen=%i, Msg=%p)", - IPCType, Ident, MsgLen, Msg); +// _SysDebug("IPC_Handle: (IPCType=%p, Ident=%p, MsgLen=%i, Msg=%p)", +// IPCType, Ident, MsgLen, Msg); if( MsgLen < sizeof(tAxWin_IPCMessage) ) return ; if( MsgLen < sizeof(tAxWin_IPCMessage) + Msg->Size ) return ; - client = IPC_int_GetClient(IPCType, Ident); - - switch((enum eAxWin_IPCMessageTypes) Msg->ID) + if( Msg->Flags & IPCMSG_FLAG_RENDERER ) { - // --- Ping message (reset timeout and get server version) - case IPCMSG_PING: - _SysDebug(" IPC_Handle: IPCMSG_PING"); - if( Msg->Size < 4 ) return; - if( Msg->Flags & IPCMSG_FLAG_RETURN ) - { - tIPCMsg_ReturnInt *ret = (void*)Msg->Data; - Msg->ID = IPCMSG_PING; - Msg->Size = sizeof(*ret); - ret->Value = AXWIN_VERSION; - IPCType->SendMessage(Ident, sizeof(*Msg)+sizeof(*ret), Msg); + tWindow *win = IPC_int_GetWindow(Client, Msg->Window); + if( !win ) { + _SysDebug("WARNING: NULL window in message %i", Msg->ID); + return ; } - break; - - // -- Get display count - case IPCMSG_GETDISPLAYCOUNT: - rv = IPC_Msg_GetDisplayCount(client, Msg); - break; - - // --- Get display dimensions - case IPCMSG_GETDISPLAYDIMS: - rv = IPC_Msg_GetDisplayDims(client, Msg); - break; - - // --- Send a message - case IPCMSG_SENDMSG: - _SysDebug(" IPC_Handle: IPCMSG_SENDMSG %i", ((tIPCMsg_SendMsg*)Msg->Data)->ID); - rv = IPC_Msg_SendMsg(client, Msg); - break; - - // --- Create window - case IPCMSG_CREATEWIN: - _SysDebug(" IPC_Handle: IPCMSG_CREATEWIN"); - rv = IPC_Msg_CreateWin(client, Msg); - break; - // --- Show/Hide a window - case IPCMSG_SHOWWINDOW: - _SysDebug(" IPC_Handle: IPCMSG_SHOWWINDOW"); - rv = IPC_Msg_ShowWindow(client, Msg); - break; - // --- Move/Resize a window - case IPCMSG_SETWINPOS: - _SysDebug(" IPC_Handle: IPCMSG_SETWINPOS"); - rv = IPC_Msg_SetWinPos(client, Msg); - break; - - // --- Unknown message - default: - fprintf(stderr, "WARNING: Unknown message %i (%p)\n", Msg->ID, IPCType); - _SysDebug("WARNING: Unknown message %i (%p)", Msg->ID, IPCType); - break; + tWMRenderer *renderer = win->Renderer; + if( Msg->ID >= renderer->nIPCHandlers ) { + _SysDebug("WARNING: Message %i out of range in %s", Msg->ID, renderer->Name); + return ; + } + if( !renderer->IPCHandlers[Msg->ID] ) { + _SysDebug("WARNING: Message %i has no handler in %s", Msg->ID, renderer->Name); + return ; + } + _SysDebug("IPC_Handle: Call %s-%i", renderer->Name, Msg->ID); + rv = renderer->IPCHandlers[Msg->ID](win, Msg->Size, Msg->Data); + if( rv ) + _SysDebug("IPC_Handle: rv != 0 (%i)", rv); + } + else + { + if( Msg->ID >= giIPC_NumMessageHandlers ) { + fprintf(stderr, "WARNING: Unknown message %i (%p)\n", Msg->ID, Client); + _SysDebug("WARNING: Unknown message %i (%p)", Msg->ID, Client); + return ; + } + + if( !gIPC_MessageHandlers[ Msg->ID ] ) { + fprintf(stderr, "WARNING: Message %i does not have a handler\n", Msg->ID); + _SysDebug("WARNING: Message %i does not have a handler", Msg->ID); + return ; + } + + _SysDebug("IPC_Handle: Call WM-%i", Msg->ID); + rv = gIPC_MessageHandlers[Msg->ID](Client, Msg); + if( rv ) + _SysDebug("IPC_Handle: rv != 0 (%i)", rv); } - if(rv) - _SysDebug("IPC_Handle: rv = %i", rv); } -// --- Server->Client replies +// Dispatch a message to the client void IPC_SendWMMessage(tIPC_Client *Client, uint32_t Src, uint32_t Dst, int MsgID, int Len, void *Data) { tAxWin_IPCMessage *hdr; @@ -499,3 +689,20 @@ void IPC_SendWMMessage(tIPC_Client *Client, uint32_t Src, uint32_t Dst, int MsgI Client->IPCType->SendMessage(Client->Ident, sizeof(buf), buf); } +// --- Server->Client replies +void IPC_SendReply(tIPC_Client *Client, uint32_t WinID, int MsgID, size_t Len, const void *Data) +{ + tAxWin_IPCMessage *hdr; + char buf[sizeof(*hdr)+Len]; + + hdr = (void*)buf; + + hdr->ID = MsgID; + hdr->Flags = IPCMSG_FLAG_RENDERER; + hdr->Size = Len; + hdr->Window = WinID; + + memcpy(hdr->Data, Data, Len); + Client->IPCType->SendMessage(Client->Ident, sizeof(buf), buf); +} +