Ensure that underflowing negative float is represented as a positive
0, just as native oleaut32.

diff --git a/dlls/oleaut32/tests/vartype.c b/dlls/oleaut32/tests/vartype.c
index 7cbb982..b42627c 100644
--- a/dlls/oleaut32/tests/vartype.c
+++ b/dlls/oleaut32/tests/vartype.c
@@ -4615,7 +4615,7 @@
   ok(hres == S_OK, "got hres 0x%08lx\n", hres);
   if (bstr)
   {
-    todo_wine ok(memcmp(bstr, szZero, sizeof(szZero)) == 0, "negative zero (got %s)\n", wtoascii(bstr));
+    ok(memcmp(bstr, szZero, sizeof(szZero)) == 0, "negative zero (got %s)\n", wtoascii(bstr));
   }
 }
 
diff --git a/dlls/oleaut32/vartype.c b/dlls/oleaut32/vartype.c
index a82b692..0e1b7e8 100644
--- a/dlls/oleaut32/vartype.c
+++ b/dlls/oleaut32/vartype.c
@@ -5258,6 +5258,19 @@
     return E_INVALIDARG;
 
   sprintfW( buff, lpszFormat, dblIn );
+
+  /* Negative zeroes are disallowed (some applications depend on this).
+     If buff starts with a minus, and then nothing follows but zeroes
+     and/or a period, it is a negative zero and is replaced with a
+     canonical zero. This duplicates native oleaut32 behavior.
+   */
+  if (buff[0] == '-')
+  {
+    const WCHAR szAccept[] = {'0', '.', '\0'};
+    if (strlenW(buff + 1) == strspnW(buff + 1, szAccept))
+    { buff[0] = '0'; buff[1] = '\0'; }
+  }
+
   TRACE("created string %s\n", debugstr_w(buff));
   if (dwFlags & LOCALE_USE_NLS)
   {