У меня есть 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;
ничего не происходит.
С# использует 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;
}
}