Question

I have some C# code calling into an unmanaged C++ DLL. The method I am calling is intended to accept a string as a ref. To handle this I pass in a StringBuilder, otherwise there is a StackOverflowException.

This is working fine, but on some calls the string that comes back from the unmanaged code is a jumbled string like this: øŸE˜.,Ê. I know this must have something to do with encoding, but I've tried several things, listed below, and nothing works. This is not an issue in VB.Net code that someone else has written to do something similar.

Here's what I've tried: 1. I'm using this: [DllImport("dmphnx32.dll")], but have tried all Charset options without success.

  1. Tried to use Encoding.Default.GetBytes, Encoding.ASCII, Encoding.Unicode, and the rest without success.

I don't have any experience with C++ so I can really use the help.

Here's the DLLIMport method:

[DllImport("dmphnx32.dll")]
        public static extern int PhxQueryDataAttributes(int handle,
                                        StringBuilder lTableName,
                                        StringBuilder lColumnName,
                                        ref short lIteration,
                                        ref short type,
                                        ref short maxLen,
                                        ref short endorsement,
                                        StringBuilder endorsementId);

Here's the C++ code:

short DMEXP PhxQueryDataAttributes(HWND handle,
                                   char *lTableName,
                                   char *lColumnName,
                                   short *lIteration,
                                   short *Type,
                                   short *MaxLen,
                                   short *Endorsement,
                                   char  *EndorsementID)
{

    handle = PhxInfo.HiddenHwnd;
    strcpy(lTableName, PhxInfo.TableName);
    strcpy(lColumnName, PhxInfo.ColumnName);


    *Type = PhxInfo.PhnxDataType;
    // max len
    *MaxLen = PhxInfo.MaxDataLen;
    *Endorsement = PhxInfo.Endorsement;
    strcpy(EndorsementID, PhxInfo.EndorsementID);
    // determine which table we need the iteration of
    *lIteration = PhxIterationArray[PhxInfo.sEffectiveTableID];

    return SUCCESS;
}

Here's the C# code that calls into the unmanaged code:

public int PhxQueryDataAttributes(int handle, ref string lTableName, ref string lColumnName, 
            ref short lIteration, ref short type, ref short maxLen, ref short endorsement, 
            ref string endorsementId)
        {
            var sbTableName = new StringBuilder();
            var sbColName = new StringBuilder();
            var sbEndId = new StringBuilder();

            var ret = RatingProxy.PhxQueryDataAttributes(handle, sbTableName, sbColName,
            ref lIteration, ref type, ref maxLen, ref endorsement, sbEndId);


            lTableName = sbTableName.ToString();
            lColumnName = sbColName.ToString();
            endorsementId = sbEndId.ToString();
return ret;
}

Thanks, Corey

Was it helpful?

Solution 3

After I tried the first 2 answers and learned that they weren't helping, I knew that something else must be suspect. I found a small bug somewhere else in my app where I was actually missing an initialization param on the unmanaged code. This was causing my strangely encoded string.

Thanks for the help, Corey

OTHER TIPS

Ok, I see your problem. You need to allocate a capacity for the StringBuilder, you cant just use the default.

Instead of the StringBuilder, you might try using an IntPtr and the Marshal class.

SO, it would look like this:

[DllImport("dmphnx32.dll")]
    public static extern int PhxQueryDataAttributes(int handle,
                                    IntPtr lTableName,
                                    IntPtr  lColumnName,
                                    ref short lIteration,
                                    ref short type,
                                    ref short maxLen,
                                    ref short endorsement,
                                    IntPtr endorsementId);

Calling code would be:

public int PhxQueryDataAttributes(int handle, ref string lTableName, ref string lColumnName, 
        ref short lIteration, ref short type, ref short maxLen, ref short endorsement, 
        ref string endorsementId)
    {
        var sbTableName = Marshal.AllocHGlobal(1024);//Change these to the max length possible for each string.
        var sbColName = Marshal.AllocHGlobal(1024);
        var sbEndId = = Marshal.AllocHGlobal(1024);

        var ret = RatingProxy.PhxQueryDataAttributes(handle, sbTableName, sbColName,
        ref lIteration, ref type, ref maxLen, ref endorsement, sbEndId);


        lTableName = Marshal.PtrToStringAnsi(sbTableName);
        lColumnName = Marshal.PtrToStringAnsi(sbColName);
        endorsementId = Marshal.PtrToStringAnsi(sbEndId);
        return ret;
}

This way you can specify the correct encoding (which you cannot do with a string builder, which assumes it is a UTF type encoding). Experiment a little, and see which of the Marshal.PtrToString... ones work, though ANSI should work, since that is what most C++ libraries use.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top