How to set PR_HTML where string contains Unicode characters

54 views Asked by At

In a VSTO C# Outlook addin I am copying the OOM HTMLBody text from one message and then adding it to a new message via PR_HTML with either IMAPIProp::SetProps or IMAPIProp::OpenProperty. I need to take the OOM HTMLBody.

The issue I am having is that german characters such as äüß are not being set properly on the resulting message.

First I am converting the HTML string to a Byte array with byte[] bytes= System.Text.UTF8Encoding.UTF8.GetBytes(value);

Then for example i use OpenProperty

OpenProperty((uint)PropTags.PR_HTML, Storage.IID_Stream, (uint)(STGM.CREATE | STGM.WRITE), OpenPropertyMode.MODIFY | OpenPropertyMode.CREATE, out IntPtr pObject);
if (pObject != null && pObject != IntPtr.Zero)
{
    Ole.IStream htmlStream = Marshal.GetObjectForIUnknown(pObject) as Ole.IStream;
    Storage.Write(htmlStream, bytes);
    htmlStream.Commit((int)STGC.DEFAULT);
    Marshal.ReleaseComObject(htmlStream);
}

My IMAPIProp::OpenProperty looks like this:

OpenProperty(uint ulPropTag, ref Guid lpiid, uint ulInterfaceOptions, uint ulFlags, out IntPtr lppUnk);

Alternative if possible I could try (normally try this first) to set the property with SetProps. Here I think is the bits that are critical.

[StructLayout(LayoutKind.Sequential)]
internal struct pSPropValue
{
    public UInt32 ulPropTag;
    public UInt32 dwAlignPad;
    public _PV Value;
}

[StructLayout(LayoutKind.Explicit)]
internal struct _PV
{
    //there are others just showing the one used.
    [FieldOffset(0)]
    public SBinary bin;
    
}

[StructLayout(LayoutKind.Sequential)]
internal struct SBinary
{
    public uint cb;
    public IntPtr lpb;
}


public static SBinary SBinaryCreate(byte[] data)
{
    SBinary b;
    b.cb = (uint)data.Length;
    b.lpb = Marshal.AllocHGlobal((int)b.cb);
    for (int i = 0; i < b.cb; i++)
        Marshal.WriteByte(b.lpb, i, data[i]);
    return b;
}

pSPropValue val = new pSPropValue();
//add the property tag
//call SBinaryCreate to create the _PV
val.Value.bin = SBinary.SBinaryCreate(prop.AsBinary);

I believe this is all the critical encoding parts. An array of pSPropValue is marshalled to a IntPtr and then SetProps is called.

The resulting email body does not show the special characters.

1

There are 1 answers

6
Dmitry Streblechenko On

Make sure you correctly set PR_INTERNET_CHARSET property. But most importantly, do not store any non-ASCII characters in HTML. They must be properly HTML-encoded.