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索引和sprite索引返回包含spriteset的sprite的位图。 此位图显示在PictureBox中,直到将其更改为其他图像。 我知道逻辑是有效的; 这不是问题所在。 我用来测试的.png是384 * 256。

所有参数都设置正确,所有引用的文件都在那里,一切似乎都是有序的。 最奇怪的是,有时它会起作用,有时则不起作用。 这让我相信它可能是System.Drawing本身内存泄漏,但我似乎无法追踪它。

编辑:更新了代码并添加了StackTrace。 尽管在不再使用Bitmaps时仍然存在相同的问题(请参阅下面的代码,例如如何处理Bitmap)。

 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() 

哇,这段代码泄漏的手柄就像地狱一样。 您需要处理所有实现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 } 

泄漏的句柄最终会导致内存问题,但在这种情况下它们不是问题(感谢那些指出它们的人,学到了新东西)。

问题在于,由于我将实际图像加载到内存中的方式,在我的大多数测试中,图像没有足够的时间来完全加载。 成功的那些是允许足够的时间来加载图像的那些。

我用一个简单的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,感谢清理;)在一些重构期间必须出现混乱。 猜猜我忘了它。

我发现这也试图寻找答案。 请注意,它还可以在以下情况下抛出exception:

stream包含一个大小超过65,535像素的PNG图像文件。

http://msdn.microsoft.com/en-us/library/z7ha67kw.aspx