void SetReturnValue(Type retType, object retValue) { if (retType == typeof(ushort)) { _machine.ax = (ushort)retValue; return; } if (retType == typeof(short)) { _machine.ax = unchecked ((ushort)(short)retValue); return; } if (retType == typeof(uint)) { _machine.dxax = (uint)retValue; return; } if (retType == typeof(int)) { _machine.dxax = unchecked ((uint)(int)retValue); return; } if (retType == typeof(bool)) { _machine.ax = (ushort)(((bool)retValue) ? 1U : 0U); return; } if (retType == typeof(void)) { // nop return; } if (MappedTypeAttribute.Is(retType)) { var convertMethod = retType.GetMethod("To16"); var retValue16 = convertMethod.Invoke(null, new object[] { retValue }); SetReturnValue(convertMethod.ReturnType, retValue16); return; } throw new NotImplementedException(string.Format("Return type not supported by thunking layer - {0}", retType)); }
object ReadParamFromStack(Type pt, ParameterInfo pi) { if (pt == null) { pt = pi.ParameterType; } if (pt == typeof(ushort)) { var val = _machine.ReadWord(_machine.ss, _paramPos); _paramPos += 2; return(val); } if (pt == typeof(short)) { var val = unchecked ((short)_machine.ReadWord(_machine.ss, _paramPos)); _paramPos += 2; return(val); } if (pt == typeof(byte)) { var val = _machine.ReadByte(_machine.ss, _paramPos); _paramPos += 2; return(val); } if (pt == typeof(uint)) { var val = _machine.ReadDWord(_machine.ss, _paramPos); _paramPos += 4; return(val); } if (pt == typeof(int)) { var val = unchecked ((int)_machine.ReadDWord(_machine.ss, _paramPos)); _paramPos += 4; return(val); } if (pt == typeof(string)) { var ptrOffset = _machine.ReadWord(_machine.ss, _paramPos); var ptrSeg = _machine.ReadWord(_machine.ss, (ushort)(_paramPos + 2)); var val = _machine.ReadString(ptrSeg, ptrOffset); _paramPos += 4; if (pi != null) { var fna = pi.GetCustomAttribute <FileNameAttribute>(); if (fna != null) { val = _machine.PathMapper.MapGuestToHost(val, fna.ForWrite); } } return(val); } if (pt == typeof(StringOrId)) { var ptrOffset = _machine.ReadWord(_machine.ss, _paramPos); var ptrSeg = _machine.ReadWord(_machine.ss, (ushort)(_paramPos + 2)); var val = new StringOrId(_machine, BitUtils.MakeDWord(ptrOffset, ptrSeg)); _paramPos += 4; return(val); } if (pt == typeof(bool)) { var val = _machine.ReadWord(_machine.ss, _paramPos) != 0; _paramPos += 2; return(val); } if (pt == typeof(StringBuilder)) { // Capture stuff, we'll do it later int paramIndex = _currentParameterIndex; // Get input string pointer var ptrOffset = _machine.ReadWord(_machine.ss, _paramPos); var ptrSeg = _machine.ReadWord(_machine.ss, (ushort)(_paramPos + 2)); _paramPos += 4; int capacity = 0; bool isOut = pi.GetCustomAttribute <OutAttribute>() != null; bool isIn = pi.GetCustomAttribute <InAttribute>() != null; var fna = pi.GetCustomAttribute <FileNameAttribute>(); RegisterPreInvokeCallback(() => { // Work out buffer size capacity var bufsize = pi.GetCustomAttribute <BufSizeAttribute>(); int bufsizeParamIndex = paramIndex + bufsize.ParamDX; var type = _paramValues[bufsizeParamIndex].GetType(); if (type == typeof(int)) { capacity = (int)_paramValues[bufsizeParamIndex]; } else if (type == typeof(ushort)) { capacity = (int)(ushort)_paramValues[bufsizeParamIndex]; } else if (type == typeof(nint)) { capacity = (nint)_paramValues[bufsizeParamIndex]; } else { throw new NotImplementedException(); } // Create string builder var sb = new StringBuilder(fna != null ? 512 : capacity); if (isIn) { var str = _machine.ReadString(ptrSeg, ptrOffset, (ushort)capacity); if (fna != null) { _machine.PathMapper.MapGuestToHost(str, fna.ForWrite); } sb.Append(str); } // Return the string builder _paramValues[paramIndex] = sb; }); if (isOut) { RegisterPostInvokeCallback(() => { var str = _paramValues[paramIndex].ToString(); if (fna != null) { str = _machine.PathMapper.MapHostToGuest(str, fna.ForWrite); } _machine.WriteString(ptrSeg, ptrOffset, str, (ushort)capacity); }); } return(null); // We'll fill it in later } if (pt == typeof(Win32.POINT)) { var x = unchecked ((short)_machine.ReadWord(_machine.ss, _paramPos)); var y = unchecked ((short)_machine.ReadWord(_machine.ss, (ushort)(_paramPos + 2))); _paramPos += 4; return(new Win32.POINT(x, y)); } if (pt == typeof(IntPtr)) { if (pi != null) { if (pi.GetCustomAttribute <MustBeNullAttribute>() == null) { throw new NotImplementedException("IntPtr parameters must have MustBeNull attribute"); } } var ptrOffset = _machine.ReadWord(_machine.ss, _paramPos); var ptrSeg = _machine.ReadWord(_machine.ss, (ushort)(_paramPos + 2)); _paramPos += 4; if (ptrOffset != 0 || ptrSeg != 0) { throw new NotImplementedException("Non-null IntPtr parameter passed"); } return(IntPtr.Zero); } if (MappedTypeAttribute.Is(pt)) { var convertMethod = pt.GetMethod("To32"); // Read the 16-bit value var val16 = ReadParamFromStack(convertMethod.GetParameters()[0].ParameterType, null); // Convert it var val32 = convertMethod.Invoke(null, new object[] { val16 }); if (ShouldDestroy(pi)) { RegisterPostInvokeCallback(() => { var destroyMethod = pt.GetMethod("Destroy"); destroyMethod.Invoke(null, new object[] { val16 }); }); } return(val32); } if (pt.IsByRef) { var underlyingType = pt.GetElementType(); if (underlyingType.IsValueType) { var ptr = _machine.ReadDWord(_machine.ss, _paramPos); object val; if (pi == null || !pi.IsOut) { if (MappedTypeAttribute.Is(underlyingType)) { var convertMethod = underlyingType.GetMethod("To32"); val = _machine.ReadStruct(convertMethod.GetParameters()[0].ParameterType, ptr); val = convertMethod.Invoke(null, new object[] { val }); } else { val = _machine.ReadStruct(underlyingType, ptr); } } else { val = Activator.CreateInstance(underlyingType); } _paramPos += 4; if (pi.GetCustomAttribute <InAttribute>() == null) { int index = _currentParameterIndex; RegisterPostInvokeCallback(() => { val = _paramValues[index]; if (MappedTypeAttribute.Is(underlyingType)) { var convertMethod = underlyingType.GetMethod("To16"); val = convertMethod.Invoke(null, new object[] { val }); } if (ptr != 0) { _machine.WriteStruct(ptr, val); } }); } return(val); } } throw new NotImplementedException(string.Format("Parameter type not supported by thunking layer - {0}", pt)); }
ushort SizeOfType16(Type pt) { if (pt == typeof(ushort)) { return(2); } if (pt == typeof(short)) { return(2); } if (pt == typeof(byte)) { return(2); } if (pt == typeof(uint)) { return(4); } if (pt == typeof(int)) { return(4); } if (pt == typeof(string)) { return(4); } if (pt == typeof(StringOrId)) { return(4); } if (pt.IsByRef) { return(4); } if (pt == typeof(bool)) { return(2); } if (pt == typeof(StringBuilder)) { return(4); } if (pt == typeof(IntPtr)) { return(4); } if (pt == typeof(Win32.POINT)) { return(4); } if (pt == typeof(Win16.RECT)) { return(8); } if (MappedTypeAttribute.Is(pt)) { var convertMethod = pt.GetMethod("To32"); return(SizeOfType16(convertMethod.GetParameters()[0].ParameterType)); } throw new NotImplementedException(string.Format("Type not supported by thunking layer - {0}", pt)); }