I would like to call C# function with variable number of parameters:
void f1(object arg1, params object[] argsRest);
from unmanaged, C function with variable parameters that wraps f1.
How can this be achived?
From C you need to pass the length of your array as a parameter to C# so that you can then marshal the pointer to the array into a c# array. I don't think you can directly use that function signature from C.
 
    
    To expose your managed function you will need to write a mixed mode DLL that acts as a bridge (You should read this article on MSDN as background.)
Your c++-cli bridge DLL will contain code similar to the following ...
#include <cstdarg>
extern "C" {
    __declspec(dllexport) void f1wrapper(void *arg1, int nargs, ...)
    {
        array<Object^>^ managedArgs = gcnew array<Object^>(nargs);
        va_list args;
        va_start(args, nargs);
        for (int _i = 0; _i < nargs; ++_i)
        {
            managedArgs[_i] = ???; // <- you need to translate args
        }
        va_end(args);
        // Call your function
        Object^ managedArg1 = ???; // <- translate arg1
        f1(managedArg1, managedArgs);
    }
}
You then link against the mixed mode DLL and call f1wrapper(...) from your C code. Not complete, but should provide enough foundation for you to experiment.
 
    
    params object[] is basically just an array, so treat it as array.
 
    
    Thanks, I have achieved this.
In C function:
void UnmanagedClass::foo(int i, char *message, ...);
during excuting, variable 'i' and message will be put on stack, and then the address of additional parameters array.
I there is mixed unmanaged/managed code in one CLR project, function with variable number of parameters will be compiled as unmanaged function (here) . This is why i made a bridge class with member function:
void ManagedClass::foo(int i, char * message, unsigned int *params);
and implemented:
void UnmanagedClass::foo(int i, char *message, ...) {
    unsigned int *p = (unsigned int*) &message;
    p++;
    ManagedClass::foo(i, message, (unsigned int) p);
}
I didn't need number of parameters, since the 'message' was carrying info about the number and the type of parametes in a printf fashion way.
This way, in 'ManagedClass::foo()' function I parsed the array 'p', created instances of corresponding managed types, arranged them in objects array and passed them to a managed method with invariant number of arguments.
