Изменение параметров в c / c ++ dll

0

У меня есть DLL, написанная на C. У меня есть функция в этой DLL, например:

unsigned char DLL_EXPORT getTRK(char *XML, unsigned long *Len)
{
    MessageBox(NULL, XML, "Dll message", MB_OK);
    char s[] = "Some string";
    XML = s;
    return rand()%2;
}

Мне нужно изменить значение переменной XML в dll и привести это значение к моей программе С#. У меня есть следующий код на С#:

[DllImport("Some_DLL.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern byte getTRK(string XML, uint Len);
...
string xml = "123";
uint len = 0;
tbXml.Clear();
if (getTRK(xml, len) == 0)
{
   tbXml.AppendText(xml);
}
else
{
   tbXml.AppendText("Some error!");
}

Я пробовал разные способы сделать это, но ничего не работает по мере необходимости. Я хочу получить свое значение С# prog для переменной xml = "Некоторая строка". Как я могу это получить? Если я использую ref или выхожу так:

[DllImport("Some_DLL.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern byte getTRK(ref string XML, ref uint Len);
...
string xml = "123";
uint len = 0;
tbXml.Clear();
if (getTRK(ref xml, ref len) == 0)
{
   tbXml.AppendText(xml);
}
else
{
   tbXml.AppendText("Some error!");
}

dll получает некоторые значения мусора, а не "123". если я делаю так:

*XML = *s;

ничего не происходит.

  • 0
    Вы смотрели на stackoverflow.com/questions/10856127/… ?
  • 2
    Это должно начинаться с правильного кода C в первую очередь. То, что вы опубликовали, в корне неверно, вместо назначения нужно использовать strcpy_s (). Сделайте так, чтобы он работал в программе на C, прежде чем пытаться взаимодействовать с ним.
Теги:
dll

1 ответ

2

С# использует 2-байтовые символьные строки и сопоставляет их соответственно. char * используется для хранения 1-байтовых символьных строк. Вы должны указать кодировку в свой атрибут DllImport и строки usec wchar_t *.

Если вам нужно сохранить свои строки в char *, вы можете написать собственный маршаллер, который называется чем-то вроде этого

void ErrorWriter([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))]string errorMessage, string taskId, ProcessType processType);

и реализованы так

internal class Utf8Marshaler : ICustomMarshaler
{
    private static Utf8Marshaler _staticInstance;

    public IntPtr MarshalManagedToNative(object managedObj)
    {
        if (managedObj == null)
            return IntPtr.Zero;
        if (!(managedObj is string))
            throw new MarshalDirectiveException(
                "UTF8Marshaler must be used on a string.");

        // not null terminated
        byte[] strbuf = Encoding.UTF8.GetBytes((string) managedObj);
        IntPtr buffer = Marshal.AllocHGlobal(strbuf.Length+1);
        Marshal.Copy(strbuf, 0, buffer, strbuf.Length);

        // write the terminating null
        Marshal.WriteByte(buffer + strbuf.Length, 0);
        return buffer;
    }

    public object MarshalNativeToManaged(IntPtr pNativeData)
    {
        if (pNativeData == IntPtr.Zero)
            return string.Empty;
        int length = 1;

        IntPtr offsetPtr = IntPtr.Add(pNativeData, 1);
        while (Marshal.ReadByte(offsetPtr) != 0)
        {
            offsetPtr = IntPtr.Add(offsetPtr, 1);
            length++;
        }
        byte[] strbuf = new byte[length];

        Marshal.Copy(pNativeData, strbuf, 0, length);
        string data = Encoding.UTF8.GetString(strbuf);
        return data;
    }

    public void CleanUpNativeData(IntPtr pNativeData)
    {
        Marshal.FreeHGlobal(pNativeData);
    }

    public void CleanUpManagedData(object managedObj)
    {
    }

    public int GetNativeDataSize()
    {
        return -1;
    }

    public static ICustomMarshaler GetInstance(string cookie)
    {
        if (_staticInstance == null)
        {
            return _staticInstance = new Utf8Marshaler();
        }
        return _staticInstance;
    }
}
  • 0
    Не забудьте протестировать кириллические строки.
  • 0
    Большое спасибо за помощь, но я нашел другое решение. Я использую StringBuilder вместо строкового типа. А в dll используется strcpy strcpy (XML, "Some String"). И все работает правильно. Даже кириллические строки.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню