|
|
Hello
I use the invoke dll in windows applications and it works fine.
I used the same .Net Wrapper (VB), in a .Net WebService and I have a probleme because my wrapper doesn't find the dll I load dynamicaly. (LoadLibrary return 0)
I know that Asp.Net make a copy of binary folder in cache.
How can I resolve this probleme
Thanks in advance
Sébastien
|
|
|
|
|
if u use the absolut DLL path.
such as : c:\\xxpath\\xx.dll
it should be work.
joylite
|
|
|
|
|
Hi
I have " int func(char* names[]) " function.
I need to call thus C++ dll function and get an array of names.
How I need to write my c# func?
Thanks
koby
|
|
|
|
|
Here is the progress so far, but I am not able to successfully get a valid file handle to the window and show it. It does not crash however. This will aid to your progress as well.
namespace MyApp
{
struct WNDCLASSEX
{
public uint cbSize;
public uint style;
public long lpfnWndProc;
public int cbClsExtra;
public int cbWndExtra;
public long hInstance;
public long hIcon;
public long hCursor;
public long hbrBackground;
public string lpszMenuName;
public string lpszClassName;
public long hIconSm;
}
class Class1
{
public const string KERNEL32_DLL = "kernel32.dll";
[DllImport(KERNEL32_DLL, EntryPoint="GetModuleHandle")]
static extern int GetModuleHandleA(string lpModuleName);
public const string USER32_DLL = "user32";
public const uint CS_VREDRAW = 0x0001;
public const uint CS_HREDRAW = 0x0002;
public const long WS_OVERLAPPED = 0x00000000L;
public const long WS_EX_APPWINDOW = 0x00040000L;
public const long WS_SYSMENU = 0x00080000L;
public const int SW_SHOWNORMAL = 1;
[DllImport(USER32_DLL, EntryPoint="MessageBox")]
public static extern int MessageBox(int hWnd, String strMessage, String strCaption, uint uiType);
[DllImport(USER32_DLL, EntryPoint="GetForegroundWindow")]
public static extern int GetForegroundWindow();
[DllImport(USER32_DLL, EntryPoint="RegisterClassEx")]
public static extern short RegisterClassExA(ref WNDCLASSEX pcWndClassEx);
[DllImport(USER32_DLL, EntryPoint="CreateWindowEx")]
public static extern long CreateWindowExA(long dwExStyle, string lpClassName, string lpWindowName, long dwStyle, long x, long y, long nWidth, long nHeight, long hwndParent, long hMenu, long hInstance, object lpParam);
[DllImport(USER32_DLL, EntryPoint="ShowWindow")]
public static extern int ShowWindow(long hwnd, int nCmdShow);
[DllImport(USER32_DLL, EntryPoint="UpdateWindow")]
public static extern int UpdateWindow(long hwnd);
[DllImport(USER32_DLL, EntryPoint="SetFocus")]
public static extern int SetFocus(long hwnd);
[DllImport(USER32_DLL, EntryPoint="ShowCursor")]
public static extern int ShowCursor(bool bShow);
[DllImport(USER32_DLL, EntryPoint="UnregisterClass")]
public static extern int UnregisterClassA(string lpClassName, long hInstance);
///
/// The main entry point for the application.
///
[STAThread]
static void Main(string[] args)
{
WNDCLASSEX wndclassex = new WNDCLASSEX();
wndclassex.cbSize = 48;
wndclassex.style = CS_HREDRAW | CS_VREDRAW;
wndclassex.lpfnWndProc = 0;
wndclassex.cbClsExtra = 0;
wndclassex.cbWndExtra = 0;
wndclassex.hIcon = 0;
wndclassex.hCursor = 0;
wndclassex.hbrBackground = 0;
wndclassex.lpszMenuName = "";
wndclassex.lpszClassName = "myclassname";
wndclassex.hIconSm = 0;
wndclassex.hInstance = 0;
RegisterClassExA(ref wndclassex);
long hWnd = CreateWindowExA(
WS_EX_APPWINDOW,
wndclassex.lpszClassName,
"TAGML",
WS_OVERLAPPED | WS_SYSMENU, // Window won't be resizable
0,
0,
300,
300,
0,
0,
wndclassex.hInstance,
0);
if(hWnd == 0)
{
MessageBox(0, "Unable to create window", ".NET", 0);
UnregisterClassA(wndclassex.lpszClassName, wndclassex.hInstance);
return;
}
ShowWindow(hWnd, SW_SHOWNORMAL);
UpdateWindow(hWnd);
SetFocus(hWnd);
ShowCursor(true);
//UnregisterClassA(wndclassex.lpszClassName, wndclassex.hInstance);
|
|
|
|
|
Ok at this point I have the callback coming back from the window into C#, but I can't get a valid handle. It keeps coming up as zero. Any idea why the HWND is always zero????
using System;
using System.Runtime.InteropServices;
namespace MyApp
{
public delegate UIntPtr FPtr(IntPtr hWnd, uint uMsg, UIntPtr wParam, UIntPtr lParam);
struct WNDCLASSEX
{
public UInt32 cbSize;
public UInt32 style;
public FPtr lpfnWndProc;
public Int32 cbClsExtra;
public Int32 cbWndExtra;
public IntPtr hInstance;
public IntPtr hIcon;
public IntPtr hCursor;
public IntPtr hbrBackground;
public string lpszMenuName;
public string lpszClassName;
public IntPtr hIconSm;
}
///
/// Summary description for Class1.
///
class Class1
{
public const string KERNEL32_DLL = "kernel32.dll";
[DllImport(KERNEL32_DLL, EntryPoint="GetModuleHandle")]
static extern int GetModuleHandleA(string lpModuleName);
public const string USER32_DLL = "user32";
public const UInt32 CS_VREDRAW = 0x0001;
public const UInt32 CS_HREDRAW = 0x0002;
public const UInt32 WS_EX_APPWINDOW = 0x00040000;
public const UInt32 WS_OVERLAPPED = 0x00000000;
public const UInt32 WS_SYSMENU = 0x00080000;
public const Int32 SW_SHOWNORMAL = 1;
public const int WM_QUIT = 0x0012;
[DllImport(USER32_DLL, EntryPoint="MessageBox")]
public static extern int MessageBox(int hWnd, String strMessage, String strCaption, uint uiType);
[DllImport(USER32_DLL, EntryPoint="GetForegroundWindow")]
public static extern int GetForegroundWindow();
[DllImport(USER32_DLL, EntryPoint="RegisterClassEx")]
public static extern short RegisterClassExA(ref WNDCLASSEX pcWndClassEx);
[DllImport(USER32_DLL, EntryPoint="CreateWindowEx")]
public static extern IntPtr CreateWindowExA(UInt32 dwExStyle, string lpClassName, string lpWindowName, UInt32 dwStyle, Int32 x, Int32 y, Int32 nWidth, Int32 nHeight, IntPtr hwndParent, IntPtr hMenu, IntPtr hInstance, IntPtr lpParam);
[DllImport(USER32_DLL, EntryPoint="FindWindow")]
public static extern IntPtr FindWindowA(string lpClassName, string lpWindowName);
[DllImport(USER32_DLL, EntryPoint="FindWindowEx")]
public static extern IntPtr FindWindowExA(IntPtr hwndParent, IntPtr hwndChildAfter, string lpClassName, string lpWindowName);
[DllImport(USER32_DLL, EntryPoint="ShowWindow")]
public static extern int ShowWindow(long hwnd, Int32 nCmdShow);
[DllImport(USER32_DLL, EntryPoint="UpdateWindow")]
public static extern int UpdateWindow(long hwnd);
[DllImport(USER32_DLL, EntryPoint="SetFocus")]
public static extern int SetFocus(long hwnd);
[DllImport(USER32_DLL, EntryPoint="ShowCursor")]
public static extern int ShowCursor(bool bShow);
[DllImport(USER32_DLL, EntryPoint="UnregisterClass")]
public static extern int UnregisterClassA(string lpClassName, IntPtr hInstance);
public static UIntPtr WinProc(IntPtr hWnd, uint uMsg, UIntPtr wParam, UIntPtr lParam)
{
Console.WriteLine("WinProc Callback called!!!!!!!");
return UIntPtr.Zero;
}
///
/// The main entry point for the application.
///
[STAThread]
static void Main(string[] args)
{
string ClassName = "MyClassName";
string WindowName = "TagML";
WNDCLASSEX wndclassex = new WNDCLASSEX();
wndclassex.cbSize = 48;
wndclassex.style = CS_HREDRAW | CS_VREDRAW;
wndclassex.lpfnWndProc = new FPtr(WinProc);
wndclassex.cbClsExtra = 0;
wndclassex.cbWndExtra = 0;
wndclassex.hInstance = IntPtr.Zero;
wndclassex.hIcon = IntPtr.Zero;
wndclassex.hCursor = IntPtr.Zero;
wndclassex.hbrBackground = IntPtr.Zero;
wndclassex.lpszMenuName = "";
wndclassex.lpszClassName = ClassName;
wndclassex.hIconSm = IntPtr.Zero;
RegisterClassExA(ref wndclassex);
IntPtr hWnd = CreateWindowExA(
WS_EX_APPWINDOW,
wndclassex.lpszClassName,
WindowName,
WS_OVERLAPPED | WS_SYSMENU, // Window won't be resizable
0,
0,
300,
300,
IntPtr.Zero,
IntPtr.Zero,
wndclassex.hInstance,
IntPtr.Zero);
hWnd = FindWindowA(wndclassex.lpszClassName, WindowName);
hWnd = FindWindowExA(IntPtr.Zero, IntPtr.Zero, wndclassex.lpszClassName, WindowName);
if(hWnd == IntPtr.Zero)
{
MessageBox(0, "Unable to create window", ".NET", 0);
UnregisterClassA(wndclassex.lpszClassName, wndclassex.hInstance);
return;
}
|
|
|
|
|
Why isn't CreateWindowEx returning valid window handle?
Easy to check Source Files:
http://www.tagenigma.com/qa/CSharp.Win32.zip
Do I need to setup a hook or something?
http://msdn.microsoft.com/msdnmag/issues/02/10/CuttingEdge/
|
|
|
|
|
Declare a wndProc function . Dont set it to 0;
Ravindra Kumar Sharma
SE ,Monitors
|
|
|
|
|
.Net v2.0 has no need for the InvokeFunc thunk. Instead, the System.Runtime.InteropServices.Marshal class has a GetDelegateForFunctionPointer() method which obtains a delegate for any unmanaged function pointer.
|
|
|
|
|
Okay, So You declare:
<br />
[DllImport("Invoke", CharSet=CharSet.Unicode)]<br />
public extern static int InvokeFunc(int funcptr, int hwnd, <br />
string message, string title, int flags);<br />
So if I want to use Invoke.dll to call a different function WHICH has a different signature - maybe taking two ints and a Guid,I would have to declare the following:
<br />
[DllImport("Invoke", CharSet=CharSet.Unicode)]<br />
public extern static int InvokeFunc(int funcptr, int par1, int par2, Guid par3);<br />
is that correct?
|
|
|
|
|
|
Hello, i need to create a similar Dll to handle the value of the GetProcAddress() function. The value returned by GetProcAddress() is an int value, and i guess i'd need a pointer to this int to be able to call a specific function of an API : WinStationQueryInformationW from WinSta.dll
The problem is i'm bad at C++ so i can't create a dll similar to your Invoke.dll nor understand what you've done in it. :-/
Is it possible to handle the invoking part within a c# class ?
Cause your sample code enables me to use loadlibrary + getProcAddress and make it works with your invokefunc but it's not suitable to call WinStationQueryInformationW.
I'm sorry i'm french and not very experienced so my arguments must be kind of difficult to understand. Anyway, i would be very happy if you can help me.
Thanks
|
|
|
|
|
You're making the (false) assumption that I'm good at C++ - quite the contrary. The Invoke DLL is very very simple assembler - the only x86 assembler I've written...ever.
I'm sure you can make it work.
|
|
|
|
|
I believe you but i don't know the code to fill the dll with, even if it's simple, i have no idea. Is it possible to make this dll with DotNet ?
|
|
|
|
|
it would be very good if you could give me the definition of your Function InvokeFunc() .
|
|
|
|
|
You may be able to do it using Reflection.Emit to create .Net code on the fly and executing that.
The definition for the InvokeFunc is provided in the Zip file - it's called Invoke.asm
|
|
|
|
|
Thanks. So using your invoke function, you think i can call any function stored in any DLL ?
Here is the code i use :
<br />
[DllImport("Invoke", CharSet=CharSet.Unicode)]<br />
public extern static int InvokeFunc(int funcptr, int hwnd, string message, string title, int flags);<br />
<br />
[DllImport("Invoke", CharSet=CharSet.Unicode)]<br />
public extern static int InvokeFunc(int funcptr, HANDLE hServer, long SessionID, WINSTATIONINFOCLASS WinStationInformation, ref WINSTATIONINFORMATION WinInfo,long LenWinInfo,ref long endWinInfo);<br />
Do you think i can use this kind of code or is it totally inapropriate ?
|
|
|
|
|
That looks fine to me. You obviously need to define your HANDLE, WINSTATIONINFOCLASS etc in C# structs - but it should be work fine.
|
|
|
|
|
Hello,
i might be very confusing as i am kindly new to these type of problems in C# language, like bindings, marshalling assemblies and so on.
I wonder why the Microsoft guys are so stupid. I have searched for a week how to solve my problem, and i found no valuable answer till now.
Let me detail a little the problem.
I have a Windows Service App, which makes use of an API Application given by a third party. My application will redistribute this 3rd party app, via a setup package (msi).
In my Service, i use an extern method from the 3rd party main dll.
The problem relies that, even i changed the redistribution path to Program Files Common Files folder, our clients are multinational and these folders are not fix. My problem is how to avoid the dumb DLLImport which cannot take an input param, even that i put Environment.GetCommonFilesFolder
MSDN Site says that if i do a LoadLibrary before the DLLImport, i solved this. So i called the LoadLibrary with variable path in the service constructor.
The problem is that LoadLibrary always return IntPtr.Zero. I tried with LoadLibraryEx, and this worked for passing third param 1 and 2, but it still doesn't solve my problem. I also let the DLLImport with x.dll as first param, without the full path. I get just "The service has been terminated unexpectedly" error, even i catch all exceptions, COMExceptions. There is no catch block executed
Then i moved on downloading this piece of code. My VS .NET 2005 with .NET 2.0 gives errors on assembler file.
Then i found other solution. I removed the DLLImport, and i tried the sequence:
LoadLibraryEx
GetProcAddress
creating a delegate with the same name as my DLL method, and calling this delegate, instead of calling the DLL method. Bullshit, the same error, "Service terminated unexpectedly. It has done this (1) times". Here if i haven't specified 2 as third param to LoadLibraryEx, the GetProcAddress always returns Intptr.Zero.
Knowing that i come from a full managed world, because my experience is totally in Java, and now i am learning C#, i am totally confused about this problem. I cannot imagine the Microsoft guys so dumb not to take into account this possible workflow, because i found nothing related to my problem on the net.
Thank you in advance for any possible suggestion or tutorial,
c y
|
|
|
|
|
Richard,
Nice article!
Another .NET/DLL related question.
How do I implement/simulate DllMain in C#?
As you can imagine the most intriguing part of this question would be the DLL_PROCESS_DETACH event -- Say I want to do some DLL (sorry, assembly) specific cleanup. (Doesn’t it sound similar to the destructor related “issues”?
Thanks in advance.
Alex
|
|
|
|
|
If you want to do something when your app starts - consider adding a static constructor to a class - there is no way to hook DllMain in C#. In MC++, I believe you can hook DllMain, although this was troublesome in v1.0 and partially fixed (IIRC) in v1.1. Nick Hodapp wrote an article about this - see http://www.codeproject.com/scrapbook/semicolon_2.asp
As for an assembly level destructor - this has been talked about by the CLR team at Microsoft and may well have been added for Whidbey.
|
|
|
|
|
Thanks for the article,
Please provide guidelines to make the EXE using VS.Net...
How to link the .asm and .obj files in the IDE?
Thx,
UK
|
|
|
|
|
Hi,
I don't believe it's possible to generate and link assembler in the VS.Net IDE.
Richard
|
|
|
|
|
Hey Richard,
Thx for your help! BTW I also like Curry...
How to build the invoke.dll? just NMAE makefile? is that all?
Cheers,
Uriel
|
|
|
|
|
I downloaded the source code that has been posted here and tried to compile and run it as-is with Visual Studio .NET. However, I get a System.DllNotFoundException on the following line in the .cs file:
int result=InvokeFunc(funcaddr, 0, "Hello World", ".Net dynamic export invocation", 1 /*MB_OKCANCEL*/);
Why doesn't it like this? "DllNotFoundException" suggests to me that for some reason it's not finding User32.dll; however, this file is on my system. Any suggestions?
|
|
|
|
|