2010-05-10 2 views
4

라이브 앱에서이 문제가 발생합니다.Object.DisposedException from core .NET 코드

(불행히도 이것은 사후 디버깅입니다.이 스택 추적 만 있습니다. 개인적으로 본 적이 없으며, 재현 할 수도 없습니다.)

나는이 예외를 얻을 :

message=Cannot access a disposed object. 
Object name: 'Button'. 
exceptionMessage=Cannot access a disposed object. 
Object name: 'Button'. 
exceptionDetails=System.ObjectDisposedException: Cannot access a disposed object. 
Object name: 'Button'. 
    at System.Windows.Forms.Control.CreateHandle() 
    at System.Windows.Forms.Control.get_Handle() 
    at System.Windows.Forms.Control.PointToScreen(Point p) 
    at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent) 
    at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks) 
    at System.Windows.Forms.Control.WndProc(Message& m) 
    at System.Windows.Forms.ButtonBase.WndProc(Message& m) 
    at System.Windows.Forms.Button.WndProc(Message& m) 
    at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m) 
    at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m) 
    at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam) 
exceptionSource=System.Windows.Forms 
exceptionTargetSite=Void CreateHandle() 

양식이 배치 된 후 마우스 이벤트가 양식에 도착되는 것 같습니다.

참고이 스택 추적에는 내 코드가 없습니다.

내가하고있는 이상한 (?) 일은 ShowModal() (아래 "옆으로"참조)과 함께 사용할 때 상당히 적극적으로 Dispose()하는 경향이 있다는 것입니다.

EDIT : 그냥 명확히하기 위해 나는 CLI를 사용하고 있습니다. 실제로 CLI는 삭제 연산자를 사용합니다. 그러나 Dispose()를 호출하는 것과 같습니다.

그러나 ShowModal()이 반환 된 후 (안전해야합니까?), 양식을 완료했을 때만 수행합니다.

이벤트가 이벤트 대기열에 대기 중일 수 있음을 읽었지만 이것이 문제가 될 수는 없다고 생각합니다. 프레임 워크가 오래된 메시지에 관대해야한다는 것을 확실하게 의미합니까? 스트레스 메시지가 다시 기록 될 수 있다고 생각할 수 있으며 창은 언제든지 사라질 수 있습니다.

아이디어가 있으십니까?

재생산 방법을 제안 할 수도 있다면 유용 할 것입니다.

을 제외하고

:

TBH 내가 매우 엄격하게 필요 Form.ShowDialog 후 폐기()()를 호출 여부를 이해 적이 - ShowDialog를위한 MSDN의 워드 프로세서()에있는 내 조금 모호하다.

+0

Invoke 메서드를 사용하여 의도하지 않게 일부 방법으로 Button에 액세스하려고하는 UI 스레드에서 호출하는 백그라운드 처리를 수행하고있을 가능성이 있습니까? – casperOne

+2

그럴 수도 있습니다. 불행히도, 나는 이것이 어떤 형태로 발생하는지 확실하지 않습니다. 나는 이것을하는 어떤 형태가있다. 그러나 스택 추적은 마우스 이벤트가 아니라 대기중인 Invoke임을 보여줍니까? – John

+0

처분 코드를 보여줄 수 있습니까? 객체가 잘못 배치되거나 배치되면 잘못 참조 될 때 이런 일이 발생하는 것을 보았습니다. –

답변

1

양식을 삭제 한 후에 양식을 표시하면 이런 일이 발생합니다. (시도해 보았습니다.)

ShowDialog을 호출 한 후에는 양식을 처분해야합니다. 단, 해당 인스턴스에 대해 다른 작업을 수행 할 계획이없는 경우에만 양식을 폐기해야합니다.

+0

아니, 그게 아니야. 내가 말했듯이, 나는 형식을 다 마쳤을 때만 Dispose()를 호출한다. – John

+0

정말 이니? 당신이 그렇게한다면 이것은 일어날 것입니다. 양식을 폐기 한 후 컨트롤에 'Invoke'또는 'Text'를 호출합니까? – SLaks

+0

동일한 스레드에서 사용하지 않을 것이라고 확신합니다. Invoke가 가능합니다 (main의 casperOne 주석 참조). 그러나 Invoke 인 경우 스택 추적에서 Mouse 이벤트로 표시되는 이유는 무엇입니까? – John

0

using 문 내에서 양식 인스턴스를 사용하지 않는 이유는 무엇입니까? 이렇게하면 처분을 호출 할 필요가 없으며 올바른 시간에 처리되었는지 확인할 수 있습니다.

이것은 매우 이상한 호출 스택입니다

using(FormX frm = new FormX()) 
{ 
    DialogResult res = frm.ShowDialog(); 
    // Do your other stuff after 
} 
+0

사실 저는 C++/CLI를 사용하고 있으므로 "사용"하는 키워드가 없습니다. 그러나, 나는 처분 후 확실히 양식을 사용하지 않습니다. 그래도 좋은 지적. – John

+0

오케이, C# 태그로 오해했습니다 .-)) – Shimrod

+0

죄송합니다! 미안 내 실수! – John

1

(테스트하지, 지금 컴파일러에 액세스 할 수 없습니다). 버튼이 삭제되면 PointToScreen() 메서드가 핸들을 다시 생성합니다. 그러나 그것이 폐기 되었다면 마우스 업 메시지를 얻을 수 없어야합니다. 스레딩 만이 실제로 이것을 설명 할 수 있습니다.

또한 마우스 업 메시지가 도착할 때까지 아직 처리 된 것이 없어야합니다. 아마도 이것은 대화 상자를 닫는 버튼 일 것입니다.MouseDown 이벤트가 아니라 Click 이벤트를 사용해야합니다. 또한 Close()를 호출하지 말고 DialogResult 속성을 지정하여 대화 상자를 닫아야합니다. C++/CLI에서는 형식과 변수에 대한 별도의 심볼 테이블을 별도로 보관하지 않으므로 어색함.

사용자에게 해당 컴퓨터에서 실행중인 "향상된 기능"의 종류를 묻습니다.

+0

이상하게 생각합니다. "스레딩 만 실제로 이것을 설명 할 수 있습니다."라고 말하면 조금 더 자세히 설명 할 수 있습니까? 또한 Close()를 호출해서는 안되는 이유는 무엇입니까? – John

+0

호출 스택의 맨 아래에는 버튼에 핸들이 있지만 맨 위에는 핸들이 없습니다. 다른 시나리오가 생기면 DialogResult 속성을 설정하여 대화 상자를 닫아야하며 Close는 호출하지 말아야합니다. –

+0

Close()를 호출하면 안되는 이유는 아직 확실하지 않습니다. MSDN은 괜찮다고 제안하는 것 같습니다. 다음은 Form :: Close()에서 말하는 내용입니다. "양식이 닫히지 않을 때의 두 조건은 (1) ...이고 (2) ShowDialog를 사용하여 양식을 표시 한 경우입니다. 가비지 수집을 위해 양식의 모든 컨트롤을 표시하려면 Dispose를 수동으로 호출해야합니다. " 내게 그것은 Close()를 호출하는 것이 유해하지 않다는 것을 의미합니다. 이 경우 Close()가 나쁜 이유를 설명하는 곳으로 나를 안내 할 수 있습니까? 감사! – John

1

내 응용 프로그램에서 비슷한 홀수 스택 추적을 진단하는 동안 질문을 찾았습니다. 여기에 내가 함께 일해야했다 스택 추적입니다 :

System.ObjectDisposedException: Cannot access a disposed object. 
Object name: 'TextBox'. 
    at System.Windows.Forms.Control.CreateHandle() 
    at System.Windows.Forms.TextBoxBase.CreateHandle() 
    at System.Windows.Forms.Control.get_Handle() 
    at System.Windows.Forms.Control.set_CaptureInternal(Boolean value) 
    at System.Windows.Forms.Control.WmMouseDown(Message& m, MouseButtons button, Int32 clicks) 
    at System.Windows.Forms.Control.WndProc(Message& m) 
    at System.Windows.Forms.TextBoxBase.WndProc(Message& m) 
    at System.Windows.Forms.TextBox.WndProc(Message& m) 
    at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m) 
    at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m) 
    at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam) 

그것은 당신과 같은 아니에요,하지만 동일한 주요 특성 중 일부를 가지고 :

핸들이 시작 부분에 존재
  • 있지만 스택 트레이스의 끝에서
  • 내 코드가 스택 추적에 표시되지 않습니다.

나는 내 문제가 너와 같다고 생각하지 않지만, 나는 네가 어떤 통찰력을 줄 수 있기를 희망하면서 내가 발견 한 것을 나눌 것이라고 생각했다. 몇 가지 실험을 마친 후 문제를 재현 할 수있었습니다. LostFocus 이벤트를 다른 컨트롤에 연결했는데 특정 상황에서 LostFocus 이벤트 핸들러는 더 이상 관련이없는 특정 컨트롤을 삭제합니다.

그러나 사용자가 삭제할 컨트롤 중 하나를 클릭하여 LostFocus 이벤트가 트리거 된 경우 위의 스택 추적을 얻습니다. 필자의 경우 Control.WndProc은 (다른 컨트롤의) LostFocus 이벤트 처리기를 결국 호출하는 Control.WmKillFocus를 호출하고, 클릭 한 컨트롤을 처리 한 다음 Control.WmMouseDown이 호출됩니다.

WmMouseUp 이전에 어떤 상황이 발생했는지 비슷한 상황이 발생할 수 있습니까?

WmMouseUp이 문제를 추적하는 데 도움이 될 수있는 .NET Reflector를 사용하여 어떤 이벤트가 호출되는지 확인할 수 있습니다.

0

비 모달 폼의 경우 버튼 클릭시 Close() 메서드를 호출 할 때 동일한 문제가 발생했습니다. winforms 어셈블리 디버깅 단추의 FlatStyle 속성으로 나를 이끌었다. button.FlatSyle = FlatStyle.System 있었습니까?

양식 닫기 및 처분 중에 어떤 이유로 단추가 WM_KILLFOCUS (OnLostFocus)을 수신하지 않습니다. button.FlatSyle = FlatStyle.System 인 경우 해당 콜 스택과 함께 ObjectDisposedException이 될 수 있습니다.

1

필자가 작성한 Button의 하위 클래스에서이 문제가 발생했습니다. 나에게있어 솔루션은 base.OnMouseDown에 대한 호출과 메소드의 나머지 코드 사이에서 버튼의 IsDisposed 속성을 확인하는 것으로 판명되었다. 이 같은

뭔가 : 양식이 배치 된 후 마우스 이벤트가 양식에 도착처럼

protected override void OnMouseUp(System.Windows.Forms.MouseEventArgs mevent) 
{ 
    base.OnMouseUp(mevent); 

    if (this.IsDisposed) { 
     return; 
    } 
} 
0

것 같습니다.

예! 예외는 명확하게 '배치 된 객체, 객체 이름에 액세스 할 수 없습니다 : 버튼'을 의미합니다. 이는 이미 배치 된 버튼이 다시 처분의 압력을 받고 있음을 의미하므로 예외입니다.따라서 아래 라인을 보시면 여러분이 제공 한 스택 트레이스를 기반으로 단추의 OnMouseUp 이벤트 중에 이미 배치 된 버튼을 두 번째로 반복해서 처리하는 것이 분명합니다.

at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent) 

그래서 난 당신이 아래 버튼의 붙일 수있을뿐입니다 특성에 따라 반복적 인 처분을 방지 상기 onMouseUp에 이벤트를 System.Windows.Forms.Button 컨트롤을 상속 사용자 정의 버튼을 생성하고 무시하는 것이 좋습니다.

public class FlatSylteSystemButton : System.Windows.Forms.Button 
{ 
    public FlatStyleSystemButton() 
    { 
      this.FlatStyle =FlatStyle.System; 
    } 

    protected override void OnMouseUp(MouseEventArgs mevent) 
    { 
     if(!this.IsDisposed) 
     { 
      base.OnMouseUp(mevent); 
     } 
    } 
} 

희망이 있습니다.