关于VISTA下命名管道的问题(全文搜索DNS错误,只好提问了)(300分)

  • 主题发起人 主题发起人 ThenLong
  • 开始时间 开始时间
T

ThenLong

Unregistered / Unconfirmed
GUEST, unregistred user!
大家都知道:<br>VISTA下系统服务和桌面程序已经隔离了<br>所以许多通信机制失效了<br>经过查找资料和试验最终决定选用命名管道(namedPipe)来通信<br>但现在遇到新的问题难以解决<br>情况是这样的<br>BHO(BrowserHelpObject)插件需要与系统服务通信<br>系统服务建立的管道(例如//./pipe/mypipe),<br>BHO中只能读这个管道,而写不了。。。<br>说明:前提是不关闭UAC,也不关闭浏览器的安全模式<br><br>有高手能解答或给出别的通信机制吗?谢谢
 
可以通过 sendmessage,不同的是,接收端需要声明可以接受该用户级别的消息。<br>具体可以参考哦 innosetup 源码中的 debug 机制。<br>这是由于 vista 的 uac 等限制 inno 做的若干修改。
 
看看这段代码:<br><br>unit DebugClient;<br><br>{<br>&nbsp; Inno Setup<br>&nbsp; Copyright (C) 1997-2006 Jordan Russell<br>&nbsp; Portions by Martijn Laan<br>&nbsp; For conditions of distribution and use, see LICENSE.TXT.<br><br>&nbsp; Debug info stuff<br><br>&nbsp; $jrsoftware: issrc/Projects/DebugClient.pas,v 1.23 2006/10/01 02:42:36 jr Exp $<br>}<br><br>interface<br><br>uses<br>&nbsp; Windows, SysUtils, Messages, DebugStruct;<br><br>var<br>&nbsp; Debugging: Boolean;<br>&nbsp; DebugClientCompiledCodeText: String;<br>&nbsp; DebugClientCompiledCodeDebugInfo: String;<br><br>function DebugNotify(Kind: TDebugEntryKind; Index: Integer;<br>&nbsp; var ADebugContinueStepOver: Boolean): Boolean;<br>procedure DebugNotifyException(Exception: String; Kind: TDebugEntryKind; Index: Integer);<br>function DebugNotifyIntermediate(Kind: TDebugEntryKind; Index: Integer;<br>&nbsp; var ADebugContinueStepOver: Boolean): Boolean;<br>procedure DebugNotifyLogMessage(const Msg: String);<br>procedure DebugNotifyTempDir(const Dir: String);<br>procedure DebugNotifyUninstExe(UninstExe: String);<br>procedure EndDebug;<br>procedure SetDebugWnd(Wnd: HWND; WantCodeText: Boolean);<br><br>implementation<br><br>uses<br>&nbsp; Forms, Classes, CmnFunc2, Main;<br><br>type<br>&nbsp; TDummyClass = class<br>&nbsp; private<br>&nbsp; &nbsp; class procedure DebugClientWndProc(var Message: TMessage);<br>&nbsp; end;<br><br>var<br>&nbsp; DebugWnd: HWND;<br>&nbsp; DebugClientWnd: HWND;<br>&nbsp; DebugContinue: Boolean;<br>&nbsp; DebugContinueStepOver: Boolean;<br><br>procedure SetDebugWnd(Wnd: HWND; WantCodeText: Boolean);<br>const<br>&nbsp; MSGFLT_ADD = 1;<br>var<br>&nbsp; ChangeWindowMessageFilter: function(msg: UINT; dwFlag: DWORD): BOOL; stdcall;<br>&nbsp; I: Integer;<br>begin<br>&nbsp; { On Vista, unprivileged processes can't send messages to elevated processes<br>&nbsp; &nbsp; by default. Allow the debugger (which normally runs unprivileged) to send<br>&nbsp; &nbsp; messages to us. }<br>&nbsp; ChangeWindowMessageFilter := GetProcAddress(GetModuleHandle(user32),<br>&nbsp; &nbsp; 'ChangeWindowMessageFilter');<br>&nbsp; if Assigned(ChangeWindowMessageFilter) then<br>&nbsp; &nbsp; for I := Low(DebugClientMessages) to High(DebugClientMessages) do<br>&nbsp; &nbsp; &nbsp; ChangeWindowMessageFilter(DebugClientMessages, MSGFLT_ADD);<br><br>&nbsp; Debugging := True;<br>&nbsp; DebugWnd := Wnd;<br>&nbsp; DebugClientWnd := AllocateHWnd(TDummyClass.DebugClientWndProc);<br><br>&nbsp; SendMessage(DebugWnd, WM_Debugger_Hello, WPARAM(DebugClientWnd), LPARAM(WantCodeText));<br>end;<br><br>procedure EndDebug;<br>begin<br>&nbsp; Debugging := False;<br>&nbsp; if DebugWnd &lt;&gt; 0 then begin<br>&nbsp; &nbsp; SendMessage(DebugWnd, WM_Debugger_Goodbye, 0, 0);<br>&nbsp; &nbsp; DebugWnd := 0;<br>&nbsp; end;<br>&nbsp; if DebugClientWnd &lt;&gt; 0 then begin<br>&nbsp; &nbsp; DeallocateHWnd(DebugClientWnd);<br>&nbsp; &nbsp; DebugClientWnd := 0;<br>&nbsp; end;<br>end;<br><br>function InternalDebugNotify(DebuggerMsg: UINT; Kind: TDebugEntryKind;<br>&nbsp; Index: Integer; var ADebugContinueStepOver: Boolean): Boolean;<br>{ Returns True if the debugger paused. ADebugContinueStepOver is set to True<br>&nbsp; if the debugger paused and the user resumed via Step Over, False otherwise. }<br>var<br>&nbsp; SaveAppTitle: String;<br>&nbsp; WindowList: Pointer;<br>&nbsp; Msg: TMsg;<br>&nbsp; TopWindow: HWND;<br>begin<br>&nbsp; Result := False;<br>&nbsp; ADebugContinueStepOver := False;<br>&nbsp; if not Debugging then<br>&nbsp; &nbsp; Exit;<br><br>&nbsp; DebugContinue := False;<br><br>&nbsp; if SendMessage(DebugWnd, DebuggerMsg, Ord(Kind), Index) = 0 then begin<br>&nbsp; &nbsp; { Don't pause }<br>&nbsp; &nbsp; Exit;<br>&nbsp; end;<br>&nbsp; Result := True;<br><br>&nbsp; { Wait until we get clearance to continue }<br>&nbsp; SaveAppTitle := Application.Title;<br>&nbsp; WindowList := DisableTaskWindows(0);<br>&nbsp; try<br>&nbsp; &nbsp; Application.Title := '[Paused] ' + SaveAppTitle;<br>&nbsp; &nbsp; while not DebugContinue do begin<br>&nbsp; &nbsp; &nbsp; case Integer(GetMessage(Msg, 0, 0, 0)) of<br>&nbsp; &nbsp; &nbsp; &nbsp; -1: Break; { if GetMessage failed }<br>&nbsp; &nbsp; &nbsp; &nbsp; 0: begin<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{ Repost WM_QUIT messages }<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;PostQuitMessage(Msg.WParam);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Break;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;end;<br>&nbsp; &nbsp; &nbsp; end;<br>&nbsp; &nbsp; &nbsp; TranslateMessage(Msg);<br>&nbsp; &nbsp; &nbsp; DispatchMessage(Msg);<br>&nbsp; &nbsp; end;<br>&nbsp; &nbsp; ADebugContinueStepOver := DebugContinueStepOver;<br>&nbsp; finally<br>&nbsp; &nbsp; EnableTaskWindows(WindowList);<br>&nbsp; &nbsp; Application.Title := SaveAppTitle;<br>&nbsp; end;<br><br>&nbsp; { Bring us back to the foreground, unless we've been detached }<br>&nbsp; if Debugging then begin<br>&nbsp; &nbsp; TopWindow := GetThreadTopWindow;<br>&nbsp; &nbsp; if TopWindow &lt;&gt; 0 then begin<br>&nbsp; &nbsp; &nbsp; { First ask the debugger to call SetForegroundWindow() on our window. If<br>&nbsp; &nbsp; &nbsp; &nbsp; we don't do this then Windows (98/2000+) will prevent our window from<br>&nbsp; &nbsp; &nbsp; &nbsp; becoming activated if the debugger is currently in the foreground. }<br>&nbsp; &nbsp; &nbsp; SendMessage(DebugWnd, WM_Debugger_SetForegroundWindow, WPARAM(TopWindow), 0);<br>&nbsp; &nbsp; &nbsp; { Now call SetForegroundWindow() ourself. Why? When a remote thread<br>&nbsp; &nbsp; &nbsp; &nbsp; calls SetForegroundWindow(), the request is queued; the window doesn't<br>&nbsp; &nbsp; &nbsp; &nbsp; actually become active until the next time the window's thread checks<br>&nbsp; &nbsp; &nbsp; &nbsp; the message queue. This call causes the window to become active<br>&nbsp; &nbsp; &nbsp; &nbsp; immediately. }<br>&nbsp; &nbsp; &nbsp; SetForegroundWindow(TopWindow);<br>&nbsp; &nbsp; end;<br>&nbsp; end;<br>end;<br><br>function DebugNotify(Kind: TDebugEntryKind; Index: Integer;<br>&nbsp; var ADebugContinueStepOver: Boolean): Boolean;<br>begin<br>&nbsp; Result := InternalDebugNotify(WM_Debugger_Stepped, Kind, Index,<br>&nbsp; &nbsp; ADebugContinueStepOver);<br>end;<br><br>function DebugNotifyIntermediate(Kind: TDebugEntryKind; Index: Integer;<br>&nbsp; var ADebugContinueStepOver: Boolean): Boolean;<br>begin<br>&nbsp; Result := InternalDebugNotify(WM_Debugger_SteppedIntermediate, Kind, Index,<br>&nbsp; &nbsp; ADebugContinueStepOver);<br>end;<br><br>procedure DebugNotifyException(Exception: String; Kind: TDebugEntryKind; Index: Integer);<br>var<br>&nbsp; B: Boolean;<br>begin<br>&nbsp; SendCopyDataMessageStr(DebugWnd, DebugClientWnd, CD_Debugger_Exception,<br>&nbsp; &nbsp; Exception);<br>&nbsp; InternalDebugNotify(WM_Debugger_Exception, Kind, Index, B);<br>end;<br><br>procedure DebugNotifyTempDir(const Dir: String);<br>begin<br>&nbsp; SendCopyDataMessageStr(DebugWnd, DebugClientWnd, CD_Debugger_TempDir, Dir);<br>end;<br><br>procedure DebugNotifyUninstExe(UninstExe: String);<br>begin<br>&nbsp; SendCopyDataMessageStr(DebugWnd, DebugClientWnd, CD_Debugger_UninstExe, UninstExe);<br>end;<br><br>procedure DebugNotifyLogMessage(const Msg: String);<br>begin<br>&nbsp; SendCopyDataMessageStr(DebugWnd, DebugClientWnd, CD_Debugger_LogMessage, Msg);<br>end;<br><br>class procedure TDummyClass.DebugClientWndProc(var Message: TMessage);<br>var<br>&nbsp; VariableDebugEntry: TVariableDebugEntry;<br>&nbsp; EvaluateExp, EvaluateResult: String;<br>begin<br>&nbsp; try<br>&nbsp; &nbsp; case Message.Msg of<br>&nbsp; &nbsp; &nbsp; WM_DebugClient_Detach: begin<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Debugging := False;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DebugWnd := 0;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { If it's paused, force it to continue }<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DebugContinue := True;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DebugContinueStepOver := False;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { Make the GetMessage call in DebugNotify return immediately }<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PostMessage(0, 0, 0, 0);<br>&nbsp; &nbsp; &nbsp; &nbsp; end;<br>&nbsp; &nbsp; &nbsp; WM_DebugClient_Continue: begin<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DebugContinue := True;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DebugContinueStepOver := Message.wParam = 1;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { Make the GetMessage call in DebugNotify return immediately }<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PostMessage(0, 0, 0, 0);<br>&nbsp; &nbsp; &nbsp; &nbsp; end;<br>&nbsp; &nbsp; &nbsp; WM_DebugClient_SetForegroundWindow: begin<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; SetForegroundWindow(HWND(Message.WParam));<br>&nbsp; &nbsp; &nbsp; &nbsp; end;<br>&nbsp; &nbsp; &nbsp; WM_COPYDATA: begin<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case TWMCopyData(Message).CopyDataStruct.dwData of<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CD_DebugClient_EvaluateConstant: begin<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; try<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; SetString(EvaluateExp, PChar(TWMCopyData(Message).CopyDataStruct.lpData),<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; TWMCopyData(Message).CopyDataStruct.cbData);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; try<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ConstReadOnly := True;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; try<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; EvaluateResult := ExpandConst(EvaluateExp);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; finally<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ConstReadOnly := False;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Message.Result := 1;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; except<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; EvaluateResult := GetExceptMessage;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Message.Result := 2;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; SendCopyDataMessageStr(DebugWnd, DebugClientWnd, CD_Debugger_Reply,<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; EvaluateResult);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; except<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { don't propogate exceptions }<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CD_DebugClient_EvaluateVariableEntry: begin<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; try<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Move(TWMCopyData(Message).CopyDataStruct.lpData^, VariableDebugEntry, SizeOf(VariableDebugEntry));<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; try<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if CodeRunner = nil then<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; raise Exception.Create('Cannot evaluate variable because
代码:
 isn''t running yet');<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; EvaluateResult := CodeRunner.EvaluateUsedVariable(VariableDebugEntry.Param1,<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; VariableDebugEntry.Param2, VariableDebugEntry.Param3, VariableDebugEntry.Param4);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Message.Result := 1;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; except<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; EvaluateResult := GetExceptMessage;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Message.Result := 2;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; SendCopyDataMessageStr(DebugWnd, DebugClientWnd, CD_Debugger_Reply,<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; EvaluateResult);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; except<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { don't propogate exceptions }<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CD_DebugClient_CompiledCodeText: begin<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; try<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DebugClientCompiledCodeText := '';<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; SetString(DebugClientCompiledCodeText, PChar(TWMCopyData(Message).CopyDataStruct.lpData),<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; TWMCopyData(Message).CopyDataStruct.cbData);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Message.Result := 1;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; except<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { don't propogate exceptions }<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CD_DebugClient_CompiledCodeDebugInfo: begin<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; try<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DebugClientCompiledCodeDebugInfo := '';<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; SetString(DebugClientCompiledCodeDebugInfo, PChar(TWMCopyData(Message).CopyDataStruct.lpData),<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; TWMCopyData(Message).CopyDataStruct.cbData);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Message.Result := 1;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; except<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { don't propogate exceptions }<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; end;<br>&nbsp; &nbsp; &nbsp; &nbsp; end;<br>&nbsp; &nbsp; else<br>&nbsp; &nbsp; &nbsp; with Message do<br>&nbsp; &nbsp; &nbsp; &nbsp; Result := DefWindowProc(DebugClientWnd, Msg, WParam, LParam);<br>&nbsp; &nbsp; end;<br>&nbsp; except<br>&nbsp; &nbsp; Application.HandleException(nil);<br>&nbsp; end<br>end;<br><br>end.
 
谢了,我先研究下<br>如果消息机制能用起来,那么我的程序架构的修改将最小<br>ps:论坛限制300分,解决之后另开贴给200分
 
接受答案了.
 
后退
顶部