Hello World for Pinvoke and Native Calls - visual-c++

I am trying to do a very basic hello world for Pinvoke and native calls.
I create a single solution with 2 projects (one for the dll and one for the universal windows app)
So I end up with a project heirachy like this
There is one method in my dll (file NativeCalls.cpp):
#include "pch.h"
#include "NativeCalls.h"
#include <stdio.h>
MYAPI void print_line(const char* str) {
printf("%s\n", str);
}
On the C# side of things I have my NativeCalls.cs file
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace MSSurfaceHubMonitoring
{
public static class NativeCalls
{
[DllImport("NativeCalls.dll")]
private static extern void print_line(string str);
public static void sayHelo()
{
print_line("Hello, PInvoke!");
}
}
}
At this point I will build and run it but get an error that it cannot find the dll
However I believe it to be the dependency and not the dll it self. I have changed the output directory of the dll to be in the root of where the UW app runs from (\bin\x86) so it really should be finding it. So like I said I think its the dependencies and not the actual dll.
Here is what I see in Dependency Walker
But I have installed all c++ packages I can get my hands on so I dont understand how to get the missing dependencies. Plus this is just a hello world, why do I need all these libraries.
FYI
My dll project is NOT referenced by the UW app. Im not sure thats needed or not? I dont think so though since this a runtime thing, so as long as the dll is there it should find it and read it. But regardless if I do try to add the project as a reference I get this error:

The biggest help to me was finding these method declarations (not even in the class)
extern "C" {
__declspec(dllexport) int getPageSize()
{
SYSTEM_INFO siSysInfo;
GetSystemInfo(&siSysInfo);
return siSysInfo.dwPageSize;
}
}
extern "C" {
__declspec(dllexport) Windows::Foundation::Collections::IMap<Platform::String^, int> ^getSystemInfo()
{
SYSTEM_INFO siSysInfo;
GetSystemInfo(&siSysInfo);
IMap<String^, int> ^ret =
ref new Platform::Collections::Map<String^, int>;
ret->Insert("oemId", siSysInfo.dwOemId);
ret->Insert("cpuCount", siSysInfo.dwNumberOfProcessors);
ret->Insert("pageSize", siSysInfo.dwPageSize);
ret->Insert("processorType", siSysInfo.dwProcessorType);
ret->Insert("maxApplicationAddress", siSysInfo.lpMinimumApplicationAddress);
ret->Insert("minApplicationAddress", siSysInfo.lpMaximumApplicationAddress);
ret->Insert("activeProcessorMask", siSysInfo.dwActiveProcessorMask);
return ret;
}
but in the end I was creating wrappers for things I didnt need to. in c# you can directly call the native methods without the need for a seperate dll or component project.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace Monitoring
{
public static class NativeCallsWrapper
{
private static SYSTEM_INFO sysInfo = new SYSTEM_INFO();
private static MEMORYSTATUSEX mem = new MEMORYSTATUSEX();
[DllImport("kernel32.dll", SetLastError = false)]
public static extern void GetSystemInfo([In, Out] SYSTEM_INFO Info);
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool GlobalMemoryStatusEx([In, Out] MEMORYSTATUSEX lpBuffer);
static NativeCallsWrapper()
{
GetSystemInfo(sysInfo);
GlobalMemoryStatusEx(mem);
}
[StructLayout(LayoutKind.Explicit)]
public struct SYSTEM_INFO_UNION
{
[FieldOffset(0)]
public UInt32 OemId;
[FieldOffset(0)]
public UInt16 ProcessorArchitecture;
[FieldOffset(2)]
public UInt16 Reserved;
}
public struct SYSTEM_INFO
{
public SYSTEM_INFO_UNION CpuInfo;
public UInt32 PageSize;
public UInt32 MinimumApplicationAddress;
public UInt32 MaximumApplicationAddress;
public UInt32 ActiveProcessorMask;
public UInt32 NumberOfProcessors;
public UInt32 ProcessorType;
public UInt32 AllocationGranularity;
public UInt16 ProcessorLevel;
public UInt16 ProcessorRevision;
}
[StructLayout(LayoutKind.Sequential)]
public class MEMORYSTATUSEX
{
public uint dwLength;
public uint dwMemoryLoad;
public ulong ullTotalPhys;
public ulong ullAvailPhys;
public ulong ullTotalPageFile;
public ulong ullAvailPageFile;
public ulong ullTotalVirtual;
public ulong ullAvailVirtual;
public ulong ullAvailExtendedVirtual;
public MEMORYSTATUSEX()
{
this.dwLength = (uint)Marshal.SizeOf(typeof(MEMORYSTATUSEX));
}
}
public static GeneralStatistics getGeneralStatistics()
{
GeneralStatistics generalStatistics = new GeneralStatistics();
generalStatistics.numberOfProcesses = (int)sysInfo.NumberOfProcessors;
generalStatistics.memoryTotal = mem.ullTotalPhys / 1048;
generalStatistics.memoryInUse = (mem.ullTotalPhys - mem.ullAvailPhys) / 1048;
return generalStatistics;
}
}
}

Related

Bring Window To Foreground When MainWindowHandle Is 0

The following code brings the window to the foreground, if the MainWindowHandle is not 0.
How can I bring a window to the front that has MainWindowHandle = 0?
This is for the Microsoft Excel - Compatibility Checker window that shows a GUI but does not have an icon in the task bar and has MainWindowHandle = 0.
I have no other instances of Excel running.
Add-Type #"
using System;
using System.Runtime.InteropServices;
public class Tricks {
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetForegroundWindow(IntPtr hWnd);
}
"#
$excel = (Get-Process | Where-Object { $_.ProcessName -eq 'EXCEL' }).MainWindowHandle
[void] [Tricks]::SetForegroundWindow($excel)
In Windows Task Manager, I can right click on 'Microsoft Excel - Compatibility Checker' and click on "Bring To Front" and that works. How can I mimic this functionality in Powershell?
Thanks to IInspectable for pointing me in the right direction.
This code gets the real MainWindowHandle value:
$TypeDef2 = #"
using System;
using System.Text;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace Api
{
public class WinStruct
{
public string WinTitle {get; set; }
public int MainWindowHandle { get; set; }
}
public class ApiDef
{
private delegate bool CallBackPtr(int hwnd, int lParam);
private static CallBackPtr callBackPtr = Callback;
private static List<WinStruct> _WinStructList = new List<WinStruct>();
[DllImport("User32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool EnumWindows(CallBackPtr lpEnumFunc, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
private static bool Callback(int hWnd, int lparam)
{
StringBuilder sb = new StringBuilder(256);
int res = GetWindowText((IntPtr)hWnd, sb, 256);
_WinStructList.Add(new WinStruct { MainWindowHandle = hWnd, WinTitle = sb.ToString() });
return true;
}
public static List<WinStruct> GetWindows()
{
_WinStructList = new List<WinStruct>();
EnumWindows(callBackPtr, IntPtr.Zero);
return _WinStructList;
}
}
}
"#
Add-Type -TypeDefinition $TypeDef2 -Language CSharpVersion3
$excelInstance = [Api.Apidef]::GetWindows() | Where-Object { $_.WinTitle.ToUpper() -eq "Microsoft Excel - Compatibility Checker".ToUpper() }
So now using this correct value, I can call the SetForegroundWindow() function:
Add-Type #"
using System;
using System.Runtime.InteropServices;
public class Tricks {
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetForegroundWindow(IntPtr hWnd);
}
"#
[void] [Tricks]::SetForegroundWindow($excelInstance.MainWindowHandle)
I wrote a detailed blog about this on my website.
I've put up a full example on GitHub of how to create an Excel file, edit it and run the above code in a different thread which you have to do because the Excel popup blocks the main thread.

Generic list and static main

using System;
using System.Collections.Generic;
namespace ConsoleApplication74
{
class Program<T>
{
public void Add(T X)
{
Console.WriteLine("{0}", X);
}
static void Main(string[] args)
{
Program<string> MyGeneric = new Program<string>();
MyGeneric.Add("ABC");
Console.Read();
}
}
I have erroe Program does not contain a static 'Main' method suitable for an entry point.
Program.cs properties has Build Action as Compile.
I have no idea what is wrong.
The Main method, or entry point in your program, cannot be in a class that has generic arguments. Your Program class has a T type argument. The C# specification calls this out in section 3.1 under Application Startup:
The application entry point method may not be in a generic class declaration.
You should make a new class instead of trying to use Program:
class Program
{
static void Main(string[] args)
{
MyClass<string> MyGeneric = new MyClass<string>();
MyGeneric.Add("ABC");
Console.Read();
}
}
class MyClass<T>
{
public void Add(T X)
{
Console.WriteLine("{0}", X);
}
}

DllImport is not found C++

I am having trouble with using the DllImport function!
using namespace System;
using namespace System::Runtime::InteropServices;
[DllImport("user32.dll")]
It will show me no attribute when run. I am using a Windows Form with C++. And I am really noob with WindowsForms.
namespace Projekt3{
using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Collections::Generic;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
using namespace System::Runtime::InteropServices;
using namespace System::Threading::Tasks;
using namespace System::IO;
using namespace std;
public ref class next : public System::Windows::Forms::Form
{
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(String sClassName, String sAppName);
[DllImport("user32.dll")]
private static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vk);
[DllImport("user32.dll")]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
public:
next(void)
{
InitializeComponent();
//
//TODO: Konstruktorcode hier hinzufügen.
//
}
public: enum fsmodifiers
{
NOMOD = 0x0000,
ALT = 0x0001,
CTRL = 0x0002,
SHIFT = 0x0004,
WIN = 0x0008,
};
Your code works perfectly well, in so far as we can see it. For example, this program
using namespace System;
using namespace System::Runtime::InteropServices;
[DllImport("user32.dll")]
extern int MessageBox(System::IntPtr hwnd, System::String^ text, System::String^ caption,
unsigned int uType);
int main(array<System::String ^> ^args)
{
MessageBox((System::IntPtr)0, "foo", "bar", 0);
return 0;
}
produces the expected message box.
It is very much worth pointing out that using p/invoke from C++/CLI seems like a very pointless exercise. You can link to unmanaged code directly. It would be much more natural for this C++/CLI program to be written like so:
#include <Windows.h>
int main(array<System::String ^> ^args)
{
MessageBoxA(0, "foo", "bar", MB_OK);
return 0;
}

error C2664 cannot convert parameter 1 from 'std::string (__thiscall ClassName::* )(std::string)' to 'std::string (__cdecl *)(std::string)

I'm making a unmanaged application to handle an event fired in c# here.
FYI:: I want to handle a custom event when my Name property in C# class is changed.
I have gone through the following links:
Explanation about passing pointer to member function as parameter
Something similar to my problem.But couldn't understand the solution
Now,
In NativeApp.cpp,I have a member function which is passed as a function pointer as parameter in a method present in the c++/CLI wrapper
//NativeApp.cpp
std::string Class1::FunctionToBePointed(std::string msg)
{
return msg;
}
void Class1::NativeMethod()
{
UnmanagedWrapperClass* unmanagedWrapperClass=new UnmanagedWrapperClass();
unmanagedWrapperClass->WrapperMethod(&Class1::FunctionToBePointed,"Hello")
}
In Wrapper.h,
//Wrapper.h
class __declspec(dllexport) UnmanagedWrapperClass
{
boost::signals2::signal<void(std::string)>signalEvent;
void WrapperMethod(std::string (*GetCallBack)(std::string),std::string value);
}
When I call the WrapperMethod from NativeApp.cpp,
I subscribe my EventHandlerWrapper to a c# event
connect the function pointer to my boost signal signalEvent.
Set the Name property of the CSharp Class
When the Name Property is set, c# event is fired, EventHandlerWrapper method in Wrapper.cpp is executed.Looks like this::
void EventHandlerWrapper(string value)
{
if(signalEvent.connected())
{
signalEvent(value);
}
For some reasons I can't make my FunctionToBePointed(std::string) method as a non-member function.
P.S:: All ears for any other design approach.
In your real use-case can you simply make FunctionToBePointed a static method?
static std::string Class1::FunctionToBePointed(std::string msg)
{
return msg;
}
If yes your code should work.
The reason is that instance methods are implicitly called with an hidden this pointer, this is the thiscall calling convention, whereas static methods simply use the cdecl convention because they don't work on any instance.
EDIT:
A sample with Boost::bind:
The MyClass C# class:
using System;
using System.ComponentModel;
public class MyClass : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged = delegate{};
private string name;
public string Name
{
get
{
return name;
}
set
{
if (name != value)
{
name = value;
PropertyChanged(this, new PropertyChangedEventArgs("Name"));
}
}
}
}
The C++/CLI wrapper:
Wrapper.h:
class WrapperPrivateStuff;
class __declspec(dllexport) UnmanagedWrapperClass
{
private: WrapperPrivateStuff* _private;
public: void changeIt(std::string newName);
public: void WrapperMethod(boost::function<std::string(std::string)> GetCallBack);
public: UnmanagedWrapperClass();
};
Wrapper.cpp:
#using "MyClass.dll"
#include <boost/signals2.hpp>
#include <boost/bind.hpp>
#include "Wrapper.h"
#include <msclr\auto_gcroot.h>
#include <msclr\marshal_cppstd.h>
#include <msclr\event.h>
class WrapperPrivateStuff
{
public: boost::signals2::signal<void(std::string)>signalEvent;
public: msclr::auto_gcroot<MyClass^> a;
public: void EventHandlerWrapper(System::Object^, System::ComponentModel::PropertyChangedEventArgs^ args)
{
this->signalEvent(msclr::interop::marshal_as<std::string>(a->Name));
}
public: WrapperPrivateStuff()
{
a = gcnew MyClass();
a->PropertyChanged += MAKE_DELEGATE(System::ComponentModel::PropertyChangedEventHandler, EventHandlerWrapper);
}
BEGIN_DELEGATE_MAP(WrapperPrivateStuff)
EVENT_DELEGATE_ENTRY(EventHandlerWrapper, System::Object^, System::ComponentModel::PropertyChangedEventArgs^)
END_DELEGATE_MAP()
};
void UnmanagedWrapperClass::changeIt(std::string newName)
{
this->_private->a->Name = msclr::interop::marshal_as<System::String^>(newName);
}
UnmanagedWrapperClass::UnmanagedWrapperClass()
{
this->_private = new WrapperPrivateStuff();
}
void UnmanagedWrapperClass::WrapperMethod(boost::function<std::string(std::string)> GetCallBack)
{
_private->signalEvent.connect(GetCallBack);
}
And the native application, test.cpp:
#include <iostream>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include "Wrapper.h"
class Class1
{
private: std::string name;
public: Class1(std::string name)
: name(name)
{
}
public: std::string FunctionToBePointed(std::string msg)
{
std::cout << "Hey it's " << name << "! Got: " << msg << std::endl;
return msg;
}
};
int main(void)
{
UnmanagedWrapperClass wrapper;
Class1 class1("Ed");
wrapper.WrapperMethod(boost::bind(&Class1::FunctionToBePointed, &class1, _1));
wrapper.changeIt("azerty");
return 0;
}
Result:
>test.exe
Hey it's Ed! Got: azerty
I have a more generic solution but it is really ugly. :(
Let me know if this fix your issue...

How to use Classes As List Collection in Azure AppFabric Caching

H,
I am using the Windows Azure AppFabri Caching.
I have two project in asp.ne t .
One to put data in cache and 2nd to read that cache. These Two project are running on 2 different systems.
I have 4 dll included in these projects.
Microsoft.WindowsFabric.Common.dll
Microsoft.WindowsFabric.Data.Common.dll
Microsoft.ApplicationServer.Caching.Client.dll
Microsoft.ApplicationServer.Caching.Core.dll
Poject 1: To insert data in cache is using the following code:Data is saving to cache successfully
Default.aspx.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Microsoft.ApplicationServer.Caching;
public partial class Default2 : System.Web.UI.Page
{
public class Employee
{
public string Name { get; set; }
public decimal Salary { get; set; }
}
protected static DataCacheFactory _factory = null;
protected static DataCache _cache = null;
protected void Page_Load(object sender, EventArgs e)
{
PutDataIntoCache();
}
protected void PutDataIntoCache()
{
List<Employee> emp = new List<Employee>();
try
{
emp.Add(new Employee { Name = "James", Salary = 20000 });
PutCacheItem("55", emp);
}
catch (Exception ex)
{
}
}
protected void PutCacheItem(string key, object value)
{
try
{
_cache = GetDefaultCache();
_cache.Put(key, value);
}
catch (Exception ex)
{
}
}
protected static DataCache GetDefaultCache()
{
_factory = new DataCacheFactory();
_cache = _factory.GetDefaultCache();
return _cache;
}
}
Now I am reading the cache in another project that is running on another system.
Code is given below:
default.aspx.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Microsoft.ApplicationServer.Caching;
public partial class Default2 : System.Web.UI.Page
{
protected static DataCacheFactory _factory = null;
protected static DataCache _cache = null;
protected void Page_Load(object sender, EventArgs e)
{
GetDataFromCache();
}
protected void GetDataFromCache()
{
_cache = GetDefaultCache();
string key = "55";
var item = _cache.Get(key);// Error is generation here
}
protected static DataCache GetDefaultCache()
{
_factory = new DataCacheFactory();
_cache = _factory.GetDefaultCache();
return _cache;
}
}
An error is generating on the line _cache.Get(key)
The deserializer cannot load the type to deserialize because type 'System.Collections.Generic.List`1[[_Default2+Employee, App_Web_4xzswv4j, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]]' could not be found in assembly 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. Check that the type being serialized has the same contract as the type being deserialized and the same assembly is used.
Why this error is coming?
How can Can I uses Classes as List collection to add/read in Cache.
I believe the problem is that your second project doesn't define the Employee class. You should really define a class library with Employee in it and reference that same assembly from both projects.
The way you've set these projects up, then I think ASP is compiling these code-behind pages into temporary assemblies - i.e. the Employee class is defined as being in the assembly App_Web_4xzswv4j, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Instead, you should put these classes into a class library which can be shared between the projects - this will then have a fixed name, rather than a unique name for each compilation.
As an aside, I think you should also mark your Employee as serializable in order to ensure that it can be serialized and deserialized.

Resources