Byte[] GetBytes <T>(OverlayMsg header, T message)
        {
            Marshal.StructureToPtr(header, readPtr, true);
            IntPtr adjustedPtr = new IntPtr(readPtr.ToInt64() + headerLength);

            Marshal.StructureToPtr(message, adjustedPtr, true);
            Marshal.Copy(readPtr, readBuffer, 0, (Int32)OverlayConstants.OVERLAY_STRUCT_LENGTH);

            return(readBuffer);
        }
        public void writeTo <T>(NamedPipeClientStream pipe, OverlayMsgType type, T message)
        {
            OverlayMsg header     = new OverlayMsg();
            Int32      typeLength = Marshal.SizeOf(typeof(T));

            header.overlayMsgHeader.magic  = OverlayConstants.OVERLAY_MAGIC_NUMBER;
            header.overlayMsgHeader.length = typeLength;
            header.overlayMsgHeader.type   = type;

            pipe.Write(GetBytes(header, message), 0, headerLength + typeLength);
        }
        public void WaitForRead()
        {
            try
            {
                while (overlayPipe.CanRead && overlayPipe.IsConnected)
                {
                    OverlayMsg header = buffer.readHeaderFrom(overlayPipe);

                    Int32 typeLength = header.overlayMsgHeader.length;

                    switch (header.overlayMsgHeader.type)
                    {
                    case OverlayMsgType.Shmem:
                    {
                        var shmem = buffer.readFrom <OverlayMsgShmem>(overlayPipe, typeLength);

                        String shmemKey = null;
                        unsafe
                        {
                            // length - 1 to remove trailing \0
                            shmemKey = new String(shmem.name, 0, typeLength - 1);
                        }

                        if (shmemKey != null)
                        {
                            bitmap.UpdateSharedMemoryKey(shmemKey);
                        }
                        else
                        {
                            API.Instance.Log("Unable to decode shmem key");
                            continue;
                        }

                        break;
                    }

                    case OverlayMsgType.Blit:
                    {
                        var blit = buffer.readFrom <OverlayMsgBlit>(overlayPipe, typeLength);

                        if (blit.x + blit.width > bitmap.Width ||
                            blit.y + blit.height > bitmap.Height)
                        {
                            API.Instance.Log("Invalid width and height of blit request; Expected w={0},h={1} got w={2},h={3}",
                                             bitmap.Width,
                                             bitmap.Height,
                                             blit.x + blit.width,
                                             blit.y + blit.height);

                            break;
                        }

                        frameCount++;

                        if (!bitmap.Fetch())
                        {
                            API.Instance.Log("Fetch of bitmap from shared memory failed");
                        }

                        float elapsed = (float)(stopwatch.Elapsed.TotalMilliseconds - lastFpsUpdate) / 1000;
                        if (elapsed > OverlayConstants.OVERLAY_FPS_INTERVAL)
                        {
                            OverlayMsgFps fps = new OverlayMsgFps();
                            // really? int?
                            fps.fps = (float)frameCount / elapsed;
                            buffer.writeTo(overlayPipe, OverlayMsgType.Fps, fps);

                            frameCount    = 0;
                            lastFpsUpdate = 0;
                            stopwatch.Restart();
                        }
                        break;
                    }

                    case OverlayMsgType.Active:
                    {
                        var active = buffer.readFrom <OverlayMsgActive>(overlayPipe, typeLength);
                        break;
                    }
                    }
                }
            }
            catch (ThreadAbortException e)
            {
                API.Instance.Log("OverlayHookThread aborted; {0}", e.Message);
            }
        }