ASP.NET MVC 4: Stackoverflow exception when using [DLLImport] - c#

I'm using c++ morphology library mcr.dll and it's work fine when i use it in C# Console Application, but when I'm trying to run this code in ASP.NET MVC4 Controller it fails at "getlemma()" method, at line "LoadMcr(s)" with System.StackOverflowException. Please, help me to understand, why mvc controller doens't want to make this work like it does in console app?
P.S.: there were some problems when i've tryed to run it in Console Application, like messages about "PInvoke "ConsoleApplication1!ConsoleApplication1.morph::LoadMc unbalanced stack", but they disappeared when I add "CallingConvention = CallingConvention.Cdecl".
public string getlemma(string word)
{
InitMcr();
string s = "zal.mcr";
LoadMcr(s);
Tids tt = new Tids();
FindWID(word, ref tt);
Tid t = tt.ids[0];
Tinlexdata inlex = new Tinlexdata();
GetWordById(t, false, false, ref inlex);
return (inlex.inlex[0].anword);
}
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct Tid
{
/// unsigned int
public uint lnk;
/// unsigned char
public byte en;
}
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct Tids
{
/// Tid[200]
[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 200, ArraySubType = System.Runtime.InteropServices.UnmanagedType.Struct)]
public Tid[] ids;
/// int
public int count;
}
// // InitMcr() - initialize dictionary
[DllImport("mcr.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
public static extern int InitMcr();
// // LoadMcr - load dictionary
[DllImport("mcr.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
public static extern int LoadMcr([System.Runtime.InteropServices.InAttribute()] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)] string s);
// // FindID - (find word in lemma dictionary)
[DllImport("mcr.dll", CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
public static extern int FindWID([System.Runtime.InteropServices.InAttribute()] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)] string s, ref Tids ids);
// GetByID - (get lemma for a word)
[DllImport("mcr.dll", CharSet = CharSet.None, EntryPoint = "GetWordById", CallingConvention = CallingConvention.Cdecl)]
public static extern int GetWordById(Tid id, [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.I1)] bool gh_only, [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.I1)] bool all, ref Tinlexdata outdata);

Related

How to call WFSStartUp via C# application

I use this code for call WFSStartUp via C# program
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
public unsafe struct WFSVERSION
{
public ushort wVersion;
public ushort wLowVersion;
public ushort wHighVersion;
public fixed char szDescription[256 + 1];
public fixed char szSystemStatus[256 + 1];
}
[DllImport("msxfs.dll", CharSet = CharSet.Ansi, CallingConvention = XFSConstants.CALLINGCONVENTION)]
public static extern int WFSStartUp(int dwVersionsRequired, ref WFSVERSION lpWFSVersion);
WFSVERSION m_Version = new WFSVERSION();
int requestVersion = 0x00010202;
int hResult = WFSStartUp(requestVersion, ref m_Version);
the return value hResult is Ok but m_Version.szDescription not correct (m_Version.szDescription[0] = 'W', m_Version.szDescription[1] = 0, ...)
How to solve this problem?

Access Violation Error when calling a function with struct parameter from C-DLL in C#

I got following definition for a function in a c-based DLL (no source available):
uint MakeReference(MemBlock* ipReferenceMemBlock);
MemBlock is defined as:
typedef struct {
HANDLE_TAG dTag;
long dLength;
BYTE* dpReference;
} MemBlock;
HANDLE_TAG is defined as:
typedef char HANDLE_TAG[10 + 1];
My take on this in a C# Wrapper Class is:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct MemBlock
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)]
public string dTag;
public uint dLength;
[MarshalAs(UnmanagedType.LPStr)]
public string dpReference;
}
[DllImport("lib.dll", CharSet = CharSet.Ansi, EntryPoint = "MakeReference#24", CallingConvention = CallingConvention.StdCall)]
public static extern uint MakeReference(ref IntPtr pDDipMemBlock);
public static uint FAPIMakeReference(ref MemBlock ipMemBlock)
{
uint error = 0;
IntPtr pDDipMemBlock = Marshal.AllocHGlobal(Marshal.SizeOf(ipMemBlock));
try
{
Marshal.StructureToPtr(ipMemBlock, pDDipMemBlock, false);
error = MakeReferenceEx(ref pDDipMemBlock);
ipMemBlock = (MemBlock)Marshal.PtrToStructure(pDDipMemBlock, typeof(MemBlock));
}
finally
{
Marshal.FreeHGlobal(pDDipMemBlock);
}
return error;
}
calling this with:
MemBlock refMemBlock = new MemBlock();
uint error = MakeReferenceEx(ref refMemBlock);
resulting in an Access Violation Expection

Using ShellExecuteEx in c# with Unicode Filename

I need to use ShellExecuteExin c#
my filename has unicode character when I pass filename to ShellExecuteEx it throws exception
cant find file
When function finisheed unicode character in filename change to '?'
[Serializable]
public struct ShellExecuteInfo
{
public int Size;
public uint Mask;
public IntPtr hwnd;
public string Verb;
public string File;
public string Parameters;
public string Directory;
public uint Show;
public IntPtr InstApp;
public IntPtr IDList;
public string Class;
public IntPtr hkeyClass;
public uint HotKey;
public IntPtr Icon;
public IntPtr Monitor;
}
// Code For OpenWithDialog Box
[DllImport("shell32.dll", SetLastError = true)]
extern public static bool
ShellExecuteEx(ref ShellExecuteInfo lpExecInfo);
public const uint SW_NORMAL = 1;
public static void OpenAs(string file)
{
ShellExecuteInfo sei = new ShellExecuteInfo();
sei.Size = Marshal.SizeOf(sei);
sei.Verb = "openas";
sei.File = file;
sei.Show = SW_NORMAL;
if (!ShellExecuteEx(ref sei))
throw new System.ComponentModel.Win32Exception();
}
The default character set is ANSI. So you need to specify the character set to be Unicode:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct ShellExecuteInfo
{
....
}
....
[DllImport("shell32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool ShellExecuteEx(ref ShellExecuteInfo lpExecInfo);
Although personally, since this long struct is only ever passed by reference, and since you invariably use new to ensure initialization, I'd declare it as a class:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public class ShellExecuteInfo
{
....
}
....
[DllImport("shell32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool ShellExecuteEx(ShellExecuteInfo lpExecInfo);
Note that we removed the ref because a class is a reference type. As opposed to a struct which is a value type.
I would also comment that you got the field translation incorrect, at the icon/monitor union. A corrected translation would be:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public class ShellExecuteInfo
{
public int Size;
public uint Mask;
public IntPtr hwnd;
public string Verb;
public string File;
public string Parameters;
public string Directory;
public int Show;
public IntPtr InstApp;
public IntPtr IDList;
public string Class;
public IntPtr hkeyClass;
public uint HotKey;
public IntPtr IconOrMonitor;
public IntPtr Process;
}
Finally, for convenience, it is worth adding a constructor to the class to initialize the size field:
public ShellExecuteInfo()
{
Size = Marshal.SizeOf(this);
}
Of course, you can just use Process.Start for the code in the question:
ProcessStartInfo psi = new ProcessStartInfo();
psi.UseShellExecute = true;
psi.Verb = "openas";
psi.FileName = file;
Process.Start(psi);
Opening a URL
Solution 1 - PInvoke without the nasty structure
[DllImport("shell32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern uint ShellExecute(IntPtr hwnd, string strOperation, string strFile, string strParameters, string strDirectory, Int32 nShowCmd);
string link = "http://www.yahoo.com";
string def = string.Empty;
IntPtr hWnd = (IntPtr)0;
uint ret = ShellExecute(hWnd, def, link, def, def, 0);
Solution 2: Use C# native
Process.Start(new ProcessStartInfo("cmd", "/c start " + link) { CreateNoWindow = true });
Solution 3: More C#
ProcessStartInfo URL = new ProcessStartInfo();
URL.FileName = link;
URL.CreateNoWindow = true;
URL.UseShellExecute = true;
Process.Start(URL);

How to use Win32 GetMonitorInfo() in .NET c#?

I have to implement a feature where the last position of the window is saved. When the application starts up this position needs to be obtained and restored.
Now it could be that a second monitor is dismantled. If the last position is on a now non-visible monitor (in other words the saved coordinates are outside the visible coordinates), this case should be caught and the coordinates shall be set to the default rather than last position.
In order to retrieve the information about monitors I need to use Win32. It is not easy for me to make this work.
I have created a Helper CLass:
public static class DisplayHelper
{
private const int MONITOR_DEFAULTTONEAREST = 2;
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern int GetSystemMetrics(int nIndex);
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
private static extern UInt32 MonitorFromPoint(Point pt, UInt32 dwFlags);
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
private static extern bool GetMonitorInfo(UInt32 monitorHandle, ref MonitorInfo mInfo);
public static void GetMonitorInfoNow(MonitorInfo mi, Point pt)
{
UInt32 mh = MonitorFromPoint(pt, 0);
mi.cbSize = (UInt32)System.Runtime.InteropServices.Marshal.SizeOf(typeof(MonitorInfo));
mi.dwFlags = 0;
bool result = GetMonitorInfo(mh, ref mi);
}
}
And these are my attempts to create the MonitorInfo and Rect classes:
[StructLayout(LayoutKind.Sequential)]
public class MonitorInfo
{
public UInt32 cbSize;
public Rectangle2 rcMonitor;
public Rectangle2 rcWork;
public UInt32 dwFlags;
public MonitorInfo()
{
rcMonitor = new Rectangle2();
rcWork = new Rectangle2();
cbSize = (UInt32)System.Runtime.InteropServices.Marshal.SizeOf(typeof(MonitorInfo));
dwFlags = 0;
}
}
[StructLayout(LayoutKind.Sequential)]
public class Rectangle2
{
public UInt64 left;
public UInt64 top;
public UInt64 right;
public UInt64 bottom;
public Rectangle2()
{
left = 0;
top = 0;
right = 0;
bottom = 0;
}
}
I am using this code like this to obtain the visible monitors:
//80 means it counts only visible display monitors.
int lcdNr = DisplayHelper.GetSystemMetrics(80);
var point = new System.Drawing.Point((int) workSpaceWindow.Left, (int) workSpaceWindow.Top);
MonitorInfo monitorInfo = new MonitorInfo();
DisplayHelper.GetMonitorInfoNow(monitorInfo, point);
The last method throws an exception when trying to execute
bool result = GetMonitorInfo(mh, ref mi);
Any suggestions what I need to do to fix this?
Rather than calling a native API, you should use System.Windows.Forms.Screen. It should have everything you need, and be much easier to use.
Screen.FromPoint is the managed equivalent of your GetMonitorInfoNow function with the MONITOR_DEFAULTTONEAREST option. I just noticed you aren't using that option, so you may have to write your own or use the correct P/Invoke signatures.
Writing your own should be fairly simple, if you just reference System.Drawing and System.Windows.Forms. Both of these should work:
static Screen ScreenFromPoint1(Point p)
{
System.Drawing.Point pt = new System.Drawing.Point((int)p.X, (int)p.Y);
return Screen.AllScreens
.Where(scr => scr.Bounds.Contains(pt))
.FirstOrDefault();
}
static Screen ScreenFromPoint2(Point p)
{
System.Drawing.Point pt = new System.Drawing.Point((int)p.X, (int)p.Y);
var scr = Screen.FromPoint(pt);
return scr.Bounds.Contains(pt) ? scr : null;
}
If you prefer to make the Win32 calls yourself, the proper P/Invoke signatures (i.e. what you'd get from decompiling the .Net DLL) for the functions you need to call are:
[DllImport("User32.dll", CharSet=CharSet.Auto)]
public static extern bool GetMonitorInfo(HandleRef hmonitor, [In, Out]MONITORINFOEX info);
[DllImport("User32.dll", ExactSpelling=true)]
public static extern IntPtr MonitorFromPoint(POINTSTRUCT pt, int flags);
[StructLayout(LayoutKind.Sequential,CharSet=CharSet.Auto, Pack=4)]
public class MONITORINFOEX {
public int cbSize = Marshal.SizeOf(typeof(MONITORINFOEX));
public RECT rcMonitor = new RECT();
public RECT rcWork = new RECT();
public int dwFlags = 0;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=32)]
public char[] szDevice = new char[32];
}
[StructLayout(LayoutKind.Sequential)]
public struct POINTSTRUCT {
public int x;
public int y;
public POINTSTRUCT(int x, int y) {
this.x = x;
this.y = y;
}
}
[StructLayout(LayoutKind.Sequential)]
public struct RECT {
public int left;
public int top;
public int right;
public int bottom;
}
I found one different is
public static extern bool GetMonitorInfo(IntPtr hMonitor, [In,Out] MONITORINFO lpmi) and
public static extern bool GetMonitorInfo(IntPtr hMonitor, ref MONITORINFO lpmi)
In my case, the ref keywork made the function always return false.
But if remove this keyword or usr [In,Out], it work.
More info about ref vs. [In,Out] on This.
Your Rectangle2 should use Int32 or just int, not Int64. More information can be found here.
Also it needs to be a struct, not a class. Same goes for your MonitorInfo class (it should be a struct). I'd recommend trying the version from the link above, or compare them with your versions.
Since you are using the MonitorInfo class, not a struct, you must specify the [Out] attribute and not use ref in order for the marshaler to update your class correctly.
[DllImport("user32", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern bool GetMonitorInfo(
IntPtr hmonitor,
[In, Out] MonitorInfo info);
You can also go to using structure and ref, then it will look like this:
[DllImport("user32", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern bool GetMonitorInfo(
IntPtr hmonitor,
ref MonitorInfoEx info);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 4)]
internal struct MonitorInfoEx
{
public uint cbSize;
public RECT rcMonitor;
public RECT rcWork;
public uint dwFlags;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public char[] szDevice;
}
var info = new MonitorInfoEx
{
cbSize = (uint)Marshal.SizeOf(typeof(MonitorInfoEx)),
};
GetMonitorInfo(hDesktop, ref info);

C# static constructor and GetVersion() any suggestions?

C# static constructor and GetVersion() any suggestions?
Hi,
I have defined struct like this in separate file OSVERSIONINFO.cs like this:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct OSVERSIONINFO
{
public static int SizeOf
{
get
{
return Marshal.SizeOf (typeof(OSVERSIONINFO));
}
}
public uint dwOSVersionInfoSize;
public uint dwMajorVersion;
public uint dwMinorVersion;
public uint dwBuildNumber;
public uint dwPlatformId;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string szCSDVersion;
}
Also I have this file OS.cs in which I have defined the following class:
public static class OS
{
static OS ()
{
OSVERSIONINFO info = new OSVERSIONINFO();
info.dwOSVersionInfoSize = (uint)OSVERSIONINFO.SizeOf;
if (!OS.GetVersion(ref info))
{
Console.WriteLine("Error!!!");
}
}
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetVersion (ref OSVERSIONINFO lpVersionInfo);
}
Way in static constructor of OS class population of info (instance of OSVERSIONINFO struct) fails?
If I call OS.GetVersion in other palce (not OS class) every thing is OK?
You should use the Environment.OSVersion.Platform property instead.
To answer the question, you need to call GetVersionEx.

Categories