Eusebiu

Hello.

I have a method with the parameter : params object[] pars. If call the method with : 1, "111", myObject, everything is OK. But if I call the method with : 1, "111", ref myObject, I get a compile error.

How can I get this to work

Thanks




Re: Visual C# Language ref keyword

Tom Meschter MSFT

You can't.

Consider what you're asking for. You're basically saying that when the called method changes some of the elements of the "pars" array, you want that change to be reflected in the variable passed in by the caller. This isn't supported, nor is it clear what the value would be.

Perhaps you could explain the larger problem you're trying to solve

-Tom Meschter

Software Dev, C# IDE






Re: Visual C# Language ref keyword

Eusebiu

I want to invoke a method from DLL dynamically that has some parameters like int ** pointer;

I am using the following code to load dynamic a DLL

Code Snippet

public object DynamicDllFunctionInvoke(string dllPath, string entryPoint, params object[] pars)

{

//Define return type of your dll function.

Type returnType = typeof(int);

//out or in parameters of your function.

Type [] parameterTypes = new Type[pars.Length];

for (int i = 0; i < pars.Length; i++)

{

parameterTypes[i] = pars[i].GetType();

}

object[] parameterValues = pars;

// Create a dynamic assembly and a dynamic module

AssemblyName asmName = new AssemblyName();

asmName.Name = "tempDll";

AssemblyBuilder dynamicAsm =

AppDomain.CurrentDomain.DefineDynamicAssembly(asmName,

AssemblyBuilderAccess.Run);

ModuleBuilder dynamicMod = dynamicAsm.DefineDynamicModule("tempModule");

// Dynamically construct a global PInvoke signature

// using the input information

MethodBuilder dynamicMethod = dynamicMod.DefinePInvokeMethod(

entryPoint, dllPath, MethodAttributes.Static | MethodAttributes.Public

| MethodAttributes.PinvokeImpl, CallingConventions.Standard,

returnType, parameterTypes, CallingConvention.Winapi, CharSet.Ansi);

// This global method is now complete

dynamicMod.CreateGlobalFunctions();

// Get a MethodInfo for the PInvoke method

MethodInfo mi = dynamicMod.GetMethod(EntryPoint);

// Invoke the static method and return whatever it returns

object retval = mi.Invoke(null, parameterValues);

// Filled verstr paramter.

return retval;

}

When I use DllImportAttribute to wrap the DLL, the method has a parameter like this : ref IntPtr pointer and the method is ran correctly. As you can see, the Invoke method from MethodBuilder has the second parameter an object[] .

I want to use the method of calling the DLL's method because I have a couple of versions of the DLL and I don`t want to replace the DLL for each version. I simply change the path to that DLL.

Hope you'll understand better now my problem...






Re: Visual C# Language ref keyword

nielsvanvliet

You do not need ref params (and can not). I think you have a boxing problem.

Let's take the example of a method:
int Alloc5Int(int** p); // Int32 AllocInt(ref IntPtr p);
This method allocates 5 int and returns the address (a int**) of the array (a int*) in p.

if your write the following code, it will not work:
IntPtr ppint = 0;
DynamicDll("foo.dll", "Alloc5Int", ppint); // ppint is boxed !
Console.WriteLine(ppint.ToString("x")); // displays 0!

The reason is that ppint is a valuetype. It will be boxed to an object (and copied by value),
so the result will be written in the box, not in ppint.

So you should box first:

IntPtr ppint = 0;
object ppintBoxed = ppint;
DynamicDll("foo.dll", "Alloc5Int", ppintBoxed);
ppint = (IntPtr) ppintBoxed; // copy back.
Console.WriteLine(ppint.ToString("x")); // displays an hexadecimal value.

In this case DynamicDll will work with the boxed object, and will also modify it (because of the 'ref IntPtr'
in the C# declaration of Alloc5int). But now, you have the box, and you can copy back the result to your variable.
(In the first case, the box is just garbage collected).


Note: I did not go into detail, because you seem good, but do not hesitate to ask more information.
Note2: IntPtr can be used for an 'IntPtrPtr'.




Re: Visual C# Language ref keyword

Eusebiu

Hello.. and thanks for the answers... I understand what is the problem, nielsvanvliet. Smile

Well... I have a bad news... it didn't work...

I get a TargetInvocationException (at this line : object retval = mi.Invoke(null, parameterValues)Wink

with the Message : "Exception has been thrown by the target of an invocation." ,InnerException : "Attempted to read or write protected memory. This is often an indication that other memory is corrupt." and StackTrace :

" at System.RuntimeMethodHandle._InvokeMethodFast(Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)\r\n

at System.RuntimeMethodHandle.InvokeMethodFast(Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)\r\n

at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)\r\n

at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)\r\n

at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)\r\n

at CommonClasses.LoadDymanicDLL.DynamicDllFunctionInvoke(String dllPath, String entryPoint, Object[] parameters) in D:\\CommonClasses\\LoadDymanicDLL.cs:line 54\r\n

If I wrap the dll with DllImportAttribute and remove the ref keyword before the parameter, I get an Exception with the message "Attempted to read or write protected memory. This is often an indication that other memory is corrupt.".

So I think these exceptions are the same.

//test - C#

int i = 0;

object o = i;

CommonClasses.LoadDymanicDLL.DynamicDllFunctionInvoke(@"C:\testDLL.dll", "test", o);

i = (int)o;

//test - CPP

extern "C" TESTDLL_API BOOL test(int * a)

{

*a = 20;

return TRUE;

}

//test - header file

#ifdef TESTDLL_EXPORTS

#define TESTDLL_API __declspec(dllexport)

#else

#define TESTDLL_API __declspec(dllimport)

#endif

extern "C" TESTDLL_API BOOL test(int * a);






Re: Visual C# Language ref keyword

Eusebiu

Hello again..

I've searched for using DllImportAttribute using a dymamic path and I've found this answer .

The complete code is :

Code Snippet

static class DllImportDynamic

{

public const int LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008;

/// <summary>

/// To load the dll - dllFilePath dosen't have to be const - so I can read path from registry

/// </summary>

/// <param name="dllFilePath">file path with file name</param>

/// <param name="hFile">use IntPtr.Zero</param>

/// <param name="dwFlags">What will happend during loading dll

/// <para>LOAD_LIBRARY_AS_DATAFILE</para>

/// <para>DONT_RESOLVE_DLL_REFERENCES</para>

/// <para>LOAD_WITH_ALTERED_SEARCH_PATH</para>

/// <para>LOAD_IGNORE_CODE_AUTHZ_LEVEL</para>

/// </param>

/// <returns>Pointer to loaded Dll</returns>

[DllImport("kernel32.dll", SetLastError = true)]

private static extern IntPtr LoadLibraryEx(string dllFilePath, IntPtr hFile, uint dwFlags);

/// <summary>

/// To unload library

/// </summary>

/// <param name="dllPointer">Pointer to Dll witch was returned from LoadLibraryEx</param>

/// <returns>If unloaded library was correct then true, else false</returns>

[DllImport("kernel32.dll", SetLastError = true)]

public extern static bool FreeLibrary(IntPtr dllPointer);

/// <summary>

/// To get function pointer from loaded dll

/// </summary>

/// <param name="dllPointer">Pointer to Dll witch was returned from LoadLibraryEx</param>

/// <param name="functionName">Function name with you want to call</param>

/// <returns>Pointer to function</returns>

[DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)]

public extern static IntPtr GetProcAddress(IntPtr dllPointer, string functionName);

/// <summary>

/// This will to load concret dll file

/// </summary>

/// <param name="dllFilePath">Dll file path</param>

/// <returns>Pointer to loaded dll</returns>

/// <exception cref="ApplicationException">

/// when loading dll will failure

/// </exception>

public static IntPtr LoadWin32Library(string dllFilePath)

{

IntPtr moduleHandle = LoadLibraryEx(dllFilePath, IntPtr.Zero, LOAD_WITH_ALTERED_SEARCH_PATH);

if (moduleHandle == IntPtr.Zero)

{

// I'm gettin last dll error

int errorCode = Marshal.GetLastWin32Error();

throw new ApplicationException(

string.Format("There was an error during dll loading : {0}, error - {1}", dllFilePath, errorCode)

);

}

return moduleHandle;

}

}

public class CallDlls

{

IntPtr myDll ;

void InitializeMyDll(string pathToDll)

{

try

{

myDll = DllImportDynamic.LoadWin32Library(pathToDll);

// here you can add, dll version check

}

catch (ApplicationException exc)

{

MessageBox.Show(exc.Message, "There was an error during dll loading",MessageBoxButtons.OK,MessageBoxIcon.Error);

throw exc;

}

}

// The last thing is to create delegate to calling function

// delegate must to have the same parameters then calling function (from dll)

//public delegate RETURN_TYPE RunAlgorithmDelegate(int a, string b);

delegate int TestDelegate(ref int a);

int Test(string pathToDll, ref int a)

{

if (myDll == IntPtr.Zero)

InitializeMyDll(pathToDll);

IntPtr pProc = DllImportDynamic.GetProcAddress(myDll , "test");

TestDelegate cpv = (TestDelegate)Marshal.GetDelegateForFunctionPointer(pProc, typeof(TestDelegate));

// Now i'm calling delegate, with is calling function from dll file

return cpv(ref a);

}

public int CallTest(string pathToDll, ref int a)

{

int ret;

ret = this.Test(pathToDll, ref a);

return ret;

}

public int FreeLibrary()

{

DllImportDynamic
.FreeLibrary(myDll);

}

}

// Now if you want to call dll function from program code use this

int a = 1;

CallDlls othercall = new CallDlls();

othercall.CallTest(ref a);

// after this, a will be 20

// dont' forget to FreeLibrary

othercall.FreeLibrary();