Здравствуйте, externus, Вы писали:
E>А что касается оптимального соотношения цена/качество, то у меня есть решение, наилучшим образом удовлетворяющее этому: я просто не буду показывать в .NET эти необязательные параметры функции, и пусть писатели пользуются System.String с его могучим Format
. Проблема только в том, что это подойдет для данного конкретного проекта, а он не единственный.
С другой стороны, зачем вообще давать прямой доступ к данным участвующим в unmanaged взаимодействии? Например:
[StructLayout(LayoutKind.Sequential)]
public struct KERNEL_CONTROL_BLOCK
{
[MarshalAs(UnmanagedType.I4)]
public int cbSize;
[MarshalAs(UnmanagedType.I4)]
public int dwVersion;
// ...тыр-пыр...
private IntPtr _kernelLog;
public void KernelLog(string service, int handle, int level, string msg, params object [] pars)
{
// выбрать тут подходящий тип делегата, получить его экземпляр и сделать вызов
}
};
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Всем привет!
Перерыл кучу материалов — без толку. Проблема в следующем:
есть примено такая структура на С:
struct KERNEL_CONTROL_BLOCK
{
long cbSize;
long dwVersion;
// ...тыр-пыр...
KernelLog_t KernelLog;
};
где KernelLog_t — это некий коллбэк с переменным числом аргументов:
typedef KERNEL_RETVAL (CALLBACK *KernelLog_t) (
const char *service,
KERNEL_HANDLE handle,
int level,
const char *msg, ...);
Структура эта передается в managed C# DLL из С++ программы через IntPtr, где чудненько кастится к примерно такой C# структуре:
[StructLayout(LayoutKind.Sequential)]
public struct KERNEL_CONTROL_BLOCK
{
[MarshalAs(UnmanagedType.I4)]
public int cbSize;
[MarshalAs(UnmanagedType.I4)]
public int dwVersion;
// ...тыр-пыр...
[MarshalAs(UnmanagedType.FunctionPtr)]
public KLog_t KernelLog;
};
Проблема, собственно, в том, что я не могу понять, как правильно объявить делегата для этой функции, чтобы ей как надо передавались необязательные аргументы. Я пытался написать что-то вроде:
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
public delegate int KLog_t(
string service,
int handle,
int level,
string msg,
params object [] pars);
и вызывать это дело примерно так:
public int ServiceProcess (System.IntPtr p)
{
KERNEL_CONTROL_BLOCK s = (KERNEL_CONTROL_BLOCK)
Marshal.PtrToStructure(p, typeof(KERNEL_CONTROL_BLOCK));
object [] pars = new object [] { 25 };
return s.KernelLog(".NET Service", s.hKernelContext, 0, "Hi from here with arg %d!", pars);
}
Пришедший указатель на функцию прекрасно превращается в делегата, и все замечательно работает, кроме того, что в результате в логе вместо 25 я получаю мусорное число.
В принципе, я примерно понимаю, что таким образом оно и не должно работать, хотя бы потому, что CLR понятия не имеет, как надо правильно отмаршалить эти аргументы. Но какой-то метод наверняка должен быть. Недокументированный __arglist в этом контексте не работает, а больше мне ничего не придумать.
Вдруг кто с чем-то подобным сталкивался и может подсказать? Спасибо заранее.
Здравствуйте, externus, Вы писали:
E>Перерыл кучу материалов — без толку. Проблема в следующем:
Посмотрите не декларацию
sprintf
E>В принципе, я примерно понимаю, что таким образом оно и не должно работать, хотя бы потому, что CLR понятия не имеет, как надо правильно отмаршалить эти аргументы. Но какой-то метод наверняка должен быть. Недокументированный __arglist в этом контексте не работает, а больше мне ничего не придумать.
Если стоит задача вызова только unmanaged кода то, можно определить несколько делегатов c разным числом параметров и дальше выполнять маршаллинг руками в зависимости от того, метод со сколькими параметрами нужно вызвать.
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Здравствуйте, TK, Вы писали:
TK>Посмотрите не декларацию sprintf
Смотрел. Половину сайта перерыл.
__arglist не работает для делегатов. Кроме того, не очень хочется использовать недокументированные феньки.
TK>Если стоит задача вызова только unmanaged кода то, можно определить несколько делегатов c разным числом параметров и дальше выполнять маршаллинг руками в зависимости от того, метод со сколькими параметрами нужно вызвать.
Мне такой вариант показался некрасивым. Основная задача стоит сделать написание managed модуля как можно проще. Тогда ИМХО лучше попробовать слепить отдельную mixed прослойку, где принимать массив аргументов, с ним разбираться, пытаться из него сделать va_list и слать дальше.
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Здравствуйте, TK, Вы писали:
TK>Не красивым в использовании или в реализации? В любом случае, красота понятие относительное — одно дело писать код "for fun" а другое дело получить оптимальное соотношение цена/качество
Свой код "for fun" я уже отписал лет 15 назад — сейчас я лучше посплю

.
Некрасиво прежде всего в реализации. Кроме того, managed часть проекта мне надо бы оставить как можно более прозрачной и тупой как валенок. В интерфейсе могут быть в дальнейшем изменения и дополнения, и нельзя, чтобы это сильно касалось .NETовской части. А изголяться я могу только в native модулях.
А что касается оптимального соотношения цена/качество, то у меня есть решение, наилучшим образом удовлетворяющее этому: я просто не буду показывать в .NET эти необязательные параметры функции, и пусть писатели пользуются System.String с его могучим Format

. Проблема только в том, что это подойдет для данного конкретного проекта, а он не единственный.