In einer Visual Studio 2008 Anwendung habe ich die Shapes aus dem VisualBasic PowerPack verwendet, das im Lieferumfang von Visual Studio 2008 SP1 bereits enthalten ist. Nun hat sich ein Anwender aber mit folgender Fehlermeldung gemeldet, obwohl die korrekte Version des PowerPacks im Programm-Verzeichnis mit ausgeliefert wurde:
System.TypeLoadException:
Could not load type 'Microsoft.VisualBasic.PowerPacks.ShapeContainer'
from assembly 'Microsoft.VisualBasic.PowerPacks.Vs,
Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.
Nach einiger Suche war die Ursache klar. Visual Studio 2008 (ohne SP1) kennt diese DLL ebenfalls, nur leider noch ohne Shapes. Unglücklicherweise haben beide DLLs (mit und ohne SP1) die Version 9.0.0.0. Somit wird, sofern im GAC die DLL gefunden wird, automatisch immer die DLL aus dem GAC geladen. Die einzige Lösung ist darum, die DLL im GAC zu löschen oder zu aktualisieren:
Das geht, Admin-Rechte vorrausgesetzt, erstaunlich einfach per Drag & Drop.
Beim Prüfen von Quelltext sind mir wiederholt Ungenauigkeiten mit double Zahlen aufgefallen, die schon in der 8. Stelle auftraten. Nachdem ich Ausgeschlossen hatte, dass irgendwo Single-Konvertierungen stattfinden, habe ich das Problem genauer unter die Lupe genommen. Konkret ist mir aufgefallen, dass die double Rechnung 4.0 * 25.4 eigentlich 101.6 ergeben müsste, in der Zielvariable stand aber 101.59999847412109. Extern nachstellbar war das Problem anfangs nicht.
Reproduzieren ließ sich das Verhalten erst mit folgender Funktion:
private void TestDouble()
{
var pres = new Microsoft.DirectX.Direct3D.PresentParameters
{
Windowed = true,
SwapEffect = Microsoft.DirectX.Direct3D.SwapEffect.Discard,
AutoDepthStencilFormat = Microsoft.DirectX.Direct3D.DepthFormat.D16
};
new Microsoft.DirectX.Direct3D.Device(
0, Microsoft.DirectX.Direct3D.DeviceType.Hardware, this,
Microsoft.DirectX.Direct3D.CreateFlags.SoftwareVertexProcessing, pres);
double value = 4;
double value2 = value * 25.4;
Debug.Assert(101.6 == value2);
} |
private void TestDouble()
{
var pres = new Microsoft.DirectX.Direct3D.PresentParameters
{
Windowed = true,
SwapEffect = Microsoft.DirectX.Direct3D.SwapEffect.Discard,
AutoDepthStencilFormat = Microsoft.DirectX.Direct3D.DepthFormat.D16
};
new Microsoft.DirectX.Direct3D.Device(
0, Microsoft.DirectX.Direct3D.DeviceType.Hardware, this,
Microsoft.DirectX.Direct3D.CreateFlags.SoftwareVertexProcessing, pres);
double value = 4;
double value2 = value * 25.4;
Debug.Assert(101.6 == value2);
}
Das Erzeugen der 3D-Welt mittel Managed DirectX setzt standartmäßig die Genauigkeit von Double-Zahlen auf einfache Genauigkeit (entspricht Single). Nachdem diese Ursache gefunden war, fand ich hier:
http://blogs.msdn.com/b/tmiller/archive/2004/06/01/145596.aspx
schnell eine Problemlösung. Wenn man mit leichten Geschwindigkeitseinschränkungen leben kann, ist nur eine kleine Änderung beim Erzeugen vom Device notwendig:
new Microsoft.DirectX.Direct3D.Device(
0, Microsoft.DirectX.Direct3D.DeviceType.Hardware, this,
Microsoft.DirectX.Direct3D.CreateFlags.SoftwareVertexProcessing |
Microsoft.DirectX.Direct3D.CreateFlags.FpuPreserve, pres); |
new Microsoft.DirectX.Direct3D.Device(
0, Microsoft.DirectX.Direct3D.DeviceType.Hardware, this,
Microsoft.DirectX.Direct3D.CreateFlags.SoftwareVertexProcessing |
Microsoft.DirectX.Direct3D.CreateFlags.FpuPreserve, pres);
Der zusätzliche Parameter Microsoft.DirectX.Direct3D.CreateFlags.FpuPreserve sorgt dafür, dass DirectX die Genauigkeit der Double-Zahlen so lässt, wie das Standardmäßig der Fall ist.