2012-12-31 168 views
4

經過一些更多的測試後,我發現這個問題可能是由於圖像以某種方式未被及時加載而被克隆到位圖並顯示。這是可能的還是不可以的?System.Drawing - 參數無效

注意:是的,在標題中有這個錯誤的其他問題,但從一些研究來看,它似乎是一個模糊的錯誤,有很多可能的原因。我沒有發現任何與我的情況相同的問題。

我收到以下錯誤消息。

System.ArgumentException was unhandled 
HResult=-2147024809 
Message=Parameter is not valid. 
Source=System.Drawing 

它來自此代碼。看似隨意(即,有時工作,有時它不會次數越多它的連續運行,無需重新啓動VS和重建項目,越有可能是失敗。):

private Bitmap GetSprite(bool anim, int tsIndex, int tileIdx) { 
    System.Drawing.Rectangle cloneRect; 
    string prefix = (anim) ? "A" : "S"; 
    using (Bitmap b = new Bitmap(prefix + tsIndex.ToString() + ".png")) { 
     if (anim) { 
      cloneRect = new System.Drawing.Rectangle(BaseObjects.A_AnimSpriteSets[tsIndex].StaticRecs[tileIdx].X, BaseObjects.A_AnimSpriteSets[tsIndex].StaticRecs[tileIdx].Y, BaseObjects.A_AnimSpriteSets[tsIndex].RecWidth, BaseObjects.A_AnimSpriteSets[tsIndex].RecHeight); 
     } else { 
      cloneRect = new System.Drawing.Rectangle(BaseObjects.A_StaticSpriteSets[tsIndex].StaticRecs[tileIdx].X, BaseObjects.A_StaticSpriteSets[tsIndex].StaticRecs[tileIdx].Y, BaseObjects.A_StaticSpriteSets[tsIndex].RecWidth, BaseObjects.A_StaticSpriteSets[tsIndex].RecHeight); 
     } 
     return b.Clone(cloneRect, b.PixelFormat); 
    } 
} 

具體來說,第四行:

using (Bitmap b = new Bitmap(prefix + tsIndex.ToString() + ".png")) 

代碼的簡化目的是返回包含基於一個spriteset索引和子畫面索引spriteset精靈的位圖。該位圖顯示在PictureBox中,直到它被更改爲不同的圖像。我知道邏輯起作用的事實;這不是問題。我用來測試的.png是384 * 256。

所有參數設置正確,所有引用的文件都在那裏,一切似乎都是按順序的。最奇怪的是,有時它起作用,有時它不起作用。這使我相信它可能是System.Drawing本身的內存泄漏,但我似乎無法追蹤它。

編輯:更新的代碼並添加堆棧跟蹤。仍具有儘管設置所述位圖相同的問題,當它們不再使用(參見下面的代碼例如位圖是怎樣佈置)。

if (Sprite.Image != null) { Sprite.Image.Dispose(); } 
    Sprite.Image = GetSprite(true, tsIdx, tileIdx); 

堆棧跟蹤:

System.ArgumentException was unhandled 
    HResult=-2147024809 
    Message=Parameter is not valid. 
    Source=System.Drawing 
    StackTrace: 
     at System.Drawing.Bitmap..ctor(String filename) 
     at CreationTool.Main.GetSprite(Boolean anim, Int32 tsIndex, Int32 tileIdx) in F:\~\~\CreationTool\Main.cs:line 420 
     at CreationTool.Main.Input_EnemySprite_SelectedIndexChanged(Object sender, EventArgs e) in F:\~\~\CreationTool\Main.cs:line 107 
     at System.Windows.Forms.ComboBox.OnSelectedIndexChanged(EventArgs e) 
     at System.Windows.Forms.ComboBox.set_SelectedIndex(Int32 value) 
     at CreationTool.States.State_Enemy.populateForm() in F:\~\~\CreationTool\States\State_Enemy.cs:line 28 
     at CreationTool.States.State_Enemy.Load(String name) in F:\~\~\CreationTool\States\State_Enemy.cs:line 22 
     at CreationTool.Main.btnLoad_Click(Object sender, EventArgs e) in F:\~\~\CreationTool\Main.cs:line 174 
     at System.Windows.Forms.Control.OnClick(EventArgs e) 
     at System.Windows.Forms.Button.OnClick(EventArgs e) 
     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.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam) 
     at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg) 
     at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData) 
     at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context) 
     at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context) 
     at System.Windows.Forms.Application.Run(Form mainForm) 
     at CreationTool.Program.Main() in F:\~\~\CreationTool\Program.cs:line 15 
     at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args) 
     at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) 
     at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() 
     at System.Threading.ThreadHelper.ThreadStart_Context(Object state) 
     at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 
     at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 
     at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) 
     at System.Threading.ThreadHelper.ThreadStart() 
+2

你需要調用'Dispose'在'位圖B'你克隆後。位圖使用非託管資源,這可能會導致內存壓力問題。我會用一個使用語句來包裝它。 – pstrjds

+0

謝謝,這似乎已修復它。改變成答案? – Djentleman

+0

您應該在您的應用程序的'Main'中添加try/catch,並將異常轉儲到控制檯或將其記錄下來,以便您可以查看堆棧跟蹤並確切知道其來源。 – pstrjds

回答

3

泄漏手柄會最終導致記憶問題,但他們不是在這種情況下,問題(感謝那些誰指出出來,無論如何,學到新的東西)。

問題是,由於我將實際圖像加載到內存中的方式,圖像在我的大多數測試中沒有足夠的時間來完全加載。成功的那些是允許圖像加載足夠時間的那些。

我用一個簡單的try/catch來解決這個問題。

private Bitmap GetSprite(bool anim, int tsIndex, int tileIdx) { 
    string prefix; 
    System.Drawing.Rectangle cloneRect; 
    SpriteSet set; 
    if (anim) { 
     prefix = "A"; 
     set = BaseObjects.A_AnimSpriteSets[tsIndex]; 
    } else { 
     prefix = "S"; 
     set = BaseObjects.A_StaticSpriteSets[tsIndex]; 
    } 
    cloneRect = new System.Drawing.Rectangle(set.StaticRecs[tileIdx].X, set.StaticRecs[tileIdx].Y, set.RecWidth, set.RecHeight); 
    try { 
     using (Bitmap b = new Bitmap(prefix + tsIndex.ToString() + ".png")) { 
      return b.Clone(cloneRect, b.PixelFormat); 
     } 
    } catch (Exception ex) { 
     MessageBox.Show("Error: " + ex.Message + "\n\nCause: " + "SpriteSet not yet loaded."); 
     return null; 
    } 
} 

這就是我需要的這個特定的程序。

另外,pstrjds,感謝您的清理;)在一些重構過程中,這種混亂一定會出現。猜猜我忘了它。

6

哇,這個代碼泄漏手柄像地獄。您需要處置實現IDisposable所有類型,這是在System.Drawing中裝配(GDI +)相當多的類型:

private Bitmap GetSprite(bool anim, int tsIndex, int tileIdx) 
{ 
    Rectangle cloneRect; 
    string prefix = (anim) ? "A" : "S"; 
    using (Bitmap b = new Bitmap(prefix + tsIndex.ToString() + ".png")) 
    { 
     if (anim) 
     { 
      cloneRect = new Rectangle(BaseObjects.A_AnimSpriteSets[tsIndex].StaticRecs[tileIdx].X, BaseObjects.A_AnimSpriteSets[tsIndex].StaticRecs[tileIdx].Y, BaseObjects.A_AnimSpriteSets[tsIndex].RecWidth, BaseObjects.A_AnimSpriteSets[tsIndex].RecHeight); 
     } 
     else 
     { 
      cloneRect = new Rectangle(BaseObjects.A_StaticSpriteSets[tsIndex].StaticRecs[tileIdx].X, BaseObjects.A_StaticSpriteSets[tsIndex].StaticRecs[tileIdx].Y, BaseObjects.A_StaticSpriteSets[tsIndex].RecWidth, BaseObjects.A_StaticSpriteSets[tsIndex].RecHeight); 
     } 

     return b.Clone(cloneRect, b.PixelFormat); 
    } 
} 

還要確保你也通過包裝設此函數返回的位圖在using聲明來電:

using (Bitmap b = GetSprite(true, 0, 5)) 
{ 
    // do whatever you needed to do with the bitmap here 
} 
+0

我正在嘗試清理代碼以及添加使用。哦,那麼,將upvote你的:) – pstrjds

+0

修改代碼建議所有調用GetSprite()並仍然在完全相同的地方得到完全相同的錯誤。而現在,我只得到紅色的exes來代替圖像。 – Djentleman

+0

您尚未解釋如何使用這些圖像。在我提供的例子中,你不能在using語句之外使用它們。我猜你試圖使用外部結果,這就是爲什麼你會得到Red xses。 –