【问题标题】:Unbalanced Stack Problem不平衡堆栈问题
【发布时间】:2011-03-01 13:11:46
【问题描述】:

感谢我在周五的“c# 重复 console.writeline 命令问题”中获得的所有帮助。我发现我所有的问题都是由“PInvokeStackImbalance”引起的。

  • 我在 WIN7 64 位上使用 C# Express 机器
  • 我调用的 ftcjtag.dll 是 32 位 c++ dll。我有 64 位版本 这个 dll 可用。
  • 这个dll可以在http://www.ftdichip.com/Support/SoftwareExamples/MPSSE/FTCJTAG/FTCJTAG_200.zip下载
  • 我刚开始编写 c#,到目前为止,我在 Google 上搜索到的所有内容都让我感到困惑,而不是帮助我。我希望你能给我一个提示,我的代码有什么问题或建议做什么。

错误信息:

PInvokeStackImbalance wurde erkannt。 消息:对 PInvoke 函数 'WindowsFormsApplication1!WindowsFormsApplication1.Form1::JTAG_GetHiSpeedDeviceNameLocIDChannel' 的调用使堆栈不平衡。这可能是因为托管 PInvoke 签名与非托管目标签名不匹配。检查 PInvoke 签名的调用约定和参数是否与目标非托管签名匹配。

代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Threading;




namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        uint ftStatus = FTC_SUCCESS;
        //uint numHiSpeedDevices = 0; // 32-bit unsigned integer
        byte[] byteHiSpeedDeviceName = new byte[MAX_NUM_DEVICE_NAME_CHARS];
        byte[] byteHiSpeedDeviceChannel = new byte[MAX_NUM_CHANNEL_CHARS];
        string hiSpeedChannel = null;

        uint locationID = 0;
        //UInt32 locationID = 0;

        uint hiSpeedDeviceType = 1;
        //UInt32 hiSpeedDeviceType = 1;

        //uint clk_div = 0;
        uint numBytesReturned = 0;
        private enum HI_SPEED_DEVICE_TYPES// : uint
        {
            FT2232H_DEVICE_TYPE = 1,
            FT4232H_DEVICE_TYPE = 2
        };
        string hiSpeedDeviceName = null;
        IntPtr ftHandle = IntPtr.Zero;
        public string bPin2LowHighState { get; set; }

        private const string App_Title = "FT2232/FT4232 JTAG Device C# .NET Test Application";
        private const string Dll_Version_Label = "FT2232/FT4232 JTAG DLL Version = ";
        private const string Device_Name_Label = "Device Name = ";

        private const uint FTC_SUCCESS = 0;
        private const uint FTC_DEVICE_IN_USE = 27;
        private const uint TEST_LOGIC_STATE = 1;
        private const uint RUN_TEST_IDLE_STATE = 2;
        private const uint MAX_NUM_DEVICE_NAME_CHARS = 100;
        private const uint MAX_NUM_CHANNEL_CHARS = 5;
        private const uint MAX_NUM_DLL_VERSION_CHARS = 10;
        private const uint MAX_NUM_ERROR_MESSAGE_CHARS = 100;
        private const uint WRITE_DATA_BUFFER_SIZE = 65536;
        private const uint READ_DATA_BUFFER_SIZE = 65536;
        private const uint READ_CMDS_DATA_BUFFER_SIZE = 131071;

        byte[] WriteDataBuffer = new byte[WRITE_DATA_BUFFER_SIZE];
        byte[] ReadDataBuffer = new byte[READ_DATA_BUFFER_SIZE];

        public uint clockFrequencyHz = 0;

        FTC_INPUT_OUTPUT_PINS LowInputOutputPinsData;
        FTH_INPUT_OUTPUT_PINS HighInputOutputPinsData;
        FTC_LOW_HIGH_PINS LowPinsInputData;
        FTH_LOW_HIGH_PINS HighPinsInputData;

        //**************************************************************************
        // TYPE DEFINITIONS
        //**************************************************************************

        public struct FTC_INPUT_OUTPUT_PINS
        {
            public bool bPin1InputOutputState;
            public bool bPin1LowHighState;
            public bool bPin2InputOutputState;
            public bool bPin2LowHighState;
            public bool bPin3InputOutputState;
            public bool bPin3LowHighState;
            public bool bPin4InputOutputState;
            public bool bPin4LowHighState;
        }
        public struct FTH_INPUT_OUTPUT_PINS
        {
            public bool bPin1InputOutputState;
            public bool bPin1LowHighState;
            public bool bPin2InputOutputState;
            public bool bPin2LowHighState;
            public bool bPin3InputOutputState;
            public bool bPin3LowHighState;
            public bool bPin4InputOutputState;
            public bool bPin4LowHighState;
            public bool bPin5InputOutputState;
            public bool bPin5LowHighState;
            public bool bPin6InputOutputState;
            public bool bPin6LowHighState;
            public bool bPin7InputOutputState;
            public bool bPin7LowHighState;
            public bool bPin8InputOutputState;
            public bool bPin8LowHighState;
        }
        public struct FTC_LOW_HIGH_PINS
        {
            public bool bPin1LowHighState;
            public bool bPin2LowHighState;
            public bool bPin3LowHighState;
            public bool bPin4LowHighState;
        }
        public struct FTH_LOW_HIGH_PINS
        {
            public bool bPin1LowHighState;
            public bool bPin2LowHighState;
            public bool bPin3LowHighState;
            public bool bPin4LowHighState;
            public bool bPin5LowHighState;
            public bool bPin6LowHighState;
            public bool bPin7LowHighState;
            public bool bPin8LowHighState;
        }
        public struct FTC_CLOSE_FINAL_STATE_PINS
        {
            public bool bTCKPinState;
            public bool bTCKPinActiveState;
            public bool bTDIPinState;
            public bool bTDIPinActiveState;
            public bool bTMSPinState;
            public bool bTMSPinActiveState;
        }

        //**************************************************************************
        // FUNCTION IMPORTS FROM FTCJTAG DLL
        //**************************************************************************
        [DllImport("ftcjtag.dll", EntryPoint = "JTAG_GetDllVersion", CallingConvention = CallingConvention.Cdecl)]
        static extern uint GetDllVersion(byte[] pDllVersion, uint buufferSize);
        [DllImport("ftcjtag.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern uint JTAG_GetErrorCodeString(string language, uint statusCode, byte[] pErrorMessage, uint bufferSize);
        [DllImport("ftcjtag.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern uint JTAG_GetNumHiSpeedDevices(ref uint NumHiSpeedDevices);
        [DllImport("ftcjtag.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern uint JTAG_GetHiSpeedDeviceNameLocIDChannel(uint deviceNameIndex, byte[] pDeviceName, uint deviceNameBufferSize, ref uint locationID, byte[] pChannel, uint channelBufferSize, ref uint hiSpeedDeviceType);
        [DllImport("ftcjtag.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern uint JTAG_OpenHiSpeedDevice(string DeviceName, uint locationID, string channel, ref IntPtr pftHandle);
        [DllImport("ftcjtag.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern uint JTAG_GetHiSpeedDeviceType(IntPtr ftHandle, ref uint hiSpeedDeviceType);
        [DllImport("ftcjtag.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern uint JTAG_Close(IntPtr ftHandle);
        [DllImport("ftcjtag.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern uint JTAG_CloseDevice(IntPtr ftHandle, ref FTC_CLOSE_FINAL_STATE_PINS pCloseFinalStatePinsData);
        [DllImport("ftcjtag.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern uint JTAG_InitDevice(IntPtr ftHandle, uint clockDivisor);
        [DllImport("ftcjtag.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern uint JTAG_TurnOnDivideByFiveClockingHiSpeedDevice(IntPtr ftHandle);
        [DllImport("ftcjtag.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern uint JTAG_TurnOffDivideByFiveClockingHiSpeedDevice(IntPtr ftHandle);
        [DllImport("ftcjtag.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern uint JTAG_TurnOnAdaptiveClockingHiSpeedDevice(IntPtr ftHandle);
        [DllImport("ftcjtag.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern uint JTAG_TurnOffAdaptiveClockingHiSpeedDevice(IntPtr ftHandle);
        [DllImport("ftcjtag.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern uint JTAG_SetDeviceLatencyTimer(IntPtr ftHandle, byte timerValue);
        [DllImport("ftcjtag.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern uint JTAG_GetDeviceLatencyTimer(IntPtr ftHandle, ref byte timerValue);
        [DllImport("ftcjtag.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern uint JTAG_GetHiSpeedDeviceClock(uint ClockDivisor, ref uint clockFrequencyHz);
        [DllImport("ftcjtag.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern uint JTAG_GetClock(uint clockDivisor, ref uint clockFrequencyHz);
        [DllImport("ftcjtag.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern uint JTAG_SetClock(IntPtr ftHandle, uint clockDivisor, ref uint clockFrequencyHz);
        [DllImport("ftcjtag.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern uint JTAG_SetLoopback(IntPtr ftHandle, bool loopBackState);
        [DllImport("ftcjtag.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern uint JTAG_SetHiSpeedDeviceGPIOs(IntPtr ftHandle, bool bControlLowInputOutputPins, ref FTC_INPUT_OUTPUT_PINS pLowInputOutputPinsData, bool bControlHighInputOutputPins, ref FTH_INPUT_OUTPUT_PINS pHighInputOutputPinsData);
        [DllImport("ftcjtag.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern uint JTAG_GetHiSpeedDeviceGPIOs(IntPtr ftHandle, bool bControlLowInputOutputPins, out FTC_LOW_HIGH_PINS pLowPinsInputData, bool bControlHighInputOutputPins, out FTH_LOW_HIGH_PINS pHighPinsInputData);
        [DllImport("ftcjtag.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern uint JTAG_Write(IntPtr ftHandle, bool bInstructionTestData, uint numBitsToWrite, byte[] WriteDataBuffer, uint numBytesToWrite, uint tapControllerState);
        [DllImport("ftcjtag.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern uint JTAG_Read(IntPtr ftHandle, bool bInstructionTestData, uint numBitsToRead, byte[] ReadDataBuffer, ref uint numBytesReturned, uint tapControllerState);
        [DllImport("ftcjtag.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern uint JTAG_WriteRead(IntPtr ftHandle, bool bInstructionTestData, uint numBitsToWriteRead, byte[] WriteDataBuffer, uint numBytesToWrite, byte[] ReadDataBuffer, ref uint numBytesReturned, uint tapControllerState);
        [DllImport("ftcjtag.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern uint JTAG_GenerateClockPulses(IntPtr ftHandle, uint numClockPulses);
        [DllImport("ftcjtag.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern uint JTAG_ClearCmdSequence();
        [DllImport("ftcjtag.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern uint JTAG_AddWriteCmd(bool bInstructionTestData, uint numBitsToWrite, byte[] WriteDataBuffer, uint numBytesToWrite, uint tapControllerState);
        [DllImport("ftcjtag.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern uint JTAG_AddReadCmd(bool bInstructionTestData, uint numBitsToRead, uint tapControllerState);
        [DllImport("ftcjtag.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern uint JTAG_AddWriteReadCmd(bool bInstructionTestData, uint numBitsToWriteRead, byte[] WriteDataBuffer, uint numBytesToWrite, uint tapControllerState);
        [DllImport("ftcjtag.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern uint JTAG_ExecuteCmdSequence(IntPtr ftHandle, byte[] ReadCmdSequenceDataBuffer, ref uint numBytesReturned);
        [DllImport("ftcjtag.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern uint JTAG_ClearDeviceCmdSequence(IntPtr ftHandle);
        [DllImport("ftcjtag.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern uint JTAG_AddDeviceWriteCmd(IntPtr ftHandle, bool bInstructionTestData, uint numBitsToWrite, byte[] WriteDataBuffer, uint numBytesToWrite, uint tapControllerState);
        [DllImport("ftcjtag.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern uint JTAG_AddDeviceReadCmd(IntPtr ftHandle, bool bInstructionTestData, uint numBitsToRead, uint tapControllerState);
        [DllImport("ftcjtag.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern uint JTAG_AddDeviceWriteReadCmd(IntPtr ftHandle, bool bInstructionTestData, uint numBitsToWriteRead, byte[] WriteDataBuffer, uint numBytesToWrite, uint tapControllerState);

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            LowInputOutputPinsData.bPin1InputOutputState = true;    //true= Enable TCK, TMS and TDI outputs
            LowInputOutputPinsData.bPin2InputOutputState = false;
            LowInputOutputPinsData.bPin3InputOutputState = false;
            LowInputOutputPinsData.bPin4InputOutputState = false;
            LowInputOutputPinsData.bPin1LowHighState = false;       //false= Enable TCK, TMS and TDI outputs
            LowInputOutputPinsData.bPin2LowHighState = false;
            LowInputOutputPinsData.bPin3LowHighState = false;
            LowInputOutputPinsData.bPin4LowHighState = false;

            HighInputOutputPinsData.bPin1InputOutputState = false;
            HighInputOutputPinsData.bPin2InputOutputState = false;
            HighInputOutputPinsData.bPin3InputOutputState = false;
            HighInputOutputPinsData.bPin4InputOutputState = false;
            HighInputOutputPinsData.bPin5InputOutputState = false;
            HighInputOutputPinsData.bPin6InputOutputState = false;
            HighInputOutputPinsData.bPin7InputOutputState = false;
            HighInputOutputPinsData.bPin8InputOutputState = false;
            HighInputOutputPinsData.bPin1LowHighState = false;
            HighInputOutputPinsData.bPin2LowHighState = false;
            HighInputOutputPinsData.bPin3LowHighState = false;
            HighInputOutputPinsData.bPin4LowHighState = false;
            HighInputOutputPinsData.bPin5LowHighState = false;
            HighInputOutputPinsData.bPin6LowHighState = false;
            HighInputOutputPinsData.bPin7LowHighState = false;
            HighInputOutputPinsData.bPin8LowHighState = false;

            ftStatus = JTAG_GetHiSpeedDeviceNameLocIDChannel(0, byteHiSpeedDeviceName, MAX_NUM_DEVICE_NAME_CHARS, ref locationID, byteHiSpeedDeviceChannel, MAX_NUM_CHANNEL_CHARS, ref hiSpeedDeviceType);
            if (ftStatus != 0) error(Convert.ToInt32(ftStatus));
            hiSpeedChannel = Encoding.ASCII.GetString(byteHiSpeedDeviceChannel);// Trim strings to first occurrence of a null terminator character
            hiSpeedChannel = hiSpeedChannel.Substring(0, hiSpeedChannel.IndexOf("\0"));
            hiSpeedDeviceName = Encoding.ASCII.GetString(byteHiSpeedDeviceName);// Trim strings to first occurrence of a null terminator character
            hiSpeedDeviceName = hiSpeedDeviceName.Substring(0, hiSpeedDeviceName.IndexOf("\0"));// The ftHandle parameter is a pointer to a variable of type DWORD ie 32-bit unsigned integer

            ftStatus = JTAG_OpenHiSpeedDevice(hiSpeedDeviceName, locationID, hiSpeedChannel, ref ftHandle);
            if (ftStatus != 0) error(Convert.ToInt32(ftStatus));

            ftStatus = JTAG_InitDevice(ftHandle, 0);
            if (ftStatus != 0) error(Convert.ToInt32(ftStatus));

            ftStatus = JTAG_TurnOffDivideByFiveClockingHiSpeedDevice(ftHandle);
            if (ftStatus != 0) error(Convert.ToInt32(ftStatus));

            ftStatus = JTAG_SetClock(ftHandle, 6, ref clockFrequencyHz);
            if (ftStatus != 0) error(Convert.ToInt32(ftStatus));

            ftStatus = JTAG_SetHiSpeedDeviceGPIOs(ftHandle, true, ref LowInputOutputPinsData, true, ref HighInputOutputPinsData);
            if (ftStatus != 0) error(Convert.ToInt32(ftStatus));

        }

        private void button1_Click(object sender, EventArgs e)
        {

        }

        void error(int e)
        {
            switch (e)
            {
                case 0: Console.WriteLine("FTC_SUCCESS 0 // FTC_OK"); break;
                case 1: Console.WriteLine("FTC_INVALID_HANDLE"); break;
                case 2: Console.WriteLine("FTC_DEVICE_NOT_FOUND"); break;
                case 3: Console.WriteLine("FTC_DEVICE_NOT_OPENED"); break;
                case 4: Console.WriteLine("FTC_IO_ERROR"); break;
                case 5: Console.WriteLine("FTC_INSUFFICIENT_RESOURCES"); break;
                case 20: Console.WriteLine("FTC_FAILED_TO_COMPLETE_COMMAND"); break;
                case 21: Console.WriteLine("FTC_FAILED_TO_SYNCHRONIZE_DEVICE_MPSSE"); break;
                case 22: Console.WriteLine("FTC_INVALID_DEVICE_NAME_INDEX"); break;
                case 23: Console.WriteLine("FTC_NULL_DEVICE_NAME_BUFFER_POINTER"); break;
                case 24: Console.WriteLine("FTC_DEVICE_NAME_BUFFER_TOO_SMALL"); break;
                case 25: Console.WriteLine("FTC_INVALID_DEVICE_NAME"); break;
                case 26: Console.WriteLine("FTC_INVALID_LOCATION_ID"); break;
                case 27: Console.WriteLine("FTC_DEVICE_IN_USE"); break;
                case 28: Console.WriteLine("FTC_TOO_MANY_DEVICES"); break;
                case 29: Console.WriteLine("FTC_NULL_CHANNEL_BUFFER_POINTER"); break;
                case 30: Console.WriteLine("FTC_CHANNEL_BUFFER_TOO_SMALL"); break;
                case 31: Console.WriteLine("FTC_INVALID_CHANNEL"); break;
                case 32: Console.WriteLine("FTC_INVALID_TIMER_VALUE"); break;
                case 33: Console.WriteLine("FTC_INVALID_CLOCK_DIVISOR"); break;
                case 34: Console.WriteLine("FTC_NULL_INPUT_OUTPUT_BUFFER_POINTER"); break;
                case 35: Console.WriteLine("FTC_INVALID_NUMBER_BITS"); break;
                case 36: Console.WriteLine("FTC_NULL_WRITE_DATA_BUFFER_POINTER"); break;
                case 37: Console.WriteLine("FTC_INVALID_NUMBER_BYTES"); break;
                case 38: Console.WriteLine("FTC_NUMBER_BYTES_TOO_SMALL"); break;
                case 39: Console.WriteLine("FTC_INVALID_TAP_CONTROLLER_STATE"); break;
                case 40: Console.WriteLine("FTC_NULL_READ_DATA_BUFFER_POINTER"); break;
                case 41: Console.WriteLine("FTC_COMMAND_SEQUENCE_BUFFER_FULL"); break;
                case 42: Console.WriteLine("FTC_NULL_READ_CMDS_DATA_BUFFER_POINTER"); break;
                case 43: Console.WriteLine("FTC_NO_COMMAND_SEQUENCE"); break;
                case 44: Console.WriteLine("FTC_INVALID_NUMBER_CLOCK_PULSES"); break;
                case 45: Console.WriteLine("FTC_INVALID_NUMBER_SINGLE_CLOCK_PULSES"); break;
                case 46: Console.WriteLine("FTC_INVALID_NUMBER_TIMES_EIGHT_CLOCK_PULSES"); break;
                case 47: Console.WriteLine("FTC_NULL_CLOSE_FINAL_STATE_BUFFER_POINTER"); break;
                case 48: Console.WriteLine("FTC_NULL_DLL_VERSION_BUFFER_POINTER"); break;
                case 49: Console.WriteLine("FTC_DLL_VERSION_BUFFER_TOO_SMALL"); break;
                case 50: Console.WriteLine("FTC_NULL_LANGUAGE_CODE_BUFFER_POINTER"); break;
                case 51: Console.WriteLine("FTC_NULL_ERROR_MESSAGE_BUFFER_POINTER"); break;
                case 52: Console.WriteLine("FTC_ERROR_MESSAGE_BUFFER_TOO_SMALL"); break;
                case 53: Console.WriteLine("FTC_INVALID_LANGUAGE_CODE"); break;
                case 54: Console.WriteLine("FTC_INVALID_STATUS_CODE"); break;
                default: Console.WriteLine("FTC: Unknown error occured."); break;
            }
            System.Environment.Exit(-1);
        }
    }
}

【问题讨论】:

  • 你能显示 C++ JTAG_GetHiSpeedDeviceNameLocIDChannel 签名吗
  • 您好 Stecya,我在哪里可以找到签名?
  • 你有 c++ dll 提供的 .h 文件吗?
  • 你好 Stecya,是的,我找到了这些行:FTCJTAG_API FTC_STATUS WINAPI JTAG_GetHiSpeedDeviceNameLocIDChannel(DWORD dwDeviceNameIndex, LPSTR lpDeviceNameBuffer, DWORD dwBufferSize, LPDWORD lpdwLocationID, LPSTR lpChannel, DWORD dwChannelBufferSize, LPDWORD lpdwHiSpeedDeviceType);

标签: c# c++ dll dllimport


【解决方案1】:

自从我上次使用 PInvoke 以来已经有很长一段时间了,但我相信您的问题在于,正如错误消息所暗示的那样,您正在包装的 DLL 的调用约定。

快速查看 FTCJTAG.dll 的源代码,发现所有方法都标记为 WINAPI。这意味着他们使用 stdcall 调用约定。

您的 C# 代码通过告诉 PInvoke 使用 cdecl 调用约定来导入这些函数。

如果您不熟悉调用约定的概念,维基百科有一篇不错的文章here

总结:您的代码和您调用的 DLL 在如何相互发送信息以及谁负责清理方面没有达成一致。您需要使用 stdcall 约定从 dll 中导入函数。

【讨论】:

  • 您好 Bethor,感谢您提供 wiki 链接。我会试试 stdcall 的东西。
【解决方案2】:

问题是你正在编译什么......如果你正在编译到 x86 那么你的 32 位 dll 将在你编译到我认为是默认的“任何 cpu”时工作......你的代码将运行作为 64 位,您将无法使用 32 位 dll...将编译设置切换到 x86 或使用 64 位 dll。

【讨论】:

  • 你好 jsobo,我认为 express 不能编译 x86 以外的任何东西。
猜你喜欢
  • 2014-03-13
  • 1970-01-01
  • 2016-05-06
  • 1970-01-01
  • 2011-05-22
  • 1970-01-01
  • 2014-01-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多