Hi All,
I facing a problem which i have described briefly in the following paragraph.
Let me tell you a scenario where in the user has to choose any kind of dll he wants, rather be .Net Dll or Native Dll for a connection to his server.
In that he knows the function to Invoke.
I need to write a common user interface to invoke any kind of dll, based on the choice of the user. Is that possible ?. If so help me regarding the stratergy that i have to use or any examples of such accomplishment.
FYI
I know one software which is doing to most of the Dll's.
Thanks in Advance
Loading
kandyPosted Aug 30, 2007, 2:56 AM
Hi To All,
I tried working with codeDom and I was able to invoke the Dlls quite good.My user interface gets information about the required function present in the Dll from its header file or any text file if available ,otherwise i allow the user to specify the definition of the funciton. I am able to invoke functions which does not involve any complex datastructures which I feel enough for my requirements.
Thanks to Alan,Yogesh,Sam for your valuable comments without which my work would have been more tough. I have been to this field a month ago ,so still a lot to learn and will disturb you people a lot in the upcoming days :) .
Thanks and Regards
kandy
kandyPosted Aug 28, 2007, 1:17 AM
Hi to All,
Still I am working on it by using codeDom. I need few more days.So, will reply soon.
Regards
Kandy
AlanPosted Aug 26, 2007, 5:43 AM
In my first post I was thinking that Kandy would have to use Reflection.Emit to emit the P/Invoke signatures but, yes, you could use CodeDom instead.
However, you would still have the problem of determining the P/Invoke signatures in the first place and this can be quite difficult when you need to mimic unmanaged structs that can contain embedded arrays, strings, other structs etc. and/or which may require custom marshalling.
It seems to me that there is no realistic alternative here but to ask the user to specify ALL the information needed to call the function via P/Invoke as I don't see how you can possibly work all this out programatically.
SamPosted Aug 25, 2007, 3:49 PM
Hi,
Just a thought.
If you can find out infomation about the parameters and return type of the un-managed dll functions (if possible) you could use CodeDom to dynamically create the DllImport methods with the correct signitures.
Sam.
AlanPosted Aug 25, 2007, 6:21 AM
I was thinking some more about this today and, even if it works at all, I don't think that __arglist is really going to help here because there doesn't appear to be a way to load the arguments into it at runtime. They have to be hardcoded at compile time.
So I'm coming back to my original 'gut feeling' on this, that what you're trying to do is virtually impossible. It's certainly extremely dangerous (albeit on the user's own head) as calling dll functions, willy-nilly, could cause some serious damage.
AlanPosted Aug 24, 2007, 3:04 PM
Hi Kandy,
Yes, you're right on the first point because that's the only way that you can push the arguments and a slot for the return value onto the stack in the first place.
The only way I can think of to circumvent this is to define the InvokeFunc() from the C# side to accept an __arglist parameter, which is what is normally done when an unmanaged function can accept a variable number of arguments of differing types (params doesn't work in such cases).
A possible fly in the ointment here is that __arglist generally requires the cdecl calling convention (where the caller cleans the stack) which isn't feasible here but you could try it with stdcall, which is the default for P/Invoke.
If you're not familiar with the undocumented __arglist keyword, here's a quick example which calls the C library function printf():
using System;
using System.Runtime.InteropServices;
class Test
{
[DllImport("msvcrt40.dll", CharSet = CharSet.Ansi,
CallingConvention = CallingConvention.Cdecl)]
static extern int printf(string format, __arglist);
static void Main()
{
printf("Characters: %c, %c\n",__arglist('a', 65));
printf("Integers: %d, %d\n", __arglist(65, 123));
printf("Doubles: %lf, %lf\n", __arglist(123.45, 1.0/3.0));
printf("Strings: %s, %s\n", __arglist("abc", "goodbye"));
}
}
However, this still leaves the problem of the return value and I think all you can do here is to stick with int which (as a 4 byte integer) is often used as the return value of Win32 functions.
Unless I'm missing something, I couldn't see any way of specifying the return value or arguments at all for the second approach (in the comments) so it would only be suitable for functions which required no arguments and where an int is returned.
kandyPosted Aug 24, 2007, 7:42 AM
Thanks a lot Alan. It is working fine But i still had some issues to get cleared.They are described in the following,
->According to the way he has programmed using x86 assembly it is possible to load any dll or library, but when it comes to invoking the function the same prototype has to be declared in the definition of "invokeFunc" method.. He has reduced the problem to an extent that any function in any dll can be invoked provided their signature and their return type has to get matched with the one given in "invokeFunc" method definition. am I right?
-> Say if i use the method "CallWindowProc" in user32.dll, how can i specify the arguments for the function that i am going to call in it ?.
Thanks and Regards
Kandy
AlanPosted Aug 23, 2007, 4:50 PM
I imagine that it's this bit that you don't understand, Kandy:
Invoke.obj: Invoke.asm
ml $(MLFLAGS) $**
Invoke.dll: Invoke.obj
link $** -DLL -entry:DllMain /machine:i386 /subsystem:windows /out:Invoke.dll /export:InvokeFunc
This is a 'makefile' script for use with the Microsoft utility nmake.exe which comes with VS.
The first line is what's called a 'dependency line'.
The 'target' is invoke.obj and the 'dependent' is invoke.asm.
The next line is a 'command'.
ml.exe is the Microsoft Macro Assembler (commonly known as MASM). It's followed by two macros:
$(MLFLAGS) specifies various default assembler settings for MASM
$** denotes all dependents of the current target (i.e. invoke.asm in this case)
So what this means so far is assemble the file invoke.asm into the default invoke.obj object file.
The next line is again a dependency line with invoke.dll as the target and invoke.obj as the dependent.
The final line links the dependent (i.e. invoke.obj) with the appropriate libraries to produce the dynamic link library, invoke.dll, for x86 Windows, with an entrypoint of DllMain and an export table consisting of the function InvokeFunc.
If you're not happy using nmake, then all of this can be done from the command line by invoking MASM and LINK directly but, I'd have thought you'd be OK if you follow the download instructions.
kandyPosted Aug 23, 2007, 12:55 AM
Alan,
I understood the way it is done by using x86 assembly. But i did not understand the way the invoke.dll is created from his explanation in the post itself.
Regards
Kandy
AlanPosted Aug 22, 2007, 2:58 PM
I definitely think you can do this for managed dlls, by loading the dll dynamically, reflecting on the types it contains, obtaining the parameter types/return type for the method the user has chosen and then invoking it.
You can also tell whether the .dll is managed or not by attempting to load it with the Assembly.LoadFile() method and catching the BadImageFormat exception that is thrown if it's unmanaged.
However, it's the unmanaged dlls that are the problem as I can't think of any obvious way to determine the nature of these though there are tools such as oleview (for COM), and dependency walker or dumpbin (for everything else except 16 bit dlls) that can analyze and report on the contents of dlls by reading the PE file headers.
As for calling unmanaged functions dynamically, the position is actually better than I thought as there are techniques available which can circumvent the lack of a P/Invoke signature by using either an assembly language dll to call the function or by getting its address using the API function GetProcAddress() and then invoking it using CallWindowProc(). See this Code Project article and the comments by Scott Carr:
http://www.codeproject.com/csharp/dyninvok.asp
kandyPosted Aug 22, 2007, 7:48 AM
Thanks for your replies Mr.Yogesh and Alan. I understood that this is hard to accomplish.
Tell me whether this approach would be possible to solve the problem to a certain extent.
Allowing the user to select what kind of Dll he/she is choosing from the HardDisk whether c/c++ or .Net or any unmanaged dll etc; and then extracting their features by the use of their corresponding compilers or runtime engines and calling them by their respective interfaces.
Regards
kandy
AlanPosted Aug 22, 2007, 7:21 AM
If the user can only choose amongst a fixed set of dlls and a fixed set of functions within those dlls, then I agree with Yogesh that you will be able to deal with:
1. Unmanaged dlls which export only static functions (typically written in C) by using P/Invoke (DllImport);
2. Unmanaged COM dlls by using COM interop;
3. Managed dlls by including a reference to them at compile time;
and then calling the appropriate function using 'switch' statements.
However, for all practical purposes, you won't be able to call unmanaged non-COM dlls which export classes (such as MFC or other C++ dlls) as these really need a managed or COM wrapper before they can be called from C#.
If the set of dlls and/or functions is not fixed, then you'd have to emit code dynamically to deal with the first three types which, given the complexities involved, would be virtually impossible. In the case of managed dlls, you could discover parameter and return types using reflection, as Yogesh has said, but you'd need some other means of doing this for unmanaged dlls. Even then some parameters / return types might refer to unmanaged struct types or require special marshalling, or the function itself might use a different calling convention from WINAPI.
yogesh rainPosted Aug 22, 2007, 7:04 AM
if the dll is managed i.e. (.NET)
then u can dynamically load it refer (System.Reflection namespace )
if it is unmanaged (non .NET ) the outside class definition
[DllImport("xyz.dll", CharSet = CharSet.Ansi)]
public static extern int functionname(argument 1,argument2);
then u can access specified function in ur class