Set DllImport attribute dynamically - c#

I am making use of an external unmanaged dll using PInvoke and the DllImport attribute. eg.
[DllImport("mcs_apiD.dll", CharSet = CharSet.Auto)]
private static extern byte start_api(byte pid, byte stat, byte dbg, byte ka);
I am wondering if it is possible to alter the dll file details (mcs_apiD.dll in this example) dynmically in some manner, if for instance I wanted to build against another dll version

Yes this is possible, you'll have to do part of the job that the P/Invoke marshaller does. Loading the DLL and finding the entry point of the exported function. Start by declaring a delegate whose signature matches the exported function:
private delegate byte start_api(byte pid, byte stat, byte dbg, byte ka);
Then use code like this:
using System.ComponentModel;
using System.Runtime.InteropServices;
...
static IntPtr dllHandle;
...
if (dllHandle == IntPtr.Zero) {
dllHandle = LoadLibrary("mcs_apiD.dll");
if (dllHandle == IntPtr.Zero) throw new Win32Exception();
}
IntPtr addr = GetProcAddress(dllHandle, "_start_api#16");
if (addr == IntPtr.Zero) throw new Win32Exception();
var func = (start_api)Marshal.GetDelegateForFunctionPointer(addr, typeof(start_api));
var retval = func(1, 2, 3, 4);
...
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr LoadLibrary(string name);
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
private static extern IntPtr GetProcAddress(IntPtr hModule, string name);
Lots of ways to get this wrong of course. Do note that you have to use the actual exported name from the DLL, you no longer get the help from the P/Invoke marshaller to help with name decoration. Use dumpbin.exe /exports on the DLL if you are not sure what the export name looks like.

you can't change the name of the dll but you can alter the path of the library being loaded (like by reading it from the registry or a configuration file) and load it manually with LoadLibrary kernel32's function: see my answer there.

Related

Send data to Excel file using DDE

I know DDE is old fashion outdated technology. But I am creating a C# Windows Form application to send data to Excel file for research purpose. I use Win32 DDE functions and below is what I have tried so far.
Pinvoke signatures:
[DllImport("user32.dll", EntryPoint = "DdeInitialize")]
public static extern int DdeInitialize(out uint pidInst, IntPtr pfnCallback, IntPtr afCmd, IntPtr ulRes);
[DllImport("user32.dll", EntryPoint = "DdeConnect")]
private static extern IntPtr DdeConnect(uint idInst, IntPtr hszService, IntPtr hszTopic, IntPtr pCC);
[DllImport("user32.dll", EntryPoint = "DdeCreateStringHandle")]
private static extern IntPtr DdeCreateStringHandle(uint idInst, string psz, int iCodePage);
public Form1()
{
InitializeComponent();
Process application = new Process();
application.StartInfo.FileName = #"C:\Users\xxx\Desktop\DDE_Client.xlsx";
application.Start();
uint instId;
DdeInitialize(out instId, application.MainWindowHandle, IntPtr.Zero, IntPtr.Zero);
IntPtr sPtr = DdeCreateStringHandle(instId, "Excel", 1004);
IntPtr tPtr = DdeCreateStringHandle(instId, "Sheet1", 1004);
IntPtr channel = DdeConnect(instId, sPtr, tPtr, (IntPtr)null);
}
DdeConnect returns non-zero value which indicates the connection is successful.
My question:
How to send a string value to the excel sheet? For example, I want to send "Name" to excel cell A1. Which DDE function should I use for the task?
You are trying to use DDEML and it is indeed hard to find decent DDEML examples because many people who actually needed to use DDE had done so directly using raw Windows Messages.
You will have to first start client transaction using DdeClientTransaction and then corresponding api like DdeGetData or DdeAddData, DdeAccessData etc to access or get the data.
You can find more details about DDEML in the MS Documentation here.
But since you are already using C# I highly recommend that it would be much better to just add a reference to the Microsoft Excel or Office Object Library in COM Assemblies section and use Microsoft.Office.Interop.Excel;
using Microsoft.Office.Interop.Excel;
Excel.Application xlApp = new Microsoft.Office.Interop.Excel.Application();

Xamarin Android: What is the correct way to Marshal a string from C# to a Unicode string in C++?

I am writing a Xamarin Android app and trying to also write a C++ native library that the Xamarin app needs to pass data to. I need to pass a Unicode string to the library, but I am getting some strange behavior when I try.
In my native shared library, I have the following code:
extern "C" void logANSI(const char* data) {
__android_log_print(ANDROID_LOG_INFO, "StringMarshaling", "ANSI data: %s", data);
}
extern "C" void logUnicode(const wchar_t* data) {
__android_log_print(ANDROID_LOG_INFO, "StringMarshaling", "Unicode data: %ls", data);
}
On the C# side, I have the following DllImport declarations:
[DllImport("StringMarshaling", EntryPoint = "logANSI", SetLastError = true, CharSet = CharSet.Ansi, ThrowOnUnmappableChar = true)]
public static extern void LogANSI([MarshalAs(UnmanagedType.LPStr)] string data);
[DllImport("StringMarshaling", EntryPoint = "logUnicode", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern void LogUnicode([MarshalAs(UnmanagedType.LPWStr)] string data);
Then I have the following code in my Activity:
StringMarshaling.LogANSI("12345");
StringMarshaling.LogUnicode("12345");
In the log output, I see:
05-17 18:07:12.437 Unitech PA700 Info 8351 StringMarshaling ANSI data: 12345
05-17 18:07:12.437 Unitech PA700 Info 8351 StringMarshaling Unicode data: 1
How can I get the full string, and not just the first character?
__android_log_print accepts a char *, so:
Using this C/C++ function:
extern "C" void logUnicode(const wchar_t* data) {
std::wstring fooStr = std::wstring(data);
__android_log_print(ANDROID_LOG_INFO, "StringMarshaling", "Unicode data: %s", fooStr.c_str());
}
With this DllImport:
[DllImport("StringMarshaling", EntryPoint = "logUnicode", SetLastError = true)]
public static extern void LogUnicode(string data);
Calling:
StringMarshaling.LogUnicode("1🍣2🍣3🍣4🍣5");
Will result in:
[StringMarshaling] Unicode data: 1🍣2🍣3🍣4🍣5

How to shorten a path in c# and keep it valid

I work in a place where directories have such a looong name and are in such a looong tree.
And I'm having problems with too long path names for folders in an external applicatoin (I can't change this external application, but I can give it shortened path names).
I know Microsoft operating systems can shorten path names such as transforming C:\TooLongName\TooLongSubDirectory in something like C:\TooLon~1\TooLon~1.
But how can I do this in C# and still keep the nave valid and usable?
PS: I'm not using the standard FileInfo and DirectoryInfo classes, I'm using just strings that will be sent to an external application that I cannot change in any way.
If you are unable to use the long path support build into Windows 10 you are able to use the Win32 command GetShortPathName . In order to generate a suitable path.
class Program
{
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern uint GetShortPathName(
[MarshalAs(UnmanagedType.LPTStr)]
string lpszLongPath,
[MarshalAs(UnmanagedType.LPTStr)]
StringBuilder lpszShortPath,
uint cchBuffer);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern uint GetShortPathName(string lpszLongPath, char[] lpszShortPath, int cchBuffer);
static void Main(string[] args)
{
StringBuilder builder = new StringBuilder(260);
var shortPath = GetShortPathName(#"C:\Projects\Databases\ReallllllllllllllyLOOOOOOOOOOOOOOOOOOOOOONGPATHHHHHHHHHHH\StillllllllllllllllllGOoooooooooooooooooooooooing", builder, (uint)builder.Capacity);
Console.WriteLine(builder.ToString());
Console.ReadKey();
}
}
Produces C:\Projects\DATABA~1\REALLL~1\STILLL~1

Create DLL in C++ and using in C# with BSTR* return function

I'm meeting the problem when creating DLL in C++ and using in C# with an array of String.
Here is my DLL code in c++, Im creating info.dll
extern "C" { __declspec(dllexport) BSTR* GetInfos()
{
string result1 = "ABC", result2="DEF";`
BSTR* MyBstr = new BSTR[2];
MyBstr[0] = SysAllocString(CA2W(result1.c_str()));
MyBstr[1] = SysAllocString(CA2W(result2.c_str()));
return MyBstr;
}
}
In c# code, Im creating DLL import to get this Function in class getInfoFromDll:
[DllImport("info.dll", CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
[return: MarshalAs(UnmanagedType.BStr)]
static extern string[] GetInfos();
I can't get any results when call GetInfos() from my DLL.
String[] s = getInfoFromDll.GetInfos();

How to add an icon to an existing exe file (without an icon by default)?

When I was searching on Google I found a useful class which let us change the icon of any .exe file using the following line of code :
WindowsFormsApplication1.IconInjector.InjectIcon("myfile.exe", "myicon.ico", 200, 1);
Where 200 and 1 are respectively icon GroupID and icon BaseID which I can determine using Resource Hacker. In this case the file's icon changes successfully without corrupting the file.
So i planned to use this class on my program which is a SFX / Software protector, the output file always hasn't an icon, all what I can see on Resource hacker is the below :
i can't see icon group id nor the base id, anyway, (I don't know what to put instead of 200 and 1 in this case) So I tried to change the icon using the same line of code mentioned above, I used the following line of code (same as above):
WindowsFormsApplication1.IconInjector.InjectIcon("myfile.exe", "myicon.ico", 200, 1);
The file icon was successfully changed but the file doesn't work anymore!
When I tried to reopen the file using ResourceHacker, I found the below:
It seems that the icon resources were successfully added, but i can't figure out why the file doesn't work anymore, it seems that is corrupted.
Any help would be appreciated.
Note : I tried using this class with unprotected file and it works like a charm!
The class I am using is the below:
// IconInjector.cs
using System;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace WindowsFormsApplication1
{
/// <summary>
/// IconInjectorクラスの定義
/// </summary>
public class IconInjector
{
[DllImport("kernel32.dll", SetLastError = true)]
//static extern bool UpdateResource(IntPtr hUpdate, string lpType, string lpName, ushort wLanguage, IntPtr lpData, uint cbData);
static extern int UpdateResource(IntPtr hUpdate, uint lpType, uint lpName, ushort wLanguage, byte[] lpData, uint cbData);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr BeginUpdateResource(string pFileName,
[MarshalAs(UnmanagedType.Bool)]bool bDeleteExistingResources);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool EndUpdateResource(IntPtr hUpdate, bool fDiscard);
/// <summary>
/// アプリケーションのメイン エントリ ポイントです。
/// </summary>
[STAThread]
public static void InjectIcon(string execFileName, string iconFileName, uint iconGroupID, uint iconBaseID)
{
const uint RT_ICON = 3;
const uint RT_GROUP_ICON = 14;
// アイコンファイルの読み込み
IconFile iconFile = new IconFile();
iconFile.Load(iconFileName);
// リソースの更新開始
IntPtr hUpdate = BeginUpdateResource(execFileName, false);
Debug.Assert(hUpdate != IntPtr.Zero);
// RT_GROUP_ICON 書き込み
byte[] data = iconFile.CreateIconGroupData(iconBaseID);
UpdateResource(hUpdate, RT_GROUP_ICON, iconGroupID, 0, data, (uint)data.Length);
// RT_ICON書き込み
for (int i = 0; i < iconFile.GetImageCount(); i++)
{
byte[] image = iconFile.GetImageData(i);
UpdateResource(hUpdate, RT_ICON, (uint)(iconBaseID + i), 0, image, (uint)image.Length);
}
// リソースの更新終了
EndUpdateResource(hUpdate, false);
}
}
}
Any help or suggestion on adding the icon to the protected file without corrupting it?
It sounds like the protection application is verifying that the contents of the file haven't been tampered with. Injecting an icon is definitely a form of tampering, and unless the protection software is updated to ignore it, it will always fail. Alternatively if you own the protection software you could update it to not strip the icons.
I just experienced the same issue with a 7zip Self-Extractor exe.
Updating the icon of the 7zS.sfx (instead of the exe) before creating the Self-Extractor exe does the trick and the exe is not corrupted.
Your application's icon can be added to this executable with a tool like Resource Hacker.
and visit http://georezo.net/jparis/MI_Enviro/Icons/adding_w_RH.htm

Categories