2014-12-25 2 views
3

WindowsAPICodePack ShellPropertyWriter 및 BackgroundWorker를 사용하여 파일 속성을 업데이트하는 정적 메서드를 호출하는 스레드가 있습니다. 이 스레드는 1000 개 이상의 파일 폴더에있는 각 파일에 대해 아래의 메소드를 호출하고 700 번째 업데이트 이후에 ShellPropertyWriter.close()에 정지합니다.닫기 파일에 C# 스레드가 있습니다.

파일 자체와 관련이 없으며 이전에 성공적으로 업데이트 된 다른 파일을 사용해 보았습니다.

public static bool ShellPropertyUpdate(VideoEntry mediaEntry) 
    { 
     try 
     { 
      ShellFile mediafile = ShellFile.FromFilePath(mediaEntry.FilePath); 
      ShellPropertyWriter pw = mediafile.Properties.GetPropertyWriter(); 
      pw.WriteProperty(SystemProperties.System.Music.Artist, mediaEntry.Actor); 
      pw.WriteProperty(SystemProperties.System.Music.Genre, mediaEntry.Genre); 
      pw.WriteProperty(SystemProperties.System.Rating, mediaEntry.Rating); 
      pw.Close(); 
     } 
     catch (Exception ex) 
     { 
      return false; 
     } 
     return true; 
    } 

    private void mnuWriteMetadataToFiles_Click(object sender, EventArgs ev) 
    { 
     this.WorkerThread = new BackgroundWorker(); 
     this.WorkerThread.DoWork += new DoWorkEventHandler(WorkerThread_WriteMetadataToFiles); 
     this.WorkerThread.ProgressChanged += new ProgressChangedEventHandler(WorkerThread_ProgressChanged); 
     this.WorkerThread.RunWorkerCompleted += (s, e) => WorkerThread_Completed("Writing metadata to files", s, e); 
     this.WorkerThread.WorkerReportsProgress = true; 
     this.WorkerThread.WorkerSupportsCancellation = true; 
     this.WorkerThread.RunWorkerAsync(WMPlayer); 
    } 

    private void WorkerThread_WriteMetadataToFiles(object sender, DoWorkEventArgs e) 
    { 
     int counter = 0; 
     BackgroundWorker worker = (BackgroundWorker)sender; 
     MediaPlayer wmp = (MediaPlayer)e.Argument; 

     // ... Loop with the foreach video in the library and write it to file. 
     foreach (VideoEntry entry in wmp.Videos) 
     { 
      if (worker.CancellationPending) 
      { 
       e.Cancel = true; 
      } 
      else 
      { 
       worker.ReportProgress(counter, "Updating '" + entry.Filename + "'" + Environment.NewLine + "Processing file"); 
       if (VideoToFile.ShellPropertyUpdate(entry)) 
       { 
        result &= true; 
       } 
       counter++; 
      } 
     } 
     e.Result = result; 
    } 
+0

좋은 질문입니다. 매번 재현 할 수 있습니까? Debug vs Release 모드의 차이점은 무엇입니까? 'foreach (디렉토리에있는 파일)'라고 작은 코드를 넣을 수 있습니까? 작은 스레드 (Thread.Sleep (50))를 넣을 수 있습니까? 스레드가 멈추는 파일 크기와의 상관 관계 –

+0

이 정보가 중단 문제를 해결하기에 충분할 지 모르겠습니다. API 팩에 버그가있을 가능성이 있습니다.하지만 버그가있을 수도 있습니다. 다른 곳에서는 코드를 보지 못했습니다. 우리가 공유하지 못하는 코드는 꽤 직설적입니다. 나머지 코드, 귀하의 API 또는 API 팩을 보지 않고서는 말하기 어렵습니다. IMHO, You 'd 'd –

+0

매번 다시 재생할 수 있으며 700 파일 업데이트 전후 또는 조금 지연 될 수 있습니다. 디버그 x86 (Release 시도 할 것입니다.) 호출 코드는 각각 반복됩니다. 목록에 . 나는 수면과 주 스레드를 시도하고 알려 드리겠습니다. 내가 본 것에서 파일로, 나는 목록에서 다른 파일을 교환하고 동일한 최종 결과를 얻었다. 나는 TagLib을 사용하여 ID3v2 태그를 업데이트하고 거기에 파일을 닫을 때 같은 결과가 발생하지만 약 300+ 업데이트에서 발생하므로 버그가 내 코드 어딘가에 있다고 확신합니다. 위의 호출 코드를 추가하겠습니다. – zcodemonkey

답변

3

전에이 어셈블리를 들어 본 적이 없지만 핸들 소진과 같은 냄새가납니다. 대신이 시도 :

using (ShellFile mediafile = ShellFile.FromFilePath(mediaEntry.FilePath)) 
{ 
    ShellPropertyWriter pw = mediafile.Properties.GetPropertyWriter(); 
    pw.WriteProperty(SystemProperties.System.Music.Artist, mediaEntry.Actor); 
    pw.WriteProperty(SystemProperties.System.Music.Genre, mediaEntry.Genre); 
    pw.WriteProperty(SystemProperties.System.Rating, mediaEntry.Rating); 
    pw.Close(); 
} 

여기에 모든 파일 핸들이 가비지 컬렉터의 판단에 대신 즉시 닫힙니다. ShellFile이 작동하려면 IDisposable을 구현해야합니다. 그렇지 않으면이 코드가 컴파일되지 않습니다. 나는 ShellFile이 그것을 구현한다는 것을 확신한다.

+0

ShellFile은 IDisposable을 구현합니다. 방금 시도했지만 불행히도 작동하지 않았습니다. 여전히 동일한 동작입니다. 어쨌든 메서드를 구현하는 더 깨끗한 방법입니다. 덕분에 – zcodemonkey

+0

분명히 파일 자체와 관련이 있습니다. 몇 가지 문제 파일을 꺼 냈고 스레드는 다음 문제 파일까지 처리를 계속했습니다. 파일에 어떤 문제가 있는지 전혀 알지 못하지만 문제 파일을 업데이트하려고합니다. 스레드를 중지/종료 할 수있는 방법이 있습니까? 쓰레드가 매달려 돌아 오지 않기 때문에 DoWorkEventArgs.cancel()을 사용할 수 없습니다. – zcodemonkey

+0

@stackmonkey nice, 당신은 대답을하고 그것을 받아 들여야합니다. – Dialecticus

0

분명히 파일 자체와 관련이 있습니다. 몇 가지 문제 파일을 꺼 냈고 스레드는 다음 문제 파일까지 처리를 계속했습니다. 파일에 어떤 문제가 있는지 전혀 알지 못하지만 문제 파일을 업데이트하려고합니다. 스레드를 중지/종료 할 수있는 방법이 있습니까? 쓰레드가 매달려 돌아 오지 않기 때문에 DoWorkEventArgs.cancel()을 사용할 수 없습니다.

관련 문제