I have a DLL that I have developed. I use this DLL in a website using DllImport.
When I run the website via Visual Studio all is okay, but when I run it with the IIS it is stuck with no errors.
Here's my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.IO;
using System.Runtime.InteropServices;
using System.Web.Script.Serialization;
using System.Text.RegularExpressions;
namespace WebApplication1
{
public partial class WebForm1 : System.Web.UI.Page
{
[DllImport("D:\\WebApplication1\\WebApplication1\\bin\\dapreporter.dll", CallingConvention = CallingConvention.StdCall)]
public static extern IntPtr fndapreporter(string inifile, int nReport, int nYear, int nMonth, int nDay, int nType, int nCode, int precision);
protected void Page_Load(object sender, EventArgs e)
{
try
{
string iniFile = File.ReadAllText(#"D:\WebApplication1\WebApplication1\bin\WinDAP.ini");
IntPtr pVariant = fndapreporter(iniFile, 0, 2021, 9, 12, 0, 197, 0);
object sHtml = Marshal.GetObjectForNativeVariant(pVariant);
Marshal.FreeCoTaskMem(pVariant);
pVariant = IntPtr.Zero;
Response.Write(sHtml.ToString());
}
catch(Exception ex)
{
Response.Write("ERROR: " + ex.Message);
}
}
}
}
A website's files/folders are relative to the home directory for that particular website. Due to the way DllImport works, one can add the desired directory to the PATH environment variable and then specify only the filename.
Try the following:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.IO;
using System.Web.Hosting;
using System.Runtime.InteropServices;
using System.Web.Script.Serialization;
using System.Text.RegularExpressions;
namespace WebApplication1
{
public partial class WebForm1 : System.Web.UI.Page
{
[DllImport("dapreporter.dll", CallingConvention = CallingConvention.StdCall)]
public static extern IntPtr fndapreporter(string inifile, int nReport, int nYear, int nMonth, int nDay, int nType, int nCode, int precision);
protected void Page_Load(object sender, EventArgs e)
{
IntPtr pVariant = IntPtr.Zero;
try
{
//get path to bin directory
//string binDir = Server.MapPath("~/bin/");
string binDir = HostingEnvironment.MapPath("~/bin/");
//add bin directory to PATH so DLLImport can find the DLL
Environment.SetEnvironmentVariable("PATH", String.Format("{0};{1}", Environment.GetEnvironmentVariable("PATH"), binDir));
string iniFile = File.ReadAllText(Path.Combine(binDir, "WinDAP.ini"));
pVariant = fndapreporter(iniFile, 0, 2021, 9, 12, 0, 197, 0);
object sHtml = Marshal.GetObjectForNativeVariant(pVariant);
Response.Write(sHtml.ToString());
}
catch (Exception ex)
{
Response.Write("ERROR: " + ex.Message);
}
finally
{
if (pVariant != IntPtr.Zero)
{
Marshal.FreeCoTaskMem(pVariant);
pVariant = IntPtr.Zero;
}
}
}
}
}
Resources:
Call function from DLL with non-static path
HttpServerUtility.MapPath(String) Method
HostingEnvironment.MapPath(String) Method
httpcontext.current.server.mappath Object reference not set to an instance of an object
Related
I need to set the background of a Windows form to the user's current Desktop wallpaper. How do I do this in C#?
Thanks
You can try the following code. I've tested this code on windows 8 and it works for me:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace StringFormatting
{
public partial class WallpaperTest : Form
{
private const UInt32 SPI_GETDESKWALLPAPER = 0x73;
private const int MAX_PATH = 260;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int SystemParametersInfo(UInt32 uAction, int uParam, string lpvParam, int fuWinIni);
public WallpaperTest()
{
InitializeComponent();
this.BackgroundImage = GetCurrentDesktopWallpaper();
this.BackgroundImageLayout = ImageLayout.Stretch;
}
public Image GetCurrentDesktopWallpaper()
{
string currentWallpaper = new string('\0', MAX_PATH);
SystemParametersInfo(SPI_GETDESKWALLPAPER, currentWallpaper.Length, currentWallpaper, 0);
string imageAddress = currentWallpaper.Substring(0, currentWallpaper.IndexOf('\0'));
return Image.FromFile(imageAddress);
}
}
}
As a non-admin user, I want to detect the event when another user logs in. I cannot use System Event Notification Service (SensLogon2) since it requires the user to be part of the Administrators group. Is there another API or are there certain permission/privileges that I can grant to the current user?
We need to detect another user logging on to the terminal via RDP so that we can change the application state the current user is in.
You can do next steps to get info about session changes:
Call WTSRegisterSessionNotification with NOTIFY_FOR_ALL_SESSIONS on your form to receive WM_WTSSESSION_CHANGE message
override void WndProc(ref Message m) of the Form and filtering by WM_WTSSESSION_CHANGE (0x2b1)
Extract session id from LPARAM and session state change event from WPARAM
Call WTSQuerySessionInformation with session id to get username
Here is working example with pInvoke. I have Form1 (WinForm) in my project. It is:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace MessageLoop
{
public partial class Form1 : Form
{
/// <summary>
/// WM_WTSSESSION_CHANGE message number for filtering in WndProc
/// </summary>
private const int WM_WTSSESSION_CHANGE = 0x2b1;
public Form1()
{
InitializeComponent();
NativeWrapper.WTSRegisterSessionNotification(this, SessionNotificationType.NOTIFY_FOR_ALL_SESSIONS);
}
protected override void OnClosing(CancelEventArgs e)
{
NativeWrapper.WTSUnRegisterSessionNotification(this);
base.OnClosing(e);
}
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_WTSSESSION_CHANGE)
{
int eventType = m.WParam.ToInt32();
int sessionId = m.LParam.ToInt32();
WtsSessionChange reason = (WtsSessionChange)eventType;
Trace.WriteLine(string.Format("SessionId: {0}, Username: {1}, EventType: {2}",
sessionId, NativeWrapper.GetUsernameBySessionId(sessionId), reason));
}
base.WndProc(ref m);
}
}
}
Here is NativeWrapper.cs:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace MessageLoop
{
public enum WtsSessionChange
{
WTS_CONSOLE_CONNECT = 1,
WTS_CONSOLE_DISCONNECT = 2,
WTS_REMOTE_CONNECT = 3,
WTS_REMOTE_DISCONNECT = 4,
WTS_SESSION_LOGON = 5,
WTS_SESSION_LOGOFF = 6,
WTS_SESSION_LOCK = 7,
WTS_SESSION_UNLOCK = 8,
WTS_SESSION_REMOTE_CONTROL = 9,
WTS_SESSION_CREATE = 0xA,
WTS_SESSION_TERMINATE = 0xB
}
public enum SessionNotificationType
{
NOTIFY_FOR_THIS_SESSION = 0,
NOTIFY_FOR_ALL_SESSIONS = 1
}
public static class NativeWrapper
{
public static void WTSRegisterSessionNotification(Control control, SessionNotificationType sessionNotificationType)
{
if (!Native.WTSRegisterSessionNotification(control.Handle, (int)sessionNotificationType))
throw new Win32Exception(Marshal.GetLastWin32Error());
}
public static void WTSUnRegisterSessionNotification(Control control)
{
if (!Native.WTSUnRegisterSessionNotification(control.Handle))
throw new Win32Exception(Marshal.GetLastWin32Error());
}
public static string GetUsernameBySessionId(int sessionId)
{
IntPtr buffer;
int strLen;
var username = "SYSTEM"; // assume SYSTEM as this will return "\0" below
if (Native.WTSQuerySessionInformation(IntPtr.Zero, sessionId, Native.WTS_INFO_CLASS.WTSUserName, out buffer, out strLen) && strLen > 1)
{
username = Marshal.PtrToStringAnsi(buffer); // don't need length as these are null terminated strings
Native.WTSFreeMemory(buffer);
if (Native.WTSQuerySessionInformation(IntPtr.Zero, sessionId, Native.WTS_INFO_CLASS.WTSDomainName, out buffer, out strLen) && strLen > 1)
{
username = Marshal.PtrToStringAnsi(buffer) + "\\" + username; // prepend domain name
Native.WTSFreeMemory(buffer);
}
}
return username;
}
}
}
And the last file is Native.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace MessageLoop
{
public static class Native
{
public enum WTS_INFO_CLASS
{
WTSInitialProgram,
WTSApplicationName,
WTSWorkingDirectory,
WTSOEMId,
WTSSessionId,
WTSUserName,
WTSWinStationName,
WTSDomainName,
WTSConnectState,
WTSClientBuildNumber,
WTSClientName,
WTSClientDirectory,
WTSClientProductId,
WTSClientHardwareId,
WTSClientAddress,
WTSClientDisplay,
WTSClientProtocolType,
WTSIdleTime,
WTSLogonTime,
WTSIncomingBytes,
WTSOutgoingBytes,
WTSIncomingFrames,
WTSOutgoingFrames,
WTSClientInfo,
WTSSessionInfo
}
[DllImport("wtsapi32.dll", SetLastError = true)]
internal static extern bool WTSRegisterSessionNotification(IntPtr hWnd, [MarshalAs(UnmanagedType.U4)] int dwFlags);
[DllImport("wtsapi32.dll", SetLastError = true)]
internal static extern bool WTSUnRegisterSessionNotification(IntPtr hWnd);
[DllImport("Wtsapi32.dll")]
internal static extern bool WTSQuerySessionInformation(IntPtr hServer, int sessionId, WTS_INFO_CLASS wtsInfoClass, out IntPtr ppBuffer, out int pBytesReturned);
[DllImport("Wtsapi32.dll")]
internal static extern void WTSFreeMemory(IntPtr pointer);
}
}
I'm using the WebBrowsercontrol in a WinForms application and have implemented my own download manager by following the instructions here.
My custom download manager works, but also overrides the download manager for Internet Explorer, too*. Is there a way to only have the custom download manager appear when my application is running? Or is there a way to unregistered it when my application closes?
*I appreciate that is precisely the point of implementing IDownloadManager, and the WebBrowser control is just, essentially, Internet Explorer (which is why I have gone down this route). The custom download manager provides exactly what I need, by allowing me to know what has been downloaded and where it has been downloaded to.
After weeks of research, I have finally managed to piece it together. Posting this here in the hopes that it will save someone the trauma I've been through.
IServiceProvider.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace BrowserExample
{
[ComImport, ComVisible(true)]
[Guid("6d5140c1-7436-11ce-8034-00aa006009fa")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IServiceProvider
{
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int QueryService(
[In] ref Guid guidService,
[In] ref Guid riid,
[Out] out IntPtr ppvObject);
}
}
IDownloadManager.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
namespace BrowserExample
{
[ComVisible(false), ComImport]
[Guid("988934A4-064B-11D3-BB80-00104B35E7F9")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IDownloadManager
{
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int Download(
[In, MarshalAs(UnmanagedType.Interface)] IMoniker pmk,
[In, MarshalAs(UnmanagedType.Interface)] IBindCtx pbc,
[In, MarshalAs(UnmanagedType.U4)] UInt32 dwBindVerb,
[In] int grfBINDF,
[In] IntPtr pBindInfo,
[In, MarshalAs(UnmanagedType.LPWStr)] string pszHeaders,
[In, MarshalAs(UnmanagedType.LPWStr)] string pszRedir,
[In, MarshalAs(UnmanagedType.U4)] uint uiCP);
}
}
DownloadManagerImplementation.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices.ComTypes;
using System.Windows.Forms;
namespace BrowserExample
{
[System.Runtime.InteropServices.ComVisible(true)]
[System.Runtime.InteropServices.Guid("bdb9c34c-d0ca-448e-b497-8de62e709744")]
public class DownloadManagerImplementation : IDownloadManager
{
/// <summary>
/// Return S_OK (0) so that IE will stop to download the file itself.
/// Else the default download user interface is used.
/// </summary>
public int Download(IMoniker pmk, IBindCtx pbc, uint dwBindVerb, int grfBINDF,
IntPtr pBindInfo, string pszHeaders, string pszRedir, uint uiCP)
{
// Get the display name of the pointer to an IMoniker interface that specifies
// the object to be downloaded.
string name = string.Empty;
pmk.GetDisplayName(pbc, null, out name);
if (!string.IsNullOrEmpty(name))
{
Uri url = null;
bool result = Uri.TryCreate(name, UriKind.Absolute, out url);
if (result)
{
//Implement your custom download manager here
//Example:
//WebDownloadForm manager = new WebDownloadForm();
//manager.FileToDownload = url.AbsoluteUri;
//manager.Show();
MessageBox.Show("Download URL is: " + url);
return 0; //Return S_OK
}
}
return 1; //unspecified error occured.
}
}
ExtendedBrowser.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace BrowserExample
{
public class ExtendedBrowser : WebBrowser
{
protected sealed class WebBrowserControlSite : WebBrowser.WebBrowserSite, IServiceProvider
{
DownloadManagerImplementation manager;
public WebBrowserControlSite(WebBrowser host)
: base(host)
{
manager = new DownloadManagerImplementation();
}
public int QueryService(ref Guid guidService, ref Guid riid, out IntPtr ppvObject)
{
Guid SID_SDownloadManager = new Guid("988934A4-064B-11D3-BB80-00104B35E7F9");
Guid IID_IDownloadManager = new Guid("988934A4-064B-11D3-BB80-00104B35E7F9");
if ((guidService == IID_IDownloadManager && riid == IID_IDownloadManager))
{
ppvObject = Marshal.GetComInterfaceForObject(manager, typeof(IDownloadManager));
return 0; //S_OK
}
ppvObject = IntPtr.Zero;
return unchecked((int)0x80004002); //NON_INTERFACE (use the default, please)
}
}
protected override WebBrowserSiteBase CreateWebBrowserSiteBase()
{
return new WebBrowserControlSite(this);
}
}
}
To use it, just instantiate the ExtendedBrowser.
Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace BrowserExample
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
var browser = new ExtendedBrowser();
this.Controls.Add(browser);
browser.Dock = DockStyle.Fill;
browser.Navigate("http://stackoverflow.com");
}
}
}
Program.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Test {
class Program {
static void Main(string[] args) {
for (int i = 0; i < 1000000000; i++) {
WindowHandler.testOverlay();
}
}
}
}
WindowHandler.cs:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Test {
static class WindowHandler {
private const String WINDOW_TITLE = "Minesweeper";
private static IntPtr windowHandle = IntPtr.Zero;
public static void testOverlay() {
if (windowHandle == IntPtr.Zero) {
windowHandle = getWindowHandle();
}
Graphics g = Graphics.FromHwnd(windowHandle);
g.FillRectangle(new SolidBrush(Color.White), 0, 0, 10000, 10000);
}
private static IntPtr getWindowHandle() {
foreach (Process proc in Process.GetProcesses()) {
if (proc.MainWindowTitle == WINDOW_TITLE) {
return proc.MainWindowHandle;
}
}
MessageBox.Show("Error: Unable to find window.");
return IntPtr.Zero;
}
}
}
I am not sure what I am doing wrong. I am writing a Minesweeper Solver and I am trying to overlay graphics on the Minesweeper window to provide debugging information. Unfortunately, it doesn't seem to work at all as I do not see any change on my screen. I am looping 1000000000 times in Program.cs just in case it erases my overlay on every frame refresh. I prefer to not try to hook DirectX.
I'm trying to capture a Screensaver event, however when I run my application it throws the following exception;
Unable to find an entry point named 'SystemParametersinfo' in DLL 'user32.dll'.
this is my code so far, any and all help would be greatly appreciated =D
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using NLog;
using Topshelf;
using OsWatch;
using Microsoft.Win32;
using System.Runtime.InteropServices;
namespace NotifyIcon
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
SystemEvents.SessionSwitch += SystemEvents_SessionSwitch;
}
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int SystemParametersinfo(int uAction, int uParam, ref int ipvParam, int fuWinini);
const int SPI_GETSCREENSAVERRUNNING = 114;
static int screenSaverRunning = -1;
int ok = SystemParametersinfo(SPI_GETSCREENSAVERRUNNING, 0, ref screenSaverRunning, 0);
private void ScreenSaver()
{
if (ok == 0)
{
Logger.Trace("SCREENSAVER OFF");
}
if (screenSaverRunning != 0)
{
Logger.Trace("SCREENSAVER ON");
}
}