Implement ConvertINetMultiByteToUnicode, ConvertINetUnicodeToMultiByte
and IsConvertINetStringAvailable by moving common code around, add a
stub for ConvertINetString.

diff --git a/dlls/mlang/mlang.c b/dlls/mlang/mlang.c
index 75885a0..847a6ac 100644
--- a/dlls/mlang/mlang.c
+++ b/dlls/mlang/mlang.c
@@ -380,6 +380,165 @@
     return TRUE;
 }
 
+HRESULT WINAPI ConvertINetMultiByteToUnicode(
+    LPDWORD pdwMode,
+    DWORD dwEncoding,
+    LPCSTR pSrcStr,
+    LPINT pcSrcSize,
+    LPWSTR pDstStr,
+    LPINT pcDstSize)
+{
+    INT src_len = -1;
+
+    TRACE("%p %ld %s %p %p %p\n", pdwMode, dwEncoding,
+          debugstr_a(pSrcStr), pcSrcSize, pDstStr, pcDstSize);
+
+    if (!pcDstSize)
+        return E_FAIL;
+
+    if (!pcSrcSize)
+        pcSrcSize = &src_len;
+
+    if (!*pcSrcSize)
+    {
+        *pcDstSize = 0;
+        return S_OK;
+    }
+
+    switch (dwEncoding)
+    {
+    case CP_UNICODE:
+        if (*pcSrcSize == -1)
+            *pcSrcSize = lstrlenW((LPCWSTR)pSrcStr);
+        *pcDstSize = min(*pcSrcSize, *pcDstSize);
+        *pcSrcSize *= sizeof(WCHAR);
+        memmove(pDstStr, pSrcStr, *pcDstSize * sizeof(WCHAR));
+        break;
+
+    default:
+        if (*pcSrcSize == -1)
+            *pcSrcSize = lstrlenA(pSrcStr);
+
+        *pcDstSize = MultiByteToWideChar(dwEncoding, 0, pSrcStr, *pcSrcSize, pDstStr, *pcDstSize);
+        break;
+    }
+    
+    if (!*pcDstSize)
+        return E_FAIL;
+
+    return S_OK;
+}
+
+HRESULT WINAPI ConvertINetUnicodeToMultiByte(
+    LPDWORD pdwMode,
+    DWORD dwEncoding,
+    LPCWSTR pSrcStr,
+    LPINT pcSrcSize,
+    LPSTR pDstStr,
+    LPINT pcDstSize)
+{
+
+    INT src_len = -1;
+
+    TRACE("%p %ld %s %p %p %p\n", pdwMode, dwEncoding,
+          debugstr_w(pSrcStr), pcSrcSize, pDstStr, pcDstSize);
+
+    if (!pcDstSize)
+        return E_FAIL;
+
+    if (!pcSrcSize)
+        pcSrcSize = &src_len;
+
+    if (!*pcSrcSize)
+    {
+        *pcDstSize = 0;
+        return S_OK;
+    }
+
+    switch (dwEncoding)
+    {
+    case CP_UNICODE:
+        if (*pcSrcSize == -1)
+            *pcSrcSize = lstrlenW(pSrcStr);
+        *pcDstSize = min(*pcSrcSize * sizeof(WCHAR), *pcDstSize);
+        memmove(pDstStr, pSrcStr, *pcDstSize);
+        break;
+
+    default:
+        if (*pcSrcSize == -1)
+            *pcSrcSize = lstrlenW(pSrcStr);
+
+        *pcDstSize = WideCharToMultiByte(dwEncoding, 0, pSrcStr, *pcSrcSize, pDstStr, *pcDstSize, NULL, NULL);
+        break;
+    }
+
+
+    if (!*pcDstSize)
+        return E_FAIL;
+
+    return S_OK;
+}
+
+HRESULT WINAPI ConvertINetString(
+    LPDWORD pdwMode,
+    DWORD dwSrcEncoding,
+    DWORD dwDstEncoding,
+    LPCSTR pSrcStr,
+    LPINT pcSrcSize,
+    LPSTR pDstStr,
+    LPINT pcDstSize
+)
+{
+    FIXME("%p %ld %ld %s %p %p %p: stub!\n", pdwMode, dwSrcEncoding, dwDstEncoding,
+          debugstr_a(pSrcStr), pcSrcSize, pDstStr, pcDstSize);
+    return E_NOTIMPL;
+}
+
+static HRESULT GetFamilyCodePage(
+    UINT uiCodePage,
+    UINT* puiFamilyCodePage)
+{
+    UINT i, n;
+
+    TRACE("%u %p\n", uiCodePage, puiFamilyCodePage);
+
+    if (!puiFamilyCodePage) return S_FALSE;
+
+    for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
+    {
+        for (n = 0; n < mlang_data[i].number_of_cp; n++)
+        {
+            if (mlang_data[i].mime_cp_info[n].cp == uiCodePage)
+            {
+                *puiFamilyCodePage = mlang_data[i].family_codepage;
+                return S_OK;
+            }
+        }
+    }
+
+    return S_FALSE;
+}
+
+HRESULT WINAPI IsConvertINetStringAvailable(
+    DWORD dwSrcEncoding,
+    DWORD dwDstEncoding)
+{
+    UINT src_family, dst_family;
+
+    TRACE("%ld %ld\n", dwSrcEncoding, dwDstEncoding);
+
+    if (GetFamilyCodePage(dwSrcEncoding, &src_family) != S_OK ||
+        GetFamilyCodePage(dwDstEncoding, &dst_family) != S_OK)
+        return S_FALSE;
+
+    if (src_family == dst_family) return S_OK;
+
+    /* we can convert any codepage to/from unicode */
+    if (src_family == CP_UNICODE || dst_family == CP_UNICODE) return S_OK;
+
+    return S_FALSE;
+}
+
 /******************************************************************************
  * MLANG ClassFactory
  */
@@ -921,8 +1080,7 @@
     UINT uiCodePage,
     UINT* puiFamilyCodePage)
 {
-    FIXME("\n");
-    return E_NOTIMPL;
+    return GetFamilyCodePage(uiCodePage, puiFamilyCodePage);
 }
 
 static HRESULT WINAPI fnIMultiLanguage_EnumCodePages(
@@ -950,8 +1108,7 @@
     DWORD dwSrcEncoding,
     DWORD dwDstEncoding)
 {
-    FIXME("\n");
-    return E_NOTIMPL;
+    return IsConvertINetStringAvailable(dwSrcEncoding, dwDstEncoding);
 }
 
 static HRESULT WINAPI fnIMultiLanguage_ConvertString(
@@ -964,8 +1121,8 @@
     BYTE* pDstStr,
     UINT* pcDstSize)
 {
-    FIXME("\n");
-    return E_NOTIMPL;
+    return ConvertINetString(pdwMode, dwSrcEncoding, dwDstEncoding,
+                             pSrcStr, pcSrcSize, pDstStr, pcDstSize);
 }
 
 static HRESULT WINAPI fnIMultiLanguage_ConvertStringToUnicode(
@@ -977,8 +1134,8 @@
     WCHAR* pDstStr,
     UINT* pcDstSize)
 {
-    FIXME("\n");
-    return E_NOTIMPL;
+    return ConvertINetMultiByteToUnicode(pdwMode, dwEncoding,
+                                         pSrcStr, pcSrcSize, pDstStr, pcDstSize);
 }
 
 static HRESULT WINAPI fnIMultiLanguage_ConvertStringFromUnicode(
@@ -990,8 +1147,8 @@
     CHAR* pDstStr,
     UINT* pcDstSize)
 {
-    FIXME("\n");
-    return E_NOTIMPL;
+    return ConvertINetUnicodeToMultiByte(pdwMode, dwEncoding,
+                                         pSrcStr, pcSrcSize, pDstStr, pcDstSize);
 }
 
 static HRESULT WINAPI fnIMultiLanguage_ConvertStringReset(
@@ -1175,26 +1332,7 @@
     UINT uiCodePage,
     UINT* puiFamilyCodePage)
 {
-    UINT i, n;
-
-    ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage2, iface);
-    TRACE("%p %d %p\n", This, uiCodePage, puiFamilyCodePage);
-
-    if (!puiFamilyCodePage) return S_FALSE;
-
-    for (i = 0; i < sizeof(mlang_data)/sizeof(mlang_data[0]); i++)
-    {
-        for (n = 0; n < mlang_data[i].number_of_cp; n++)
-        {
-            if (mlang_data[i].mime_cp_info[n].cp == uiCodePage)
-            {
-                *puiFamilyCodePage = mlang_data[i].family_codepage;
-                return S_OK;
-            }
-        }
-    }
-
-    return S_FALSE;
+    return GetFamilyCodePage(uiCodePage, puiFamilyCodePage);
 }
 
 static HRESULT WINAPI fnIMultiLanguage2_EnumCodePages(
@@ -1224,21 +1362,7 @@
     DWORD dwSrcEncoding,
     DWORD dwDstEncoding)
 {
-    UINT src_family, dst_family;
-
-    ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage2, iface);
-    TRACE("%p %ld %ld\n", This, dwSrcEncoding, dwDstEncoding);
-
-    if (fnIMultiLanguage2_GetFamilyCodePage(iface, dwSrcEncoding, &src_family) != S_OK ||
-        fnIMultiLanguage2_GetFamilyCodePage(iface, dwDstEncoding, &dst_family) != S_OK)
-        return S_FALSE;
-
-    if (src_family == dst_family) return S_OK;
-
-    /* we can convert any codepage to/from unicode */
-    if (src_family == CP_UNICODE || dst_family == CP_UNICODE) return S_OK;
-
-    return S_FALSE;
+    return IsConvertINetStringAvailable(dwSrcEncoding, dwDstEncoding);
 }
 
 static HRESULT WINAPI fnIMultiLanguage2_ConvertString(
@@ -1251,8 +1375,8 @@
     BYTE* pDstStr,
     UINT* pcDstSize)
 {
-    FIXME("\n");
-    return E_NOTIMPL;
+    return ConvertINetString(pdwMode, dwSrcEncoding, dwDstEncoding,
+                             pSrcStr, pcSrcSize, pDstStr, pcDstSize);
 }
 
 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringToUnicode(
@@ -1264,46 +1388,8 @@
     WCHAR* pDstStr,
     UINT* pcDstSize)
 {
-    INT src_len = -1;
-
-    ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage2, iface);
-    TRACE("%p %p %ld %s %p %p %p\n", This, pdwMode, dwEncoding,
-          debugstr_a(pSrcStr), pcSrcSize, pDstStr, pcDstSize);
-
-    if (!pcDstSize)
-        return E_FAIL;
-
-    if (!pcSrcSize)
-        pcSrcSize = &src_len;
-
-    if (!*pcSrcSize)
-    {
-        *pcDstSize = 0;
-        return S_OK;
-    }
-
-    switch (dwEncoding)
-    {
-    case CP_UNICODE:
-        if (*pcSrcSize == -1)
-            *pcSrcSize = lstrlenW((LPCWSTR)pSrcStr);
-        *pcDstSize = min(*pcSrcSize, *pcDstSize);
-        *pcSrcSize *= sizeof(WCHAR);
-        memmove(pDstStr, pSrcStr, *pcDstSize * sizeof(WCHAR));
-        break;
-
-    default:
-        if (*pcSrcSize == -1)
-            *pcSrcSize = lstrlenA(pSrcStr);
-
-        *pcDstSize = MultiByteToWideChar(dwEncoding, 0, pSrcStr, *pcSrcSize, pDstStr, *pcDstSize);
-        break;
-    }
-    
-    if (!*pcDstSize)
-        return E_FAIL;
-
-    return S_OK;
+    return ConvertINetMultiByteToUnicode(pdwMode, dwEncoding,
+                                         pSrcStr, pcSrcSize, pDstStr, pcDstSize);
 }
 
 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringFromUnicode(
@@ -1315,46 +1401,8 @@
     CHAR* pDstStr,
     UINT* pcDstSize)
 {
-    INT src_len = -1;
-
-    ICOM_THIS_MULTI(MLang_impl, vtbl_IMultiLanguage2, iface);
-    TRACE("%p %p %ld %s %p %p %p\n", This, pdwMode, dwEncoding,
-          debugstr_w(pSrcStr), pcSrcSize, pDstStr, pcDstSize);
-
-    if (!pcDstSize)
-        return E_FAIL;
-
-    if (!pcSrcSize)
-        pcSrcSize = &src_len;
-
-    if (!*pcSrcSize)
-    {
-        *pcDstSize = 0;
-        return S_OK;
-    }
-
-    switch (dwEncoding)
-    {
-    case CP_UNICODE:
-        if (*pcSrcSize == -1)
-            *pcSrcSize = lstrlenW(pSrcStr);
-        *pcDstSize = min(*pcSrcSize * sizeof(WCHAR), *pcDstSize);
-        memmove(pDstStr, pSrcStr, *pcDstSize);
-        break;
-
-    default:
-        if (*pcSrcSize == -1)
-            *pcSrcSize = lstrlenW(pSrcStr);
-
-        *pcDstSize = WideCharToMultiByte(dwEncoding, 0, pSrcStr, *pcSrcSize, pDstStr, *pcDstSize, NULL, NULL);
-        break;
-    }
-
-
-    if (!*pcDstSize)
-        return E_FAIL;
-
-    return S_OK;
+    return ConvertINetUnicodeToMultiByte(pdwMode, dwEncoding,
+                                         pSrcStr, pcSrcSize, pDstStr, pcDstSize);
 }
 
 static HRESULT WINAPI fnIMultiLanguage2_ConvertStringReset(
diff --git a/dlls/mlang/mlang.spec b/dlls/mlang/mlang.spec
index b5de11a..c5ecea6 100644
--- a/dlls/mlang/mlang.spec
+++ b/dlls/mlang/mlang.spec
@@ -1,13 +1,13 @@
-@ stub ConvertINetMultiByteToUnicode
+@ stdcall ConvertINetMultiByteToUnicode(ptr long ptr ptr ptr ptr)
 @ stub ConvertINetReset
-@ stub ConvertINetString
-@ stub ConvertINetUnicodeToMultiByte
+@ stdcall ConvertINetString(ptr long long ptr ptr ptr ptr)
+@ stdcall ConvertINetUnicodeToMultiByte(ptr long ptr ptr ptr ptr)
 @ stdcall DllCanUnloadNow() MLANG_DllCanUnloadNow
 @ stdcall DllGetClassObject(ptr ptr ptr) MLANG_DllGetClassObject
 @ stdcall DllRegisterServer() MLANG_DllRegisterServer
 @ stdcall DllUnregisterServer() MLANG_DllUnregisterServer
 @ stub GetGlobalFontLinkObject
-@ stub IsConvertINetStringAvailable
+@ stdcall IsConvertINetStringAvailable(long long)
 @ stub LcidToRfc1766A
 @ stub LcidToRfc1766W
 @ stub Rfc1766ToLcidA
diff --git a/include/mlang.h b/include/mlang.h
index 5e24cba..83ed665 100644
--- a/include/mlang.h
+++ b/include/mlang.h
@@ -2072,6 +2072,16 @@
 
 #endif  /* __IMultiLanguage2_INTERFACE_DEFINED__ */
 
+STDAPI LcidToRfc1766A(LCID, LPSTR, INT);
+STDAPI LcidToRfc1766W(LCID, LPWSTR, INT);
+#define LcidToRfc1766 WINELIB_NAME_AW(LcidToRfc1766)
+STDAPI Rfc1766ToLcidA(LCID *, LPCSTR);
+STDAPI Rfc1766ToLcidW(LCID *, LPCWSTR);
+#define Rfc1766ToLcid WINELIB_NAME_AW(Rfc1766ToLcid)
+STDAPI IsConvertINetStringAvailable(DWORD, DWORD);
+STDAPI ConvertINetString(LPDWORD, DWORD, DWORD, LPCSTR, LPINT, LPSTR, LPINT);
+STDAPI ConvertINetMultiByteToUnicode(LPDWORD, DWORD, LPCSTR, LPINT, LPWSTR, LPINT);
+STDAPI ConvertINetUnicodeToMultiByte(LPDWORD, DWORD, LPCWSTR, LPINT, LPSTR, LPINT);
 DEFINE_GUID(CLSID_CMultiLanguage, 0x275c23e2, 0x3747, 0x11d0, 0x9f,0xea,0x00,0xaa,0x00,0x3f,0x86,0x46);
 DEFINE_GUID(IID_IMLangCodePages, 0x359F3443,0xBD4A,0x11D0,0xB1,0x88,0x00,0xAA,0x00,0x38,0xC9,0x69);
 DEFINE_GUID(IID_IMLangFontLink, 0x359F3441,0xBD4A,0x11D0,0xB1,0x88,0x00,0xAA,0x00,0x38,0xC9,0x69);
diff --git a/include/mlang.idl b/include/mlang.idl
index dadc92b..a4f675f 100644
--- a/include/mlang.idl
+++ b/include/mlang.idl
@@ -463,6 +463,19 @@
         [in] DWORD dwfIODControl);
 };
 
+cpp_quote("STDAPI LcidToRfc1766A(LCID, LPSTR, INT);")
+cpp_quote("STDAPI LcidToRfc1766W(LCID, LPWSTR, INT);")
+cpp_quote("#define LcidToRfc1766 WINELIB_NAME_AW(LcidToRfc1766)")
+
+cpp_quote("STDAPI Rfc1766ToLcidA(LCID *, LPCSTR);")
+cpp_quote("STDAPI Rfc1766ToLcidW(LCID *, LPCWSTR);")
+cpp_quote("#define Rfc1766ToLcid WINELIB_NAME_AW(Rfc1766ToLcid)")
+
+cpp_quote("STDAPI IsConvertINetStringAvailable(DWORD, DWORD);")
+cpp_quote("STDAPI ConvertINetString(LPDWORD, DWORD, DWORD, LPCSTR, LPINT, LPSTR, LPINT);")
+cpp_quote("STDAPI ConvertINetMultiByteToUnicode(LPDWORD, DWORD, LPCSTR, LPINT, LPWSTR, LPINT);")
+cpp_quote("STDAPI ConvertINetUnicodeToMultiByte(LPDWORD, DWORD, LPCWSTR, LPINT, LPSTR, LPINT);")
+
 cpp_quote("DEFINE_GUID(CLSID_CMultiLanguage, 0x275c23e2, 0x3747, 0x11d0, 0x9f,0xea,0x00,0xaa,0x00,0x3f,0x86,0x46);")
 cpp_quote("DEFINE_GUID(IID_IMLangCodePages, 0x359F3443,0xBD4A,0x11D0,0xB1,0x88,0x00,0xAA,0x00,0x38,0xC9,0x69);")
 cpp_quote("DEFINE_GUID(IID_IMLangFontLink, 0x359F3441,0xBD4A,0x11D0,0xB1,0x88,0x00,0xAA,0x00,0x38,0xC9,0x69);")