MLANG: Add stubbed support for IEnumScript interface

Dmitry Timoshkov dmitry at baikal.ru
Wed Aug 11 08:14:37 CDT 2004


Hello,

Changelog:
    Dmitry Timoshkov <dmitry at codeweavers.com>
    - add stubbed support for IEnumScript interface
    - ConvertINetMultiByteToUnicode/ConvertINetUnicodeToMultiByte should
      return required target length if the target buffer is NULL
    - add the tests for all the above
    - fix IMultiLanguage2 vtable (it was missing ConvertStringFromUnicodeEx)

diff -u cvs/hq/wine/dlls/mlang/mlang.c wine/dlls/mlang/mlang.c
--- cvs/hq/wine/dlls/mlang/mlang.c	2004-08-07 14:02:25.000000000 +0900
+++ wine/dlls/mlang/mlang.c	2004-08-08 16:12:49.000000000 +0900
@@ -412,14 +412,18 @@ HRESULT WINAPI ConvertINetMultiByteToUni
             *pcSrcSize = lstrlenW((LPCWSTR)pSrcStr);
         *pcDstSize = min(*pcSrcSize, *pcDstSize);
         *pcSrcSize *= sizeof(WCHAR);
-        memmove(pDstStr, pSrcStr, *pcDstSize * sizeof(WCHAR));
+        if (pDstStr)
+            memmove(pDstStr, pSrcStr, *pcDstSize * sizeof(WCHAR));
         break;
 
     default:
         if (*pcSrcSize == -1)
             *pcSrcSize = lstrlenA(pSrcStr);
 
-        *pcDstSize = MultiByteToWideChar(dwEncoding, 0, pSrcStr, *pcSrcSize, pDstStr, *pcDstSize);
+        if (pDstStr)
+            *pcDstSize = MultiByteToWideChar(dwEncoding, 0, pSrcStr, *pcSrcSize, pDstStr, *pcDstSize);
+        else
+            *pcDstSize = MultiByteToWideChar(dwEncoding, 0, pSrcStr, *pcSrcSize, NULL, 0);
         break;
     }
     
@@ -461,14 +465,18 @@ HRESULT WINAPI ConvertINetUnicodeToMulti
         if (*pcSrcSize == -1)
             *pcSrcSize = lstrlenW(pSrcStr);
         *pcDstSize = min(*pcSrcSize * sizeof(WCHAR), *pcDstSize);
-        memmove(pDstStr, pSrcStr, *pcDstSize);
+        if (pDstStr)
+            memmove(pDstStr, pSrcStr, *pcDstSize);
         break;
 
     default:
         if (*pcSrcSize == -1)
             *pcSrcSize = lstrlenW(pSrcStr);
 
-        *pcDstSize = WideCharToMultiByte(dwEncoding, 0, pSrcStr, *pcSrcSize, pDstStr, *pcDstSize, NULL, NULL);
+        if (pDstStr)
+            *pcDstSize = WideCharToMultiByte(dwEncoding, 0, pSrcStr, *pcSrcSize, pDstStr, *pcDstSize, NULL, NULL);
+        else
+            *pcDstSize = WideCharToMultiByte(dwEncoding, 0, pSrcStr, *pcSrcSize, NULL, 0, NULL, NULL);
         break;
     }
 
@@ -687,7 +695,7 @@ typedef struct tagMLang_impl
     ICOM_VTABLE(IMultiLanguage) *vtbl_IMultiLanguage;
     ICOM_VTABLE(IMultiLanguage2) *vtbl_IMultiLanguage2;
     DWORD ref;
-    DWORD total;
+    DWORD total_cp, total_scripts;
 } MLang_impl;
 
 static ULONG WINAPI MLang_AddRef( MLang_impl* This)
@@ -887,6 +895,7 @@ static HRESULT EnumCodePage_create( MLan
     ecp = HeapAlloc( GetProcessHeap(), 0, sizeof (EnumCodePage_impl) );
     ecp->vtbl_IEnumCodePage = &IEnumCodePage_vtbl;
     ecp->ref = 1;
+    ecp->pos = 0;
     ecp->total = 0;
     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
     {
@@ -919,6 +928,161 @@ static HRESULT EnumCodePage_create( MLan
 
 /******************************************************************************/
 
+typedef struct tagEnumScript_impl
+{
+    ICOM_VTABLE(IEnumScript) *vtbl_IEnumScript;
+    DWORD ref;
+    SCRIPTINFO *script_info;
+    DWORD total, pos;
+} EnumScript_impl;
+
+static HRESULT WINAPI fnIEnumScript_QueryInterface(
+        IEnumScript* iface,
+        REFIID riid,
+        void** ppvObject)
+{
+    ICOM_THIS_MULTI(EnumScript_impl, vtbl_IEnumScript, iface);
+
+    TRACE("%p -> %s\n", This, debugstr_guid(riid) );
+
+    if (IsEqualGUID(riid, &IID_IUnknown)
+        || IsEqualGUID(riid, &IID_IEnumScript))
+    {
+        IEnumScript_AddRef(iface);
+        TRACE("Returning IID_IEnumScript %p ref = %ld\n", This, This->ref);
+        *ppvObject = &(This->vtbl_IEnumScript);
+        return S_OK;
+    }
+
+    WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI fnIEnumScript_AddRef(
+        IEnumScript* iface)
+{
+    ICOM_THIS_MULTI(EnumScript_impl, vtbl_IEnumScript, iface);
+    return ++(This->ref);
+}
+
+static ULONG WINAPI fnIEnumScript_Release(
+        IEnumScript* iface)
+{
+    ICOM_THIS_MULTI(EnumScript_impl, vtbl_IEnumScript, iface);
+    ULONG ref = --This->ref;
+
+    TRACE("%p ref = %ld\n", This, ref);
+    if (ref == 0)
+    {
+        TRACE("Destroying %p\n", This);
+        HeapFree(GetProcessHeap(), 0, This);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI fnIEnumScript_Clone(
+        IEnumScript* iface,
+        IEnumScript** ppEnum)
+{
+    ICOM_THIS_MULTI(EnumScript_impl, vtbl_IEnumScript, iface);
+    FIXME("%p %p: stub!\n", This, ppEnum);
+    return E_NOTIMPL;
+}
+
+static  HRESULT WINAPI fnIEnumScript_Next(
+        IEnumScript* iface,
+        ULONG celt,
+        PSCRIPTINFO rgelt,
+        ULONG* pceltFetched)
+{
+    ICOM_THIS_MULTI(EnumScript_impl, vtbl_IEnumScript, iface);
+    TRACE("%p %lu %p %p\n", This, celt, rgelt, pceltFetched);
+
+    if (!pceltFetched || !rgelt) return E_FAIL;
+
+    *pceltFetched = 0;
+
+    if (This->pos + celt > This->total)
+        celt = This->total - This->pos;
+
+    if (!celt) return S_FALSE;
+
+    memcpy(rgelt, This->script_info + This->pos, celt * sizeof(SCRIPTINFO));
+    *pceltFetched = celt;
+    This->pos += celt;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI fnIEnumScript_Reset(
+        IEnumScript* iface)
+{
+    ICOM_THIS_MULTI(EnumScript_impl, vtbl_IEnumScript, iface);
+    TRACE("%p\n", This);
+
+    This->pos = 0;
+    return S_OK;
+}
+
+static  HRESULT WINAPI fnIEnumScript_Skip(
+        IEnumScript* iface,
+        ULONG celt)
+{
+    ICOM_THIS_MULTI(EnumScript_impl, vtbl_IEnumScript, iface);
+    TRACE("%p %lu\n", This, celt);
+
+    if (celt >= This->total) return S_FALSE;
+
+    This->pos = celt;  /* FIXME: should be += ?? */
+    return S_OK;
+}
+
+static ICOM_VTABLE(IEnumScript) IEnumScript_vtbl =
+{
+    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+    fnIEnumScript_QueryInterface,
+    fnIEnumScript_AddRef,
+    fnIEnumScript_Release,
+    fnIEnumScript_Clone,
+    fnIEnumScript_Next,
+    fnIEnumScript_Reset,
+    fnIEnumScript_Skip
+};
+
+static HRESULT EnumScript_create( MLang_impl* mlang, DWORD dwFlags,
+                     LANGID LangId, IEnumScript** ppEnumScript )
+{
+    static const WCHAR defaultW[] = { 'D','e','f','a','u','l','t',0 };
+    EnumScript_impl *es;
+
+    FIXME("%p, %08lx, %04x, %p: stub!\n", mlang, dwFlags, LangId, ppEnumScript);
+
+    if (!dwFlags) /* enumerate all available scripts */
+        dwFlags = SCRIPTCONTF_SCRIPT_USER | SCRIPTCONTF_SCRIPT_HIDE | SCRIPTCONTF_SCRIPT_SYSTEM;
+
+    es = HeapAlloc( GetProcessHeap(), 0, sizeof (EnumScript_impl) );
+    es->vtbl_IEnumScript = &IEnumScript_vtbl;
+    es->ref = 1;
+    es->pos = 0;
+    es->total = 1;
+
+    es->script_info = HeapAlloc(GetProcessHeap(), 0, sizeof(SCRIPTINFO) * es->total);
+
+    /* just a fake for now */
+    es->script_info[0].ScriptId = 0;
+    es->script_info[0].uiCodePage = 0;
+    strcpyW(es->script_info[0].wszDescription, defaultW);
+    es->script_info[0].wszFixedWidthFont[0] = 0;
+    es->script_info[0].wszProportionalFont[0] = 0;
+
+    *ppEnumScript = (IEnumScript *)es;
+
+    return S_OK;
+}
+
+/******************************************************************************/
+
 static HRESULT WINAPI fnIMLangFontLink_QueryInterface(
         IMLangFontLink* iface,
         REFIID riid,
@@ -1260,7 +1424,7 @@ static HRESULT WINAPI fnIMultiLanguage2_
 
     if (!pcCodePage) return S_FALSE;
 
-    *pcCodePage = This->total;
+    *pcCodePage = This->total_cp;
     return S_OK;
 }
 
@@ -1489,6 +1653,21 @@ static HRESULT WINAPI fnIMultiLanguage2_
     return E_NOTIMPL;
 }
 
+static HRESULT WINAPI fnIMultiLanguage2_ConvertStringFromUnicodeEx(
+    IMultiLanguage2* This,
+    DWORD* pdwMode,
+    DWORD dwEncoding,
+    WCHAR* pSrcStr,
+    UINT* pcSrcSize,
+    CHAR* pDstStr,
+    UINT* pcDstSize,
+    DWORD dwFlag,
+    WCHAR* lpFallBack)
+{
+    FIXME("\n");
+    return E_NOTIMPL;
+}
+
 static HRESULT WINAPI fnIMultiLanguage2_DetectCodepageInIStream(
     IMultiLanguage2* iface,
     DWORD dwFlag,
@@ -1554,8 +1733,13 @@ static HRESULT WINAPI fnIMultiLanguage2_
     IMultiLanguage2* iface,
     UINT* pnScripts)
 {
-    FIXME("\n");
-    return E_NOTIMPL;
+    ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage2, iface);
+    TRACE("%p %p\n", This, pnScripts);
+
+    if (!pnScripts) return S_FALSE;
+
+    *pnScripts = This->total_scripts;
+    return S_OK;
 }
 
 static HRESULT WINAPI fnIMultiLanguage2_EnumScripts(
@@ -1564,8 +1748,10 @@ static HRESULT WINAPI fnIMultiLanguage2_
     LANGID LangId,
     IEnumScript** ppEnumScript)
 {
-    FIXME("\n");
-    return E_NOTIMPL;
+    ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage2, iface);
+    TRACE("%p %08lx %04x %p\n", This, dwFlags, LangId, ppEnumScript);
+
+    return EnumScript_create( This, dwFlags, LangId, ppEnumScript );
 }
 
 static HRESULT WINAPI fnIMultiLanguage2_ValidateCodePageEx(
@@ -1574,8 +1760,10 @@ static HRESULT WINAPI fnIMultiLanguage2_
     HWND hwnd,
     DWORD dwfIODControl)
 {
-    FIXME("\n");
-    return E_NOTIMPL;
+    ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage2, iface);
+    FIXME("%p %u %p %08lx: stub!\n", This, uiCodePage, hwnd, dwfIODControl);
+
+    return S_FALSE;
 }
 
 static ICOM_VTABLE(IMultiLanguage2) IMultiLanguage2_vtbl =
@@ -1601,6 +1789,7 @@ static ICOM_VTABLE(IMultiLanguage2) IMul
     fnIMultiLanguage2_CreateConvertCharset,
     fnIMultiLanguage2_ConvertStringInIStream,
     fnIMultiLanguage2_ConvertStringToUnicodeEx,
+    fnIMultiLanguage2_ConvertStringFromUnicodeEx,
     fnIMultiLanguage2_DetectCodepageInIStream,
     fnIMultiLanguage2_DetectInputCodepage,
     fnIMultiLanguage2_ValidateCodePage,
@@ -1624,9 +1813,11 @@ static HRESULT MultiLanguage_create(IUnk
     mlang->vtbl_IMultiLanguage = &IMultiLanguage_vtbl;
     mlang->vtbl_IMultiLanguage2 = &IMultiLanguage2_vtbl;
 
-    mlang->total = 0;
+    mlang->total_cp = 0;
     for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
-        mlang->total += mlang_data[i].number_of_cp;
+        mlang->total_cp += mlang_data[i].number_of_cp;
+
+    mlang->total_scripts = 1;
 
     mlang->ref = 1;
     *ppObj = (LPVOID) mlang;
diff -u cvs/hq/wine/dlls/mlang/tests/mlang.c wine/dlls/mlang/tests/mlang.c
--- cvs/hq/wine/dlls/mlang/tests/mlang.c	2004-08-05 03:33:06.000000000 +0900
+++ wine/dlls/mlang/tests/mlang.c	2004-08-08 16:15:02.000000000 +0900
@@ -35,6 +35,7 @@
 #endif
 
 /*#define DUMP_CP_INFO*/
+/*#define DUMP_SCRIPT_INFO*/
 
 #define TRACE_2 OutputDebugStringA
 
@@ -45,8 +46,19 @@ static void test_multibyte_to_unicode_tr
     WCHAR stringW[] = {'J','u','s','t',' ','a',' ','t','e','s','t',' ','s','t','r','i','n','g',0};
     char bufA[256];
     WCHAR bufW[256];
-    UINT lenA, lenW;
+    UINT lenA, lenW, expected_len;
     HRESULT ret;
+    HMODULE hMlang;
+    FARPROC pConvertINetMultiByteToUnicode;
+    FARPROC pConvertINetUnicodeToMultiByte;
+
+    hMlang = LoadLibraryA("mlang.dll");
+    ok(hMlang != 0, "couldn't load mlang.dll\n");
+
+    pConvertINetMultiByteToUnicode = GetProcAddress(hMlang, "ConvertINetMultiByteToUnicode");
+    ok(pConvertINetMultiByteToUnicode != NULL, "couldn't resolve ConvertINetMultiByteToUnicode\n");
+    pConvertINetUnicodeToMultiByte = GetProcAddress(hMlang, "ConvertINetUnicodeToMultiByte");
+    ok(pConvertINetUnicodeToMultiByte != NULL, "couldn't resolve ConvertINetUnicodeToMultiByte\n");
 
     /* IMultiLanguage2_ConvertStringToUnicode tests */
 
@@ -93,6 +105,33 @@ static void test_multibyte_to_unicode_tr
     bufW[lenW] = 0; /* -1 doesn't include 0 terminator */
     ok(!lstrcmpA((LPCSTR)bufW, stringA), "bufW/stringA mismatch\n");
 
+    memset(bufW, 'x', sizeof(bufW));
+    lenA = lstrlenA(stringA);
+    lenW = 0;
+    ret = IMultiLanguage2_ConvertStringToUnicode(iML2, NULL, 1252, stringA, &lenA, NULL, &lenW);
+    ok(ret == S_OK, "IMultiLanguage2_ConvertStringToUnicode failed: %08lx\n", ret);
+    ok(lenA == lstrlenA(stringA), "expected lenA %u, got %u\n", lstrlenA(stringA), lenA);
+    expected_len = MultiByteToWideChar(1252, 0, stringA, lenA, NULL, 0);
+    ok(lenW == expected_len, "expected lenW %u, got %u\n", expected_len, lenW);
+
+    memset(bufW, 'x', sizeof(bufW));
+    lenA = lstrlenA(stringA);
+    lenW = sizeof(bufW)/sizeof(bufW[0]);
+    ret = pConvertINetMultiByteToUnicode(NULL, 1252, stringA, &lenA, NULL, &lenW);
+    ok(ret == S_OK, "ConvertINetMultiByteToUnicode failed: %08lx\n", ret);
+    ok(lenA == lstrlenA(stringA), "expected lenA %u, got %u\n", lstrlenA(stringA), lenA);
+    expected_len = MultiByteToWideChar(1252, 0, stringA, lenA, NULL, 0);
+    ok(lenW == expected_len, "expected lenW %u, got %u\n", expected_len, lenW);
+
+    memset(bufW, 'x', sizeof(bufW));
+    lenA = lstrlenA(stringA);
+    lenW = 0;
+    ret = pConvertINetMultiByteToUnicode(NULL, 1252, stringA, &lenA, NULL, &lenW);
+    ok(ret == S_OK, "ConvertINetMultiByteToUnicode failed: %08lx\n", ret);
+    ok(lenA == lstrlenA(stringA), "expected lenA %u, got %u\n", lstrlenA(stringA), lenA);
+    expected_len = MultiByteToWideChar(1252, 0, stringA, lenA, NULL, 0);
+    ok(lenW == expected_len, "expected lenW %u, got %u\n", expected_len, lenW);
+
     /* IMultiLanguage2_ConvertStringFromUnicode tests */
 
     memset(bufA, 'x', sizeof(bufA));
@@ -138,6 +177,33 @@ static void test_multibyte_to_unicode_tr
     bufA[lenA] = 0; /* -1 doesn't include 0 terminator */
     bufA[lenA+1] = 0; /* sizeof(WCHAR) */
     ok(!lstrcmpW((LPCWSTR)bufA, stringW), "bufA/stringW mismatch\n");
+
+    memset(bufA, 'x', sizeof(bufA));
+    lenW = lstrlenW(stringW);
+    lenA = 0;
+    ret = IMultiLanguage2_ConvertStringFromUnicode(iML2, NULL, 1252, stringW, &lenW, NULL, &lenA);
+    ok(ret == S_OK, "IMultiLanguage2_ConvertStringFromUnicode failed: %08lx\n", ret);
+    ok(lenW == lstrlenW(stringW), "expected lenW %u, got %u\n", lstrlenW(stringW), lenW);
+    expected_len = WideCharToMultiByte(1252, 0, stringW, lenW, NULL, 0, NULL, NULL);
+    ok(lenA == expected_len, "expected lenA %u, got %u\n", expected_len, lenA);
+
+    memset(bufA, 'x', sizeof(bufA));
+    lenW = lstrlenW(stringW);
+    lenA = sizeof(bufA);
+    ret = pConvertINetUnicodeToMultiByte(NULL, 1252, stringW, &lenW, NULL, &lenA);
+    ok(ret == S_OK, "ConvertINetUnicodeToMultiByte failed: %08lx\n", ret);
+    ok(lenW == lstrlenW(stringW), "expected lenW %u, got %u\n", lstrlenW(stringW), lenW);
+    expected_len = WideCharToMultiByte(1252, 0, stringW, lenW, NULL, 0, NULL, NULL);
+    ok(lenA == expected_len, "expected lenA %u, got %u\n", expected_len, lenA);
+
+    memset(bufA, 'x', sizeof(bufA));
+    lenW = lstrlenW(stringW);
+    lenA = 0;
+    ret = pConvertINetUnicodeToMultiByte(NULL, 1252, stringW, &lenW, NULL, &lenA);
+    ok(ret == S_OK, "ConvertINetUnicodeToMultiByte failed: %08lx\n", ret);
+    ok(lenW == lstrlenW(stringW), "expected lenW %u, got %u\n", lstrlenW(stringW), lenW);
+    expected_len = WideCharToMultiByte(1252, 0, stringW, lenW, NULL, 0, NULL, NULL);
+    ok(lenA == expected_len, "expected lenA %u, got %u\n", expected_len, lenA);
 }
 
 static void inline cpinfo_cmp(MIMECPINFO *cpinfo1, MIMECPINFO *cpinfo2)
@@ -222,7 +288,7 @@ static void test_EnumCodePages(IMultiLan
     n = total * 2;
     TRACE_2("Call IEnumCodePage_Next\n");
     ret = IEnumCodePage_Next(iEnumCP, n, cpinfo, &n);
-    ok(ret == S_OK && n != 0, "IEnumCodePage_Next: expected S_OK, got %08lx/%lu\n", ret, n);
+    ok(ret == S_OK && n != 0, "IEnumCodePage_Next: expected S_OK/!0, got %08lx/%lu\n", ret, n);
 
     trace("flags %08lx, enumerated codepages %lu\n", flags, n);
 
@@ -310,13 +376,13 @@ static void test_EnumCodePages(IMultiLan
     /* now IEnumCodePage_Next should fail, since pointer is at the end */
     n = 1;
     ret = IEnumCodePage_Next(iEnumCP, 1, &cpinfo2, &n);
-    ok(ret == S_FALSE && n == 0, "IEnumCodePage_Next: expected S_OK/0, got %08lx/%lu\n", ret, n);
+    ok(ret == S_FALSE && n == 0, "IEnumCodePage_Next: expected S_FALSE/0, got %08lx/%lu\n", ret, n);
 
     ret = IEnumCodePage_Reset(iEnumCP);
     ok(ret == S_OK, "IEnumCodePage_Reset: expected S_OK, got %08lx\n", ret);
     n = 0;
     ret = IEnumCodePage_Next(iEnumCP, 1, &cpinfo2, &n);
-    ok(n == 1 && ret == S_OK, "IEnumCodePage_Next: expected 2/S_OK, got %lu/%08lx\n", n, ret);
+    ok(n == 1 && ret == S_OK, "IEnumCodePage_Next: expected 1/S_OK, got %lu/%08lx\n", n, ret);
     cpinfo_cmp(&cpinfo[0], &cpinfo2);
 
 #if 0
@@ -338,6 +404,125 @@ static void test_EnumCodePages(IMultiLan
     IEnumCodePage_Release(iEnumCP);
 }
 
+static void inline scriptinfo_cmp(SCRIPTINFO *sinfo1, SCRIPTINFO *sinfo2)
+{
+    ok(sinfo1->ScriptId == sinfo2->ScriptId, "ScriptId mismatch: %d != %d\n", sinfo1->ScriptId, sinfo2->ScriptId);
+    ok(sinfo1->uiCodePage == sinfo2->uiCodePage, "uiCodePage mismatch: %u != %u\n", sinfo1->uiCodePage, sinfo2->uiCodePage);
+    ok(!lstrcmpW(sinfo1->wszDescription, sinfo2->wszDescription), "wszDescription mismatch\n");
+    ok(!lstrcmpW(sinfo1->wszFixedWidthFont, sinfo2->wszFixedWidthFont), "wszFixedWidthFont mismatch\n");
+    ok(!lstrcmpW(sinfo1->wszProportionalFont, sinfo2->wszProportionalFont), "wszProportionalFont mismatch\n");
+}
+
+static void test_EnumScripts(IMultiLanguage2 *iML2, DWORD flags)
+{
+    IEnumScript *iEnumScript = NULL;
+    SCRIPTINFO *sinfo;
+    SCRIPTINFO sinfo2;
+    HRESULT ret;
+    ULONG i, n;
+    UINT total;
+
+    total = 0;
+    TRACE_2("Call IMultiLanguage2_GetNumberOfScripts\n");
+    ret = IMultiLanguage2_GetNumberOfScripts(iML2, &total);
+    ok(ret == S_OK && total != 0, "IMultiLanguage2_GetNumberOfScripts: expected S_OK/!0, got %08lx/%u\n", ret, total);
+
+    trace("total mlang supported scripts %u\n", total);
+
+    TRACE_2("Call IMultiLanguage2_EnumScripts\n");
+    ret = IMultiLanguage2_EnumScripts(iML2, flags, LANG_NEUTRAL, &iEnumScript);
+    trace("IMultiLanguage2_EnumScripts = %08lx, iEnumScript = %p\n", ret, iEnumScript);
+    ok(ret == S_OK && iEnumScript, "IMultiLanguage2_EnumScripts: expected S_OK/!NULL, got %08lx/%p\n", ret, iEnumScript);
+
+    TRACE_2("Call IEnumScript_Reset\n");
+    ret = IEnumScript_Reset(iEnumScript);
+    ok(ret == S_OK, "IEnumScript_Reset: expected S_OK, got %08lx\n", ret);
+    n = 65536;
+    TRACE_2("Call IEnumScript_Next\n");
+    ret = IEnumScript_Next(iEnumScript, 0, NULL, &n);
+    ok(n == 65536 && ret == E_FAIL, "IEnumScript_Next: expected 65536/E_FAIL, got %lu/%08lx\n", n, ret);
+    TRACE_2("Call IEnumScript_Next\n");
+    ret = IEnumScript_Next(iEnumScript, 0, NULL, NULL);
+    ok(ret == E_FAIL, "IEnumScript_Next: expected E_FAIL, got %08lx\n", ret);
+
+    sinfo = HeapAlloc(GetProcessHeap(), 0, sizeof(*sinfo) * total * 2);
+
+    n = total * 2;
+    TRACE_2("Call IEnumScript_Next\n");
+    ret = IEnumScript_Next(iEnumScript, 0, sinfo, &n);
+    ok(ret == S_FALSE && n == 0, "IEnumScript_Next: expected S_FALSE/0, got %08lx/%lu\n", ret, n);
+
+    n = total * 2;
+    TRACE_2("Call IEnumScript_Next\n");
+    ret = IEnumScript_Next(iEnumScript, n, sinfo, &n);
+    ok(ret == S_OK && n != 0, "IEnumScript_Next: expected S_OK, got %08lx/%lu\n", ret, n);
+
+    trace("flags %08lx, enumerated scripts %lu\n", flags, n);
+
+    if (!flags)
+    {
+	ok(n == total, "IEnumScript_Next: expected %u, got %lu", total, n);
+	flags = SCRIPTCONTF_SCRIPT_USER | SCRIPTCONTF_SCRIPT_HIDE | SCRIPTCONTF_SCRIPT_SYSTEM;
+    }
+
+    total = n;
+
+    for (i = 0; i < n; i++)
+    {
+	CPINFOEXA cpinfoex;
+#ifdef DUMP_SCRIPT_INFO
+	trace("SCRIPTINFO #%lu:\n"
+	      "ScriptId %08lx\n"
+	      "uiCodePage %u\n"
+	      "wszDescription %s\n"
+	      "wszFixedWidthFont %s\n"
+	      "wszProportionalFont %s\n\n",
+	      i,
+	      sinfo[i].ScriptId,
+	      sinfo[i].uiCodePage,
+	      wine_dbgstr_w(sinfo[i].wszDescription),
+	      wine_dbgstr_w(sinfo[i].wszFixedWidthFont),
+	      wine_dbgstr_w(sinfo[i].wszProportionalFont));
+#endif
+	if (GetCPInfoExA(sinfo[i].uiCodePage, 0, &cpinfoex))
+	    trace("CodePage %u name: %s\n", sinfo[i].uiCodePage, cpinfoex.CodePageName);
+	else
+	    trace("GetCPInfoExA failed for cp %u\n", sinfo[i].uiCodePage);
+
+	trace("---\n");
+    }
+
+    /* now IEnumScript_Next should fail, since pointer is at the end */
+    n = 1;
+    ret = IEnumScript_Next(iEnumScript, 1, &sinfo2, &n);
+    ok(ret == S_FALSE && n == 0, "IEnumScript_Next: expected S_FALSE/0, got %08lx/%lu\n", ret, n);
+
+    ret = IEnumScript_Reset(iEnumScript);
+    ok(ret == S_OK, "IEnumScript_Reset: expected S_OK, got %08lx\n", ret);
+    n = 0;
+    ret = IEnumScript_Next(iEnumScript, 1, &sinfo2, &n);
+    ok(n == 1 && ret == S_OK, "IEnumScript_Next: expected 1/S_OK, got %lu/%08lx\n", n, ret);
+    scriptinfo_cmp(&sinfo[0], &sinfo2);
+
+#if 0
+    /* Due to a bug in MS' implementation of IEnumScript_Skip
+     * it's not used here.
+     */
+    ret = IEnumScript_Skip(iEnumScript, 1);
+    ok(ret == S_OK, "IEnumScript_Skip: expected S_OK, got %08lx\n", ret);
+#endif
+    for (i = 0; i < total - 1; i++)
+    {
+        n = 0;
+        ret = IEnumScript_Next(iEnumScript, 1, &sinfo2, &n);
+        ok(n == 1 && ret == S_OK, "IEnumScript_Next: expected 1/S_OK, got %lu/%08lx\n", n, ret);
+        scriptinfo_cmp(&sinfo[i + 1], &sinfo2);
+    }
+
+    HeapFree(GetProcessHeap(), 0, sinfo);
+    IEnumScript_Release(iEnumScript);
+}
+
 START_TEST(mlang)
 {
     IMultiLanguage2 *iML2 = NULL;
@@ -359,6 +544,10 @@ START_TEST(mlang)
     /* FIXME: why MIMECONTF_MIME_REGISTRY returns 0 of supported codepages? */
     /*test_EnumCodePages(iML2, MIMECONTF_MIME_REGISTRY);*/
 
+    test_EnumScripts(iML2, 0);
+    test_EnumScripts(iML2, SCRIPTCONTF_SCRIPT_USER);
+    test_EnumScripts(iML2, SCRIPTCONTF_SCRIPT_USER | SCRIPTCONTF_SCRIPT_HIDE | SCRIPTCONTF_SCRIPT_SYSTEM);
+
     TRACE_2("Call IMultiLanguage2_IsConvertible\n");
     ret = IMultiLanguage2_IsConvertible(iML2, CP_UTF8, CP_UNICODE);
     ok(ret == S_OK, "IMultiLanguage2_IsConvertible(CP_UTF8 -> CP_UNICODE) = %08lx\n", ret);
diff -u cvs/hq/wine/include/mlang.h wine/include/mlang.h
--- cvs/hq/wine/include/mlang.h	2004-08-07 14:02:27.000000000 +0900
+++ wine/include/mlang.h	2004-08-07 16:07:38.000000000 +0900
@@ -346,14 +346,78 @@ typedef struct IEnumScript IEnumScript;
 
 #define MAX_SCRIPT_NAME (48)
 
+#define MAX_MIMEFACE_NAME (32)
+
 typedef BYTE SCRIPT_ID;
 
+typedef __int64 SCRIPT_IDS;
+
+typedef enum tagSCRIPTCONTF {
+    sidDefault = 0,
+    sidMerge = sidDefault + 1,
+    sidAsciiSym = sidMerge + 1,
+    sidAsciiLatin = sidAsciiSym + 1,
+    sidLatin = sidAsciiLatin + 1,
+    sidGreek = sidLatin + 1,
+    sidCyrillic = sidGreek + 1,
+    sidArmenian = sidCyrillic + 1,
+    sidHebrew = sidArmenian + 1,
+    sidArabic = sidHebrew + 1,
+    sidDevanagari = sidArabic + 1,
+    sidBengali = sidDevanagari + 1,
+    sidGurmukhi = sidBengali + 1,
+    sidGujarati = sidGurmukhi + 1,
+    sidOriya = sidGujarati + 1,
+    sidTamil = sidOriya + 1,
+    sidTelugu = sidTamil + 1,
+    sidKannada = sidTelugu + 1,
+    sidMalayalam = sidKannada + 1,
+    sidThai = sidMalayalam + 1,
+    sidLao = sidThai + 1,
+    sidTibetan = sidLao + 1,
+    sidGeorgian = sidTibetan + 1,
+    sidHangul = sidGeorgian + 1,
+    sidKana = sidHangul + 1,
+    sidBopomofo = sidKana + 1,
+    sidHan = sidBopomofo + 1,
+    sidEthiopic = sidHan + 1,
+    sidCanSyllabic = sidEthiopic + 1,
+    sidCherokee = sidCanSyllabic + 1,
+    sidYi = sidCherokee + 1,
+    sidBraille = sidYi + 1,
+    sidRunic = sidBraille + 1,
+    sidOgham = sidRunic + 1,
+    sidSinhala = sidOgham + 1,
+    sidSyriac = sidSinhala + 1,
+    sidBurmese = sidSyriac + 1,
+    sidKhmer = sidBurmese + 1,
+    sidThaana = sidKhmer + 1,
+    sidMongolian = sidThaana + 1,
+    sidUserDefined = sidMongolian + 1,
+    sidLim = sidUserDefined + 1,
+    sidFEFirst = sidHangul,
+    sidFELast = sidHan
+} SCRIPTCONTF;
+
+typedef enum tagSCRIPTFONTCONTF {
+    SCRIPTCONTF_FIXED_FONT = 0x1,
+    SCRIPTCONTF_PROPORTIONAL_FONT = 0x2,
+    SCRIPTCONTF_SCRIPT_USER = 0x10000,
+    SCRIPTCONTF_SCRIPT_HIDE = 0x20000,
+    SCRIPTCONTF_SCRIPT_SYSTEM = 0x40000
+} SCRIPTFONTCONTF;
+
+typedef struct tagSCRIPFONTINFO {
+    SCRIPT_IDS scripts;
+    WCHAR wszFont[32];
+} SCRIPTFONTINFO, *PSCRIPTFONTINFO;
+
 typedef struct tagSCRIPTINFO {
     SCRIPT_ID ScriptId;
     UINT uiCodePage;
     WCHAR wszDescription[48];
-    WCHAR wszFixedWidthFont[1];
-    WCHAR wszProportionalFont[1];
+    WCHAR wszFixedWidthFont[32];
+    WCHAR wszProportionalFont[32];
 } SCRIPTINFO, *PSCRIPTINFO;
 
 /*****************************************************************************
@@ -489,8 +553,6 @@ typedef struct IEnumCodePage IEnumCodePa
 
 #define MAX_MIMECSET_NAME (50)
 
-#define MAX_MIMEFACE_NAME (32)
-
 typedef enum tagMIMECONTF {
     MIMECONTF_MAILNEWS = 0x1,
     MIMECONTF_BROWSER = 0x2,
@@ -1501,6 +1563,16 @@ struct IMultiLanguage2 : public IUnknown
         DWORD dwFlag,
         WCHAR* lpFallBack) = 0;
 
+    virtual HRESULT STDMETHODCALLTYPE ConvertStringFromUnicodeEx(
+        DWORD* pdwMode,
+        DWORD dwEncoding,
+        WCHAR* pSrcStr,
+        UINT* pcSrcSize,
+        CHAR* pDstStr,
+        UINT* pcDstSize,
+        DWORD dwFlag,
+        WCHAR* lpFallBack) = 0;
+
     virtual HRESULT STDMETHODCALLTYPE DetectCodepageInIStream(
         DWORD dwFlag,
         DWORD dwPrefWinCodePage,
@@ -1678,6 +1750,17 @@ struct IMultiLanguage2Vtbl {
         DWORD dwFlag,
         WCHAR* lpFallBack);
 
+    HRESULT (STDMETHODCALLTYPE *ConvertStringFromUnicodeEx)(
+        IMultiLanguage2* This,
+        DWORD* pdwMode,
+        DWORD dwEncoding,
+        WCHAR* pSrcStr,
+        UINT* pcSrcSize,
+        CHAR* pDstStr,
+        UINT* pcDstSize,
+        DWORD dwFlag,
+        WCHAR* lpFallBack);
+
     HRESULT (STDMETHODCALLTYPE *DetectCodepageInIStream)(
         IMultiLanguage2* This,
         DWORD dwFlag,
@@ -1755,6 +1838,7 @@ struct IMultiLanguage2Vtbl {
 #define IMultiLanguage2_CreateConvertCharset(p,a,b,c,d) (p)->lpVtbl->CreateConvertCharset(p,a,b,c,d)
 #define IMultiLanguage2_ConvertStringInIStream(p,a,b,c,d,e,f,g) (p)->lpVtbl->ConvertStringInIStream(p,a,b,c,d,e,f,g)
 #define IMultiLanguage2_ConvertStringToUnicodeEx(p,a,b,c,d,e,f,g,h) (p)->lpVtbl->ConvertStringToUnicodeEx(p,a,b,c,d,e,f,g,h)
+#define IMultiLanguage2_ConvertStringFromUnicodeEx(p,a,b,c,d,e,f,g,h) (p)->lpVtbl->ConvertStringFromUnicodeEx(p,a,b,c,d,e,f,g,h)
 #define IMultiLanguage2_DetectCodepageInIStream(p,a,b,c,d,e) (p)->lpVtbl->DetectCodepageInIStream(p,a,b,c,d,e)
 #define IMultiLanguage2_DetectInputCodepage(p,a,b,c,d,e,f) (p)->lpVtbl->DetectInputCodepage(p,a,b,c,d,e,f)
 #define IMultiLanguage2_ValidateCodePage(p,a,b) (p)->lpVtbl->ValidateCodePage(p,a,b)
@@ -1791,6 +1875,7 @@ struct IMultiLanguage2Vtbl {
     STDMETHOD_(HRESULT,CreateConvertCharset)(THIS_ UINT uiSrcCodePage, UINT uiDstCodePage, DWORD dwProperty, IMLangConvertCharset** ppMLangConvertCharset) PURE; \
     STDMETHOD_(HRESULT,ConvertStringInIStream)(THIS_ DWORD* pdwMode, DWORD dwFlag, WCHAR* lpFallBack, DWORD dwSrcEncoding, DWORD dwDstEncoding, IStream* pstmIn, IStream* pstmOut) PURE; \
     STDMETHOD_(HRESULT,ConvertStringToUnicodeEx)(THIS_ DWORD* pdwMode, DWORD dwEncoding, CHAR* pSrcStr, UINT* pcSrcSize, WCHAR* pDstStr, UINT* pcDstSize, DWORD dwFlag, WCHAR* lpFallBack) PURE; \
+    STDMETHOD_(HRESULT,ConvertStringFromUnicodeEx)(THIS_ DWORD* pdwMode, DWORD dwEncoding, WCHAR* pSrcStr, UINT* pcSrcSize, CHAR* pDstStr, UINT* pcDstSize, DWORD dwFlag, WCHAR* lpFallBack) PURE; \
     STDMETHOD_(HRESULT,DetectCodepageInIStream)(THIS_ DWORD dwFlag, DWORD dwPrefWinCodePage, IStream* pstmIn, DetectEncodingInfo* lpEncoding, INT* pnScores) PURE; \
     STDMETHOD_(HRESULT,DetectInputCodepage)(THIS_ DWORD dwFlag, DWORD dwPrefWinCodePage, CHAR* pSrcStr, INT* pcSrcSize, DetectEncodingInfo* lpEncoding, INT* pnScores) PURE; \
     STDMETHOD_(HRESULT,ValidateCodePage)(THIS_ UINT uiCodePage, HWND hwnd) PURE; \
@@ -1980,6 +2065,21 @@ void __RPC_STUB IMultiLanguage2_ConvertS
     struct IRpcChannelBuffer* pRpcChannelBuffer,
     PRPC_MESSAGE pRpcMessage,
     DWORD* pdwStubPhase);
+HRESULT CALLBACK IMultiLanguage2_ConvertStringFromUnicodeEx_Proxy(
+    IMultiLanguage2* This,
+    DWORD* pdwMode,
+    DWORD dwEncoding,
+    WCHAR* pSrcStr,
+    UINT* pcSrcSize,
+    CHAR* pDstStr,
+    UINT* pcDstSize,
+    DWORD dwFlag,
+    WCHAR* lpFallBack);
+void __RPC_STUB IMultiLanguage2_ConvertStringFromUnicodeEx_Stub(
+    struct IRpcStubBuffer* This,
+    struct IRpcChannelBuffer* pRpcChannelBuffer,
+    PRPC_MESSAGE pRpcMessage,
+    DWORD* pdwStubPhase);
 HRESULT CALLBACK IMultiLanguage2_DetectCodepageInIStream_Proxy(
     IMultiLanguage2* This,
     DWORD dwFlag,
@@ -2088,6 +2188,7 @@ DEFINE_GUID(IID_IMLangFontLink, 0x359F34
 DEFINE_GUID(IID_IMultiLanguage2, 0xDCCFC164,0x2B38,0x11d2,0xB7,0xEC,0x00,0xC0,0x4F,0x8F,0x5D,0x9A);
 DEFINE_GUID(IID_IMultiLanguage, 0x275c23e1,0x3747,0x11d0,0x9f,0xea,0x00,0xaa,0x00,0x3f,0x86,0x46);
 DEFINE_GUID(IID_IEnumCodePage, 0x275c23e3,0x3747,0x11d0,0x9f,0xea,0x00,0xaa,0x00,0x3f,0x86,0x46);
+DEFINE_GUID(IID_IEnumScript, 0xae5f1430,0x388b,0x11d2,0x83,0x80,0x00,0xc0,0x4f,0x8f,0x5d,0xa1);
 #ifdef __cplusplus
 }
 #endif
diff -u cvs/hq/wine/include/mlang.idl wine/include/mlang.idl
--- cvs/hq/wine/include/mlang.idl	2004-08-07 14:02:27.000000000 +0900
+++ wine/include/mlang.idl	2004-08-07 16:07:30.000000000 +0900
@@ -79,8 +79,73 @@ interface IMLangFontLink : IMLangCodePag
 interface IEnumScript : IUnknown
 {
     const USHORT MAX_SCRIPT_NAME = 48;
+    const USHORT MAX_MIMEFACE_NAME = 32;
 
     typedef BYTE SCRIPT_ID;
+    typedef __int64 SCRIPT_IDS;
+
+    typedef enum tagSCRIPTCONTF
+    {
+        sidDefault = 0,
+        sidMerge = sidDefault + 1,
+        sidAsciiSym = sidMerge + 1,
+        sidAsciiLatin = sidAsciiSym + 1,
+        sidLatin = sidAsciiLatin + 1,
+        sidGreek = sidLatin + 1,
+        sidCyrillic = sidGreek + 1,
+        sidArmenian = sidCyrillic + 1,
+        sidHebrew = sidArmenian + 1,
+        sidArabic = sidHebrew + 1,
+        sidDevanagari = sidArabic + 1,
+        sidBengali = sidDevanagari + 1,
+        sidGurmukhi = sidBengali + 1,
+        sidGujarati = sidGurmukhi + 1,
+        sidOriya = sidGujarati + 1,
+        sidTamil = sidOriya + 1,
+        sidTelugu = sidTamil + 1,
+        sidKannada = sidTelugu + 1,
+        sidMalayalam = sidKannada + 1,
+        sidThai = sidMalayalam + 1,
+        sidLao = sidThai + 1,
+        sidTibetan = sidLao + 1,
+        sidGeorgian = sidTibetan + 1,
+        sidHangul = sidGeorgian + 1,
+        sidKana = sidHangul + 1,
+        sidBopomofo = sidKana + 1,
+        sidHan = sidBopomofo + 1,
+        sidEthiopic = sidHan + 1,
+        sidCanSyllabic = sidEthiopic + 1,
+        sidCherokee = sidCanSyllabic + 1,
+        sidYi = sidCherokee + 1,
+        sidBraille = sidYi + 1,
+        sidRunic = sidBraille + 1,
+        sidOgham = sidRunic + 1,
+        sidSinhala = sidOgham + 1,
+        sidSyriac = sidSinhala + 1,
+        sidBurmese = sidSyriac + 1,
+        sidKhmer = sidBurmese + 1,
+        sidThaana = sidKhmer + 1,
+        sidMongolian = sidThaana + 1,
+        sidUserDefined = sidMongolian + 1,
+        sidLim = sidUserDefined + 1,
+        sidFEFirst = sidHangul,
+        sidFELast = sidHan
+    } SCRIPTCONTF;
+
+    typedef enum tagSCRIPTFONTCONTF
+    {
+        SCRIPTCONTF_FIXED_FONT = 0x1,
+        SCRIPTCONTF_PROPORTIONAL_FONT = 0x2,
+        SCRIPTCONTF_SCRIPT_USER = 0x10000,
+        SCRIPTCONTF_SCRIPT_HIDE = 0x20000,
+        SCRIPTCONTF_SCRIPT_SYSTEM = 0x40000
+    } SCRIPTFONTCONTF;
+
+    typedef struct tagSCRIPFONTINFO
+    {
+        SCRIPT_IDS scripts;
+        WCHAR wszFont[MAX_MIMEFACE_NAME];
+    } SCRIPTFONTINFO, *PSCRIPTFONTINFO;
 
     typedef struct tagSCRIPTINFO {
         SCRIPT_ID ScriptId;
@@ -112,7 +177,6 @@ interface IEnumCodePage : IUnknown
 {
     const USHORT MAX_MIMECP_NAME = 64;
     const USHORT MAX_MIMECSET_NAME = 50;
-    const USHORT MAX_MIMEFACE_NAME = 32;
 
     typedef enum tagMIMECONTF
     {
@@ -418,6 +482,16 @@ interface IMultiLanguage2 : IUnknown
         [in] DWORD dwFlag,
         [in] WCHAR *lpFallBack);
 
+    HRESULT ConvertStringFromUnicodeEx(
+        [in,out] DWORD *pdwMode,
+        [in] DWORD dwEncoding,
+        [in] WCHAR *pSrcStr,
+        [in,out] UINT *pcSrcSize,
+        [in] CHAR *pDstStr,
+        [in,out] UINT *pcDstSize,
+        [in] DWORD dwFlag,
+        [in] WCHAR *lpFallBack);
+
     HRESULT DetectCodepageInIStream(      
         [in] DWORD dwFlag,
         [in] DWORD dwPrefWinCodePage,
@@ -482,3 +556,4 @@ cpp_quote("DEFINE_GUID(IID_IMLangFontLin
 cpp_quote("DEFINE_GUID(IID_IMultiLanguage2, 0xDCCFC164,0x2B38,0x11d2,0xB7,0xEC,0x00,0xC0,0x4F,0x8F,0x5D,0x9A);")
 cpp_quote("DEFINE_GUID(IID_IMultiLanguage, 0x275c23e1,0x3747,0x11d0,0x9f,0xea,0x00,0xaa,0x00,0x3f,0x86,0x46);")
 cpp_quote("DEFINE_GUID(IID_IEnumCodePage, 0x275c23e3,0x3747,0x11d0,0x9f,0xea,0x00,0xaa,0x00,0x3f,0x86,0x46);")
+cpp_quote("DEFINE_GUID(IID_IEnumScript, 0xae5f1430,0x388b,0x11d2,0x83,0x80,0x00,0xc0,0x4f,0x8f,0x5d,0xa1);")
diff -u cvs/hq/wine/programs/winetest/Makefile.in wine/programs/winetest/Makefile.in
--- cvs/hq/wine/programs/winetest/Makefile.in	2004-07-27 23:17:16.000000000 +0900
+++ wine/programs/winetest/Makefile.in	2004-08-07 17:00:02.000000000 +0900
@@ -26,6 +26,7 @@ TESTS = \
 	iphlpapi \
 	kernel32 \
 	mapi32 \
+	mlang \
 	msacm32 \
 	msvcrt \
 	msvcrtd \
@@ -93,6 +94,8 @@ kernel32_test.exe$(DLLEXT): $(DLLDIR)/ke
 	cp $(DLLDIR)/kernel/tests/kernel32_test.exe$(DLLEXT) $@ && $(STRIP) $@
 mapi32_test.exe$(DLLEXT): $(DLLDIR)/mapi32/tests/mapi32_test.exe$(DLLEXT)
 	cp $(DLLDIR)/mapi32/tests/mapi32_test.exe$(DLLEXT) $@ && $(STRIP) $@
+mlang_test.exe$(DLLEXT): $(DLLDIR)/mlang/tests/mlang_test.exe$(DLLEXT)
+	cp $(DLLDIR)/mlang/tests/mlang_test.exe$(DLLEXT) $@ && $(STRIP) $@
 msacm32_test.exe$(DLLEXT): $(DLLDIR)/msacm/tests/msacm32_test.exe$(DLLEXT)
 	cp $(DLLDIR)/msacm/tests/msacm32_test.exe$(DLLEXT) $@ && $(STRIP) $@
 msvcrt_test.exe$(DLLEXT): $(DLLDIR)/msvcrt/tests/msvcrt_test.exe$(DLLEXT)






More information about the wine-patches mailing list