I have entered this code in my Program.cs file.
AppContainer container = new AppContainer();
But when I try to debug it, it shows like this.
Anyone know how to solve this?
Consider using a nuget package to include the dependency for you.
Alternatively you could import the DLL manually using [DllImport("Win32Interop.User32").
Here's an excerpt from MSDN showing how to manually import and define methods to use from an imported DLL
using System;
using System.Runtime.InteropServices;
class Example
{
// Use DllImport to import the Win32 MessageBox function.
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern int MessageBox(IntPtr hWnd, String text, String caption, uint type);
static void Main()
{
// Call the MessageBox function using platform invoke.
MessageBox(new IntPtr(0), "Hello World!", "Hello Dialog", 0);
}
}
Related
I am learning C# from my C++/CLR background by rewriting a sample C++/CLR project in C#.
The project is a simple GUI (using Visual Studio/ Windows Forms) that performs calls to a DLL written in C (in fact, in NI LabWindows/CVI but this is just ANSI C with custom libraries). The DLL is not written by me and I cannot perform any changes to it because it is also used elsewhere.
The DLL contains functions to make an RFID device perform certain functions (like reading/writing RFID tag etc). In each of these functions, there is always a call to another function that performs writing to a log file. If the log file is not present, it is created with a certain header and then data is appended.
The problem is: the C++/CLR project works fine.
But, in the C# one, the functions work (the RFID tag is correctly written/read etc.) but there is no activity regarding the log file!
The declarations for DLL exports look like this (just one example, there are more of them, of course):
int __declspec(dllexport) __stdcall Magnetfeld_einschalten(char path_Logfile_RFID[300]);
int save_Logdatei(char path_Logdatei[], char Funktion[], char Mitteilung[]);
The save_Logdatei function is called during execution of Magnetfeld_einschalten like this:
save_Logdatei(path_Logfile_RFID, "Magnetfeld_einschalten", "OK");
In the C++/CLR project, I declared the function like this:
#ifdef __cplusplus
extern "C" {
#endif
int __declspec(dllexport) __stdcall Magnetfeld_einschalten(char path_Logfile_RFID[300]);
#ifdef __cplusplus
}
#endif
then a simple call to the function is working.
In the C# project, the declaration goes like:
[DllImport("MyDLL.dll", CallingConvention = CallingConvention.StdCall, EntryPoint = "Magnetfeld_einschalten", CharSet = CharSet.Ansi, ExactSpelling = false)]
private static extern int Magnetfeld_einschalten(string path_Logfile_RFID);
and, as I said, although the primary function is working (in this case, turning on the magnetic field of the RFID device), the logging is never done (so, the internal DLL call to save_Logdatei is not executing correctly).
The relevant code in the Form constructor is the following:
pathapp = Application.StartupPath;
pathlog = string.Format("{0}\\{1:yyyyMMdd}_RFID_Logdatei.dat", pathapp, DateTime.Now);
//The naming scheme for the log file.
//Normally, it's autogenerated when a `save_Logdatei' call is made.
Magnetfeld_einschalten(pathlog);
What am I missing? I have already tried using unsafe for the DLL method declaration - since there is a File pointer in save_Logdatei - but it didn't make any difference.
===================================EDIT==================================
Per David Heffernan's suggestion, i have tried to recreate the problem in an easy to test way. For this, i have created a very simple DLL ("test.dll") and I have stripped it completely from the custom CVI libaries, so it should be reproducible even without CVI. I have uploaded it here. In any case, the code of the DLL is:
#include <stdio.h>
int __declspec(dllexport) __stdcall Magnetfeld_einschalten(char path_Logfile_RFID[300]);
int save_Logdatei(char path_Logdatei[], char Funktion[], char Mitteilung[]);
int __declspec(dllexport) __stdcall Magnetfeld_einschalten(char path_Logfile_RFID[300])
{
save_Logdatei(path_Logfile_RFID, "Opening Magnet Field", "Success");
return 0;
}
int save_Logdatei(char path_Logdatei[], char Funktion[], char Mitteilung[])
{
FILE *fp; /* File-Pointer */
char line[700]; /* Zeilenbuffer */
char path[700];
sprintf(path,"%s\\20160212_RFID_Logdatei.dat",path_Logdatei);
fp = fopen (path, "a");
sprintf(line, "Just testing");
sprintf(line,"%s %s",line, Funktion);
sprintf(line,"%s %s",line, Mitteilung);
fprintf(fp,"%s\n",line);
fclose(fp);
return 0;
}
The C# code is also stripped down and the only thing i have added to the standard Forms project, is Button 1 (and the generated button click as can be seen). The code is this:
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace TestDLLCallCSharp
{
public partial class Form1 : Form
{
public int ret;
public string pathapp;
public string pathlog;
[DllImport("test", CallingConvention = CallingConvention.StdCall, EntryPoint = "Magnetfeld_einschalten", CharSet = CharSet.Ansi, ExactSpelling = false)]
private static extern int Magnetfeld_einschalten(string path_Logfile_RFID);
public Form1()
{
pathapp = #"C:\ProgramData\test";
pathlog = string.Format("{0}\\20160212_RFID_Logdatei.dat", pathapp);
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
ret = Magnetfeld_einschalten(pathlog);
}
}
}
As can be seen, I have avoided using an automatic naming scheme for the log file (normally i use the date) and in both the dll and the C# code, the log file is "20160212_RFID_Logdatei.dat". I have also avoided using the app path as the directory where to put the log file and instead I have opted for a folder named test i created in ProgramData
Again, no file is created at all
This looks like a simple typo in your calling code. Instead of:
ret = Magnetfeld_einschalten(pathlog);
you mean to write:
ret = Magnetfeld_einschalten(pathapp);
In the C# code, these two strings have the following values:
pathapp == "C:\ProgramData\\test"
pathlog == "C:\ProgramData\\test\\20160212_RFID_Logdatei.dat"
When you pass pathlog to the unmanaged code it then does the following:
sprintf(path,"%s\\20160212_RFID_Logdatei.dat",path_Logdatei);
which sets path to be
path == "C:\\ProgramData\\test\\20160212_RFID_Logdatei.dat\\20160212_RFID_Logdatei.dat"
In other words you are appending the file name to the path twice instead of once.
An extensive overview for P/Invoke in C# is given in Platform Invoke Tutorial - MSDN Library.
The problematic bit is you need to pass a fixed char array rather than the standard char*. This is covered in Default Marshalling for Strings.
The gist is, you need to construct a char[300] from your C# string and pass that rather than the string.
For this case, two ways are specified:
pass a StringBuilder instead of a string initialized to the specified length and with your data (I omitted non-essential parameters):
[DllImport("MyDLL.dll", ExactSpelling = true)]
private static extern int Magnetfeld_einschalten(
[MarshalAs(UnmanagedType.LPStr)] StringBuilder path_Logfile_RFID);
<...>
StringBuilder sb = new StringBuilder(pathlog,300);
int result = Magnetfeld_einschalten(sb);
In this case, the buffer is modifiable.
define a struct with the required format and manually convert your string to it:
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
struct Char300 {
[MarshalAs(UnmanagedType.ByValTStr,SizeConst=300)]String s;
}
[DllImport("MyDLL.dll")]
private static extern int Magnetfeld_einschalten(Char300 path_Logfile_RFID);
<...>
int result = Magnetfeld_einschalten(new Char300{s=pathlog});
You can define an explicit or implicit cast routine to make this more straightforward.
According to UnmanagedType docs, UnmanagedType.ByValTStr is only valid in structures so it appears to be impossible to get the best of both worlds.
The String is in Unicode format, convert it to byte[]
Encoding ec = Encoding.GetEncoding(System.Threading.Thread.CurrentThread.CurrentCulture.TextInfo.ANSICodePage);
byte[] bpathlog = ec.GetBytes(pathlog);
and change parameter type to byte[]
[DllImport("MyDLL.dll", CallingConvention = CallingConvention.StdCall, EntryPoint = "Magnetfeld_einschalten", CharSet = CharSet.Ansi, ExactSpelling = false)]
private static extern int Magnetfeld_einschalten(byte[] path_Logfile_RFID);
For me it is working
JSh
I am trying to use a DLL that was writen in C++ but my application is in C#
The DLL is from another company but they have supplied an SDK for their software.
They give an example of how to load their DLL in C++ but I need to adapt it to C#.
Below is their instructions of how to do it in C++
MarkEzd.dll file is Dynamic Link Library.
MarkEzdDll.h is header file of the exports function in MarkEzd.dll
The calling way of MarkEzd.dll is explicitly link. Developer needs to load and free MarkEzd.dll by calling Windows API function.
The steps are as follows.
Call Windows’ API function LoadLibrary() to load DLL dynamically;
Call Windows’ API function GetProcAddrress() to get the pointer of the functions in the DLL and use the function pointer to finish the work;
Call Windows’ API function FreeLibrary() to release library when you do not use DLL or the program ends.
Below is the example they have provided.
Step 2. Program software for calling markezd.dll.
a) First step : Dynamic Load MarkEzd.dll
HINSTANCE hEzdDLL = LoadLibrary(_T("MarkEzd.dll"));
b) Second step: get the pointer of the function to be called
lmc1_Initial=(LMC1_INITIAL)GetProcAddress(hEzdDLL, _T("lmc1_Initial"));
lmc1_Close=(LMC1_CLOSE)GetProcAddress(hEzdDLL, _T("lmc1_Close"));
lmc1_LoadEzdFile=(LMC1_LOADEZDFILE)GetProcAddress(hEzdDLL,_T("lmc1_LoadEzdFile"));
lmc1_Mark=(LMC1_MARK)GetProcAddress(hEzdDLL,_T("lmc1_Mark"));
c) Third step: Call the function
1) Initialization lmc1 board: lmc1_Initial().
2) Open test.ezd: lmc1_LoadEzdFile(_T(“test.ezd”)).
3) Call lmc1_Mark() for machining: lmc1_Mark().
4) Close lmc1 board: lmc1_Close().
d) Fourth step, Release markezd.dll: FreeLibrary(hEzdDLL)
Bellow is the descriptions of the commands.
lmc1_Initial
INTENTION: initialize lmc1 control board
DEFINITION: int lmc1_Initial(TCHAR* strEzCadPath, BOOL bTestMode, HWND hOwenWnd)
strEzCadPath: the full path where ezcad2.exe exists
bTestMode Whether in test mode or not
hOwenWnd: The window that has the focus. It is used to check the user’s stop messages.
DESCRIPTION: you must first call lmc1¬_Initial before other function in program.
RETURN VALUE: common error code
lmc1_Close
INTENTION: Close lmc1 board
DEFINITION: int lmc1_Close();
DESCRIPTION: you must call lmc1_Close to close the lmc1 board when exit program.
RETURN VALUE: common error code
lmc1_LoadEzdFile
INTENTION: open the appointed ezd file, and clear all the object in database.
DEFINITION: int lmc1_LoadEzdFile(TCHAR* strFileName);
DESCRIPTION: this function can open an ezd file that was build by user as a template. User need not set process parameters, because they will be loaded in from the template file.
RETURN VALUE: common error code
lmc1_Mark
INTENTION: mark all the data in database
DEFINITION: int lmc1_Mark(BOOL bFlyMark);
bFlyMark= TRUE // mark on fly
DISCRIPTION: Begin to mark by calling this function after loading ezd file using lmc1_LoadEzdFile. The function will not return back until marking complete.
RETURN VALUE: common error code
They also explain how to set up VS6.0
Choose “Microsoft Visual C++ 6.0” when install visual studio, and click “Change Option”.
Choose “VC++ MFC and Template Libraries” and click “Change Option”.
Choose “MS Foundation Class Libraries” and click “change option”.
Choose the options as following picture, and click “OK”.
Open the project, choose menu Project->Settings. Choose “C/C++”, add “UNICODE” and delete “MCBS” in “Preprocessor definitions”
Choose “Link”, select “Output” in Category, and add “wWinMainCRTStartup” in “Entry-point symbol”
Change all “char” to “TCHAR” in source code.
Change all character string included by double quotation marks “…” to _T(“…”)
Compile and link the project again.
most of the functions return an integer code of 0 for success.
Would this be correct?
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 System.Runtime.InteropServices;
namespace Start_Mark
{
public partial class Form1 : Form
{
[DllImport("kernel32.dll")]
public static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
[DllImport("kernel32.dll")]
public static extern bool FreeLibrary(IntPtr hModule);
[DllImport("MarkEzd.dll")]
[return: MarshalAs(UnmanagedType.I2)]
public static extern int lmc1_Initial(string strEzCadPath, bool bTestMode, IntPtr hOwenWnd);
[DllImport("MarkEzd.dll")]
[return: MarshalAs(UnmanagedType.I2)]
public static extern int lmc1_Close();
[DllImport("MarkEzd.dll")]
[return: MarshalAs(UnmanagedType.I2)]
public static extern int lmc1_LoadEzdFile(string strFileName);
[DllImport("MarkEzd.dll")]
[return: MarshalAs(UnmanagedType.I2)]
public static extern int lmc1_Mark(bool bFlyMark);
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
IntPtr hEzdDLL = LoadLibrary("MarkEzd.dll");
IntPtr iplmc1_Initial = GetProcAddress(hEzdDLL, "lmc1_Initial");
IntPtr iplmc1_Close = GetProcAddress(hEzdDLL, "lmc1_Close");
IntPtr iplmc1_LoadEzdFile = GetProcAddress(hEzdDLL, "lmc1_LoadEzdFile");
IntPtr iplmc1_Mark = GetProcAddress(hEzdDLL, "lmc1_Mark");
int intlmc1_Initial=lmc1_Initial("c:\temp", false, hEzdDLL);
if (intlmc1_Initial > 0)
{
return;
}
int intlmc1_LoadEzdFile = lmc1_LoadEzdFile("c:\temp\test.ezd");
if (intlmc1_LoadEzdFile > 0)
{
return;
}
int intlmc1_Mark = lmc1_Mark(true);
if (intlmc1_Mark > 0)
{
return;
}
int intlmc1_Close = lmc1_Close();
if (intlmc1_Close > 0)
{
return;
}
FreeLibrary(hEzdDLL);
}
}
}
The correct syntax is as follows.
using System;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace Company.Group
{
public class FuncList
{
[DllImport("MarkEzd.dll", EntryPoint = "lmc1_Initial2", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
public static extern int Initialize(string PathName, bool TestMode);
}
}
Use P-Invoke to call native DLL. You might have to marshall some datatype in order to make it work.
http://msdn.microsoft.com/en-us/library/aa288468.aspx
Hi guys I write a console app:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
using System.Text.RegularExpressions;
namespace ConsoleApplication1
{
class Program
{
public static void Main(String[] args)
{
if (args.Length == 0)
{
Console.WriteLine("No file to upload...");
Environment.Exit(0);
}
else
Console.WriteLine("[~] Trying to upload: " + args[0]);
string name = Regex.Match(args[0], #"[^\\]*$").Value;
ftp ftpClient = new ftp(#"ftp://site.ru/", "dfgd", "QWERTY_123");
ftpClient.upload("www/site.ru/upload/" + name, args[0]);
Console.WriteLine("[+] Upload File Complete");
Console.ReadKey();
}
}
}
How after Console.WriteLine("[+] Upload File Complete"); copy args[0] to clipboard?
First you must add a reference to System.Windows.Forms in your application.
Go to Project -> Add reference, select System.Windows.Forms from .NET tab in the window that just opened.
You must avoid the ThreadStateException by applying the STAThread attribute to your Main() function. Then you can use the Clipboard functions without any problems.
using System;
using System.Windows.Forms;
class Program
{
[STAThread]
static void Main(string[] args)
{
Clipboard.SetText("this is in clipboard now");
}
}
In case you dont want to use the reference to System.Windows.Forms, u can do it via P/Invoke
Platform Invoking the Clipboard APIs is a possible solution. Example:
using System.Runtime.InteropServices;
class Program
{
[DllImport("user32.dll")]
internal static extern bool OpenClipboard(IntPtr hWndNewOwner);
[DllImport("user32.dll")]
internal static extern bool CloseClipboard();
[DllImport("user32.dll")]
internal static extern bool SetClipboardData(uint uFormat, IntPtr data);
[STAThread]
static void Main(string[] args)
{
OpenClipboard(IntPtr.Zero);
var yourString = "Hello World!";
var ptr = Marshal.StringToHGlobalUni(yourString);
SetClipboardData(13, ptr);
CloseClipboard();
Marshal.FreeHGlobal(ptr);
}
}
This is just an example. Adding a little error handling around the code, like checking the return values of the P/Invoke functions would be a good addition.
SetClipboardData is the interesting bit, you also want to make sure you open and close the clipboard, too.
The 13 passed in as the first argument is the data format. 13 means unicode string.
The Marshal.StringToHGlobalUni function actually allocates memory in a fashion unsuitable for SetClipboardData (using LocalAlloc with LMEM_FIXED), which can cause crashes. (You wouldn't expect it given the method name, but stepping into the code e.g. using ReSharper reveals this.) SetClipboardData requires GlobalAlloc with GMEM_MOVABLE according to the docs: SetClipboardData on MSDN.
Here's an MIT licensed System.Windows.Forms alternative, tested and complete with error handling: Clippy
(the clipboard pushing code itself is to be found here: Clippy.cs
You need to use ClipBoard.SetText method
Clipboard.SetText(args[0], TextDataFormat.Text);
I am trying to learn P/Invoke, so I created a simple dll in C++
KingFucs.h:
namespace KingFuncs
{
class KingFuncs
{
public:
static __declspec(dllexport) int GiveMeNumber(int i);
};
}
KingFuns.cpp:
#include "KingFuncs.h"
#include <stdexcept>
using namespace std;
namespace KingFuncs
{
int KingFuncs::GiveMeNumber(int i)
{
return i;
}
}
So it does compile, then I copied this dll into my WPF's debug folder, with code:
[DllImport("KingFuncDll.dll", EntryPoint = "GiveMeNumber", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern int GiveMeNumber(
int i
);
And calling it in button click:
private void Button_Click(object sender, RoutedEventArgs e)
{
int num = GiveMeNumber(123);
}
But it gives me exception:
Unable to find an entry point named 'GiveMeNumber' in DLL
'KingFuncDll.dll'.
Really.... what have I done wrong... It obviously able to find the DLL, otherwise would be another exception. But my method name is exactly the same.... I can't think of other reason.
You need to use extern "C" when you export your function so that you suppress C++ name mangling. And you also should not try to p/invoke to members of a class. Use free functions instead:
extern "C" {
__declspec(dllexport) int GiveMeNumber(int i)
{
return i;
}
}
On the managed side your DllImport attribute is all wrong. Don't use SetLastError which is for Win32 APIs only. Don't bother setting CharSet if there are not text parameters. No need for ExactSpelling. And the calling convention is presumably Cdecl.
[DllImport("KingFuncDll.dll", CallingConvention=CallingConvention.Cdecl)]
public static extern int GiveMeNumber(int i);
The problem is that you are declaring the C++ "function" inside a C++ class and are telling P/Invoke to use StdCall.
Try to declare a C++ function outside a class and and export it like you did. Then your code should work.
If you really must have a C++ function inside a class, take a look at CallingConvention.ThisCall. But then you are responsible for creating your unmanaged class instance and pass it as the first parameter of your P/Invoke call
The entry point name of a dll file is given in .exp file which is found in debug folder where other source files are present. If dumpbin doesn't work you can try this.
I wave a method in C++ that receives a parameter of the LPCOLESTR type. I'm accessing this method through C#, but I can't make the correct conversion between String and this type.
Let's say the method signinature in C++ is:
void Something(LPCOLESTR str)
In C#, I'm trying to call it (all reference issues to access the method through a DLL have been solved already):
String test = "Hello world";
Something(test);
But with no luck, of course. If anyone can help me, I'd be very glad. Thank you!
Code snippet:
As an example, here's my C++ portion of code, defined in the file MixedCodeCpp.h (CLR Class Library)
#include "windows.h"
#pragma once
using namespace System;
namespace MixedCodeCpp
{
public ref class MyClass
{
public:
HRESULT Something(LPCOLESTR str)
{
return S_OK;
}
};
}
And here's my code in C# (I've added a reference to the C++ project in the C# project, through Visual Studio):
StringBuilder sb = new StringBuilder();
sb.Append("Hello world");
MixedCodeCpp.MyClass cls = new MixedCodeCpp.MyClass();
cls.Something(sb);
The argument will appear as Char* on the C# side. That requires unsafe code, like this:
unsafe static void CallSomething(MyClass obj, string arg) {
IntPtr mem = Marshal.StringToCoTaskMemUni(arg);
try {
obj.Something((Char*)mem);
}
finally {
Marshal.FreeCoTaskMem(mem);
}
}
It makes very little sense to expose the LPCOLESTR to other managed code. This method really should accept a String^ and convert to wchar_t* internally.
Try StringBuilder instead of String thusly:
System.Text.StringBuilder test = new System.Text.StringBuilder ();
test.Append("Hello world");
Something(test);
I've used it that way in pinvoke to Win32 functions that required various string pointers as parameters. Not sure it will work with your API but it's worth a shot. Here's some MSDN info about the process. And here is another.
Here's an arbitrary sample of what your import statement and declaration ought to look like. (To be taken with a grain of salt.)
[DllImport(SomeLib.SomeName, CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool Something(StringBuilder pMyString);
StringBuilder str = new StringBuilder(MAX_PATH);
DWORD uSize;
bool b = Something(str);