Guys I'm stuck at the final part of a functional deskband implementation for my application,
For context, I'm currently running a visual studio solution with 2 projects in them,
one is the c++ deskband dll and another is a simple c# console program.
The DeskBand code is Microsoft's DeskBand sample
Currently, I can register the dll when the console app runs by calling the "DllRegisterServer" with GetProcAddress(). After this I'll simply right-click the taskbar and enable the registered deskband.
My question comes from here on,
Once registered, let's say the OnPaint event in the Deskband implementation paints a text variable called "Hello world", What I want to do is simply send a string from c# to the running dll and make it paint "Sent from c#".
The register class:
public class Registrar
{
private IntPtr hLib;
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
internal static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern IntPtr LoadLibrary(string lpFileName);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern bool FreeLibrary(IntPtr hModule);
internal delegate int PointerToMethodInvoker();
public Registrar(string filePath)
{
hLib = LoadLibrary(filePath);
if (IntPtr.Zero == hLib)
{
int errno = Marshal.GetLastWin32Error();
throw new Win32Exception(errno, "Failed to load library.");
}
}
public void RegisterComDLL()
{
CallPointerMethod("DllRegisterServer");
}
public void UnRegisterComDLL()
{
CallPointerMethod("DllUnregisterServer");
}
private void CallPointerMethod(string methodName)
{
IntPtr dllEntryPoint = GetProcAddress(hLib, methodName);
if (IntPtr.Zero == dllEntryPoint)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
PointerToMethodInvoker drs =
(PointerToMethodInvoker)Marshal.GetDelegateForFunctionPointer(dllEntryPoint,
typeof(PointerToMethodInvoker));
drs();
}
public void FreeLib()
{
if (IntPtr.Zero != hLib)
{
FreeLibrary(hLib);
hLib = IntPtr.Zero;
}
}
}
The simple console program:
static void Main(string[] args)
{
Console.WriteLine("Start");
Registrar reg = new Registrar("DeskBandDLL.dll");
if (reg != null)
{
reg.RegisterComDLL();
//send data to the registered dll to start painting new text
Console.ReadLine();
reg.UnRegisterComDLL();
reg.FreeLib();
}
}
Btw, I do know that Microsoft discontinued deskband in win11, but I really want to implement this feature for only the win10 platform and I feel like I'm close to finishing this.
And if you need the full code for clarification, I can host it on GitHub.
Related
all!
Please, help me with any advice with my problem: I build GUI WinForms application and now I want to attach console to it. I found this is not as much easy as it seems before. But I found good solution here: How do I show a console output/window in a forms application? Below the code from rag answer.
using System;
using System.Runtime.InteropServices;
namespace SomeProject
{
class GuiRedirect
{
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool AttachConsole(int dwProcessId);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr GetStdHandle(StandardHandle nStdHandle);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool SetStdHandle(StandardHandle nStdHandle, IntPtr handle);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern FileType GetFileType(IntPtr handle);
private enum StandardHandle : uint
{
Input = unchecked((uint)-10),
Output = unchecked((uint)-11),
Error = unchecked((uint)-12)
}
private enum FileType : uint
{
Unknown = 0x0000,
Disk = 0x0001,
Char = 0x0002,
Pipe = 0x0003
}
private static bool IsRedirected(IntPtr handle)
{
FileType fileType = GetFileType(handle);
return (fileType == FileType.Disk) || (fileType == FileType.Pipe);
}
public static void Redirect()
{
if (IsRedirected(GetStdHandle(StandardHandle.Output)))
{
var initialiseOut = Console.Out;
}
bool errorRedirected = IsRedirected(GetStdHandle(StandardHandle.Error));
if (errorRedirected)
{
var initialiseError = Console.Error;
}
AttachConsole(-1);
if (!errorRedirected)
SetStdHandle(StandardHandle.Error, GetStdHandle(StandardHandle.Output));
}
}
This code works as charm except one downside: non-latin letters outputs to console in strange encoding (but if redirected to file, they are in right encoding). I need to redirect both StdOut and StdErr, and if I change any part of the code it stops redirecting.
Thanks to all who share their wisdom with me in comments!
SetConsoleOutputCP was the answer.
Don't forget put this to other definitions of the class.
[DllImport("kernel32.dll")]
static extern bool SetConsoleOutputCP(uint wCodePageID);
And than add call of the SetConsoleOutputCP(desired codepage); to Redirect() method.
I am trying to create a WPF - hybrid application. This application should have the option to be started from command prompt, where in this case, it would not show any window but will only start some process and then quit.
For example (made up example) in my WPF application I enable users to create body of an email message that will be send to any user (sort of a template).
Afterwards when user wants to send the email, he can do it via cmd like following (meaning GUI will not even start, it will only call email connector and send message to selected recipient and then quit program):
MyProgram.exe -recipient john#doe.com -send=true
My Main() looks like this (created based on the following website:http://www.jankowskimichal.pl/en/2011/12/wpf-hybrid-application-with-parameters/)
public static class Program
{
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool AllocConsole();
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool FreeConsole();
[DllImport("kernel32", SetLastError = true)]
static extern bool AttachConsole(int dwProcessId);
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);
[STAThreadAttribute]
[System.Diagnostics.DebuggerNonUserCodeAttribute]
public static void Main(string[] args)
{
//App.Main();
if (args.Length == 0)
{
IP_DynamicMailings.App app = new IP_DynamicMailings.App();
app.InitializeComponent();
app.Run();
}
else
{
// Get uppermost window process
IntPtr ptr = GetForegroundWindow();
int u;
GetWindowThreadProcessId(ptr, out u);
Process process = Process.GetProcessById(u);
// Check if it is console?
if (process.ProcessName == "cmd")
{
// Yes – attach to active console
AttachConsole(process.Id);
}
else
{
// No – create new console
AllocConsole();
}
// Program actions ...
foreach (var item in args)
{
Console.WriteLine(item);
}
FreeConsole();
}
}
}
What happens is, that I need to press Enter in order to quit application.
I am also open to rewrite my hybrid logic, shall you have better solution (this was so far the best I could find).
I am trying to use a function drom a DLL, but I keep getting an XamlParseException, but I am able to see while running step by step my program that I get an AccessViolationException, which I think is the cause of the first exception.
Basically, what the function is supposed to do is to log me to a directory of a program to use the different classes to interact with the program.
I do not have access to the source of the DLL, but I have some documentation to use it, even though there aren't a lot of information in it, here is how I am supposed to use it :
Logon(BSTR DirectoryPath, BSTR ErrorFile, int Lang)
And here is my code :
public partial class MainWindow : Window
{
[DllImport("kernel32.dll")]
static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
private delegate int Logon([MarshalAs(UnmanagedType.BStr)]String DirectoryPath, [MarshalAs(UnmanagedType.BStr)]String ErrorFile, int Lang);
public MainWindow()
{
InitializeComponent();
try
{
string LnkPsbEppPath = "dll/LnkPsbEpp.dll";
IntPtr pAddressFctLogon = GetProcAddress(LnkPsbEppLink, "#Tdtm_Dossier#Logon$qv");
if (pAddressFctLogon == IntPtr.Zero)
Console.WriteLine("Logon function not found");
else
{
try
{
dynamic logon = Marshal.GetDelegateForFunctionPointer(pAddressFctLogon, typeof(Logon));
dynamic varLogon = logon(directoryPath, errorFilePath, 2); // <-- Here is where the AccessViolactionException happend
}
catch (Exception ex)
{
}
}
}
catch (Exception ex)
{
Console.WriteLine("ERROR : " + ex.Message);
}
}
}
Check that C++ dll whether it provides you the permission to write .
Check C++ dll documentation for more details
Even I faced same problem when I was using C++ dll in my WPF application
It could happen if in unmanaged code, there is some Null pointer being accessed.
I have a C dll with exported functions
I can use the command-line tool dumpbin.exe /EXPORTS to extract the list of exported functions, and then use them in my C# code to (successfully) call these functions.
Is there a way to get this exported-functions-list directly from .NET, without having to use an external command-line tool?
Thanks
As far as I know there is no class in the .Net Framework that
provides the information you need.
However you can use the platform invocation services (PInvoke) of the .Net platform to
use the functions of the Win32 dbghelp.dll DLL. This DLL is part of
the Debugging Tools for the Windows platform. The dbghelp DLL provides
a function called SymEnumerateSymbols64 which allows you to enumerate all
exported symbols of a dynamic link library. There is also a
newer function called SymEnumSymbols which also allows to enumerate
exported symbols.
The code below shows a simple example on how to use the SymEnumerateSymbols64
function.
[DllImport("dbghelp.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SymInitialize(IntPtr hProcess, string UserSearchPath, [MarshalAs(UnmanagedType.Bool)]bool fInvadeProcess);
[DllImport("dbghelp.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SymCleanup(IntPtr hProcess);
[DllImport("dbghelp.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern ulong SymLoadModuleEx(IntPtr hProcess, IntPtr hFile,
string ImageName, string ModuleName, long BaseOfDll, int DllSize, IntPtr Data, int Flags);
[DllImport("dbghelp.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SymEnumerateSymbols64(IntPtr hProcess,
ulong BaseOfDll, SymEnumerateSymbolsProc64 EnumSymbolsCallback, IntPtr UserContext);
public delegate bool SymEnumerateSymbolsProc64(string SymbolName,
ulong SymbolAddress, uint SymbolSize, IntPtr UserContext);
public static bool EnumSyms(string name, ulong address, uint size, IntPtr context)
{
Console.Out.WriteLine(name);
return true;
}
static void Main(string[] args)
{
IntPtr hCurrentProcess = Process.GetCurrentProcess().Handle;
ulong baseOfDll;
bool status;
// Initialize sym.
// Please read the remarks on MSDN for the hProcess
// parameter.
status = SymInitialize(hCurrentProcess, null, false);
if (status == false)
{
Console.Out.WriteLine("Failed to initialize sym.");
return;
}
// Load dll.
baseOfDll = SymLoadModuleEx(hCurrentProcess,
IntPtr.Zero,
"c:\\windows\\system32\\user32.dll",
null,
0,
0,
IntPtr.Zero,
0);
if (baseOfDll == 0)
{
Console.Out.WriteLine("Failed to load module.");
SymCleanup(hCurrentProcess);
return;
}
// Enumerate symbols. For every symbol the
// callback method EnumSyms is called.
if (SymEnumerateSymbols64(hCurrentProcess,
BaseOfDll, EnumSyms, IntPtr.Zero) == false)
{
Console.Out.WriteLine("Failed to enum symbols.");
}
// Cleanup.
SymCleanup(hCurrentProcess);
}
In order to keep the example simple I did not use the
SymEnumSymbols function. I've also did the example
without using such classes as the SafeHandle class of
the .Net framework. If you need a example for the
SymEnumSymbols function, just let me know.
Basically, how do I tell if my program is layered above all the other ones?
A fairly simple way is to P/Invoke GetForegroundWindow() and compare the HWND returned to the application's form.Handle property.
using System;
using System.Runtime.InteropServices;
namespace MyNamespace
{
class GFW
{
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
public bool IsActive(IntPtr handle)
{
IntPtr activeHandle = GetForegroundWindow();
return (activeHandle == handle);
}
}
}
Then, from your form:
if (MyNamespace.GFW.IsActive(this.Handle))
{
// Do whatever.
}
You can use:
if (GetForegroundWindow() == Process.GetCurrentProcess().MainWindowHandle)
{
//do stuff
}
WINAPI imports (at class level):
[System.Runtime.InteropServices.DllImport("user32.dll")] public static extern bool GetForegroundWindow();
Assign a property to hold the value, and add the check to the form's GotFocus event through IDE, or after InitializeComponent();
e.g.:
//.....
InitalizeComponent();
this.GotFocus += (myFocusCheck);
//...
private bool onTop = false;
private void myFocusCheck(object s, EventArgs e)
{
if(GetFore......){ onTop = true; }
}
If your window inherits form, you can check Form.Topmost property
A good solution is given by this answer to an identical question:
https://stackoverflow.com/a/7162873/386091
/// <summary>Returns true if the current application has focus, false otherwise</summary>
public static bool ApplicationIsActivated()
{
var activatedHandle = GetForegroundWindow();
if (activatedHandle == IntPtr.Zero) {
return false; // No window is currently activated
}
var procId = Process.GetCurrentProcess().Id;
int activeProcId;
GetWindowThreadProcessId(activatedHandle, out activeProcId);
return activeProcId == procId;
}
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int GetWindowThreadProcessId(IntPtr handle, out int processId);
The currently accepted solution by Euric doesn't work if your program shows a dialog box or has detachable windows (like if you use a windows docking framework).