Thanks for the tip, Ian.
I didn't get it to work, though.
I was doing at least one wrong thing:
I was getting the lenght of the string returned as a string pointer by TAGS_Read using lstrlenW, but UTF-8 strings aren't wide characters. According to Microsoft a UTF-8 character can occupy from 1 to 3 bytes. Also I don't know if the null terminator should be a wide character. Microsoft says something like "don't asume anything".
So, using your suggestion of passing -1 as the string lenght, I didn't bother to find the actual lenght in advance, but let MultiByteToWideChar guess it.
Dim TagPtr As Long
Dim Buff As String
Dim BuffLen As Long
Const CP_UTF8 As Long = 65001
TAGS_SetUTF8 BASSTRUE
TagPtr = TAGS_Read(hTag, TagId)
If TagPtr <> 0 Then
BuffLen = MultiByteToWideChar(CP_UTF8, 0, TagPtr, -1, 0, 0)
If BuffLen = 0 Then Exit Sub
Buff = String$(BuffLen, vbNullChar)
BuffLen = MultiByteToWideChar(CP_UTF8, 0, TagPtr, -1, StrPtr(Buff), BuffLen)
If BuffLen = 0 Then Exit Sub
Buff = Mid(Buff, 1, BuffLen - 1) 'trim the null terminator
If Trim(Buff) <> "" Then
fgPl.TextMatrix(RowX, ColX) = Buff
End If
End If
This worked OK for tags containing only Ansi characters, like %YEAR and %TRCK, but those containing non-Ansi characters still show as question marks instead of squares. This is the same behaviour I got with my previous code.
I tried to use the code linked by you but stumbled on the ptroblem of converting the string pointer returned by TAGS_Read into a Byte array. I don't know how to do it.
The usual way to do it would be to Dim the byte array and copy the bytes from the internal buffer of tags18 into it. Something like this:
ReDim abytBuf(lLen)
'Copy the memory contents into a they byte buffer
Call CopyMemory(abytBuf(0), ByVal lPtr, lLen)
But, how can I get the lenght lLen? lstrlenW expects wide characters (and wide null terminator?) and lstrlenA expects a single byte 0 as terminator. None of them would work (I tried both!). I'm lost.
I thought I could use an arbitrary insanely large iLen and trust that MultiByteToWideChar will find the null terminator and discard the rest of the array, but it doesn't seem fool-proof (unless tags are restricted to a known maximum lenght?).
I can't declare TAGS_Read as returning a byte array like TAGS_Read(hTag as Long, TagId as string)() as Byte because a VB6 byte array is a safarray (a structure), not a string.
So I'm stuck.
I discarded other trivial problems like the tags including invalid UTF-8 points and the MSHFlexGrid not being able to display UTF-16 characters with appropiate tests. Everything works as a charm except the non-Ansi tags.
I can use more help.
If you have some working C code that I can pack into a dll and call from VB6 code I'd like to give it a try. I've coded a few dozens of stdcall functions into dlls but this specific problem is beyond me.
Thanks in advance!