Is there anyway to call a memory address (like (void*) f = 0xFFFF; ) WITHOUT IntPtr or any native Win32 functions. I need to do this for an executable loader (It is for an OS that uses a open source project called COSMOS)
There is no way to do it in a proper C# high level way without using Marshal.GetDelegateForFunctionPointer:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate void CallMeDelegate(int i);
CallMeDelegate del = (CallMeDelegate)Marshal.GetDelegateForFunctionPointer(new IntPtr(0xffff), typeof(CallMeDelegate));
Note that IntPtr isn't native Windows just because of its name: It is the typical pointer value for the current compilation target (32 or 64 bit).
You don't get around using that API I think, because you have to specify a calling convention for being able to use it in normal C# delegate syntax. Be happy with the fact, that Marshal.GetDelegateForFunctionPointer does all the dirty work for you, platform independently!
Related
I have used NAudio for many years with many versions and have seen this problem from the beginning. I do not care about using the Avid driver as it is unusable anyway. I just do not want the app to crash if someone tries to use it. I can block it out but how many other ASIO drivers are out there with the same problem. Try loops in C# do not catch the exception, just bails out of the app every time. Has anyone seen this before? Here is where it crashes in NAudio.Wave.AsioOut:
private void InitFromGuid(Guid asioGuid)
{
const uint CLSCTX_INPROC_SERVER = 1;
// Start to query the virtual table a index 3 (init method of AsioDriver)
const int INDEX_VTABLE_FIRST_METHOD = 3;
// Pointer to the ASIO object
// USE CoCreateInstance instead of builtin COM-Class instantiation,
// because the AsioDriver expect to have the ASIOGuid used for both COM Object and COM interface
// The CoCreateInstance is working only in STAThread mode.
int hresult = CoCreateInstance(ref asioGuid, IntPtr.Zero, CLSCTX_INPROC_SERVER, ref asioGuid, out pAsioComObject);
if ( hresult != 0 )
{
throw new COMException("Unable to instantiate ASIO. Check if STAThread is set",hresult);
}
// The first pointer at the adress of the ASIO Com Object is a pointer to the
// C++ Virtual table of the object.
// Gets a pointer to VTable.
IntPtr pVtable = Marshal.ReadIntPtr(pAsioComObject);
// Instantiate our Virtual table mapping
asioDriverVTable = new AsioDriverVTable();
// This loop is going to retrieve the pointer from the C++ VirtualTable
// and attach an internal delegate in order to call the method on the COM Object.
FieldInfo[] fieldInfos = typeof (AsioDriverVTable).GetFields();
for (int i = 0; i < fieldInfos.Length; i++)
{
FieldInfo fieldInfo = fieldInfos[i];
// Read the method pointer from the VTable
IntPtr pPointerToMethodInVTable = Marshal.ReadIntPtr(pVtable, (i + INDEX_VTABLE_FIRST_METHOD) * IntPtr.Size);
// Instantiate a delegate
object methodDelegate = Marshal.GetDelegateForFunctionPointer(pPointerToMethodInVTable, fieldInfo.FieldType);
// Store the delegate in our C# VTable
fieldInfo.SetValue(asioDriverVTable, methodDelegate);
}
}
I did find a way to get a very detailed list of all the audio devices on my desktop and whether or not they function. It was a bit convoluted, but it works. I took the latest revision 2.0.1 demo project and striped out everything not needed except my class which gathers the data on all the devices. The latest revision runs in emulator mode and seems to work fine. I am sure it could be done with earlier revisions as well without emulator mode. The only problem is that since the original demo project is a solution itself, I cannot add it to my solution. Nevertheless, I can run it as a separate process and write the data output to the hard drive. I thought maybe the c++ code was crashing the app because it ran on the same thread as the GUI thread but that is not the case. It all runs on the main thread. I guess it to worked because of the Reflection strategy the demo uses.
I am developing a C# dll project with C++ dll project.
Let's say that C++ dll logins to a certain web site, and do some query on the web server.
And C++ dll has to return that html code of a web site.
In the same time, C++ dll must save the cookie data from the web site.
So, I passed StringBuilder object to C++ function.
I already know how to get html code from a web site using HttpWebRequest and HttpWebResponse classed in C#, but unfortunately I have to do it in C++ dll project.
So bear in mind, I don't need any C# codes.
I have tried Passing a string variable as a ref between a c# dll and c++ dll.
Passing StringBuilder from C# and get it as LPTSTR.
It works fine, but some strings were missing from the result.
I couldn't find out the reason.
Anyway, here is my code.
C++
extern "C" __declspec(dllexport) BSTR LoginQuery(const char* UserID, const char* UserPW, char Cookies[])
{
std::string html;
try
{
std::map<std::string, std::string> cookies;
MyClass *myclass = new MyClass();
html = myclass->LoginQuery(UserID, UserPW, cookies);
// Response cookies
std::string cookieData;
for (std::map<std::string, std::string>::iterator iterator = cookies.begin(); iterator != cookies.end(); iterator++)
{
cookieData += iterator->first;
cookieData += "=";
cookieData += iterator->second;
cookieData += ";";
}
sprintf(Cookies, cookieData.c_str(), 0);
delete myclass;
}
catch (...)
{
}
return ::SysAllocString(CComBSTR(html.c_str()).Detach());
}
C#
[DllImport(#"MyDll.dll", EntryPoint="LoginQuery", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.BStr)]
private static extern void LoginQuery(string UserID, string UserPW, StringBuilder Cookies);
void SomeThing()
{
StringBuilder _cookies = new StringBuilder(1024);
string result = LoginQuery("test", "1234", _cookies);
}
It works fine.
With the StringBuilder as cookie, I can carry on the next url of the web site.
(I am using libcurl in C++ project.)
But the problem is that I have about 100 ids.
When it runs about 3~40, it returns heap error.
Debug Assertion Failed!
Program: ~~~~mics\dbgheap.c
Line: 1424
Expression: _pFirstBlock == pHead
I cannot click the abort, retry or ignore button.
It looks like C# application hangs.
I read so many articles about debug assertion failed with dbgheap.
Mostly like free memory object from another heap.
I am newbie to C++.
I read Edson's question on http://bytes.com/topic/c-sharp/answers/812465-best-way-interop-c-system-string-c-std-string.
But the error does not always comes out in certain time.
So I came across with a guess, that it happens when .NET runs garbage collector.
.NET garbage collector tries to free some memory which created from C++ dll and I get the heap error.
Am I right?
I think he's suffering same problem as mine.
What is the best way to avoid heap error and return correct string from C++ dll to C# dll?
P/S: And the heap error occurs only when I run it debug mode. I don't get the error when I run release mode.
EDIT
According to WhozCraig answer, I changed my code as below.
//return ::SysAllocString(CComBSTR(html.c_str()).Detach());
CComBSTR res(html.c_str());
return res.Detach();
But no luck, I still get the heap error.
Your question is title asks about passing a string reference from c# to c++, but later in the text you ask how to return a string from C++ to C#. Also, you tell you are new to C++. With this in mind, I'll tell how I did this sort of interaction last time I had to do that. I just made C++ side allocate and free all the memory, passing out to C# only IntPtrs to be Marshal.PtrToStringAnsi(p)ed. In my case, storing recerences thread-local in C++ and freeing them on each function call was enough, but you can make a C++ function that frees whatever ref it is given. Not very intellectual and not necessarily the most efficient way, but it works.
upd:
It does just what they say it does. Some quick googling comes up with this article. I think it's pretty good, so you can refer to it instead of my suggestion. Passing raw IntPtrs is good if the pointer is not okay to be freed by itself (like old Delphi/C++Builder style strings, for example) and you prefer to be bothered more on the managed side than on the native side.
As an example, piece of code doing Delphi interaction (good for C++ Builder as well):
// function Get_TI_TC(AuraFileName:PAnsiChar; var TI,TC:PAnsiChar):Boolean; stdcall; external 'AuraToIec104.dll' name 'Get_TI_TC';
[DllImport("AuraToIec104")]
[return: MarshalAs(UnmanagedType.I1)]
private static extern bool Get_TI_TC(string AuraFileName, out IntPtr TI, out IntPtr TC);
public static bool Get_TI_TC(string AuraFileName, out string TI, out string TC)
{
IntPtr pTI, pTC;
bool result = Get_TI_TC(AuraFileName, out pTI, out pTC);
TI = Marshal.PtrToStringAnsi(pTI);
TC = Marshal.PtrToStringAnsi(pTC);
return result;
}
It looks like your problem is rather simple. You are creating a StringBuilder that can hold as much as 1024 chars. If your C++ function returns more than that, your application will crash (sooner or later).
So to fix your problem, increase the StringBuilder's size to the maximum possible output length. More details: Passing StringBuilder to PInvoke function which quotes:
The only
caveat is that the StringBuilder must
be allocated enough space for the
return value, or the text will
overflow, causing an exception to be
thrown by P/Invoke.
It might actually be better in your case with dynamic string lengths to use a BSTR parameter in the C++ function. You can then use [MarshalAs(UnmanagedType.AnsiBStr), Out] ref string ... in C# and BSTR* in C++.
I have an API function in my application:
<Runtime.InteropServices.DllImport("kernel32.dll", SetLastError:=True, CharSet:=Runtime.InteropServices.CharSet.Ansi, ExactSpelling:=True)>
Private Shared Function GetProcAddress(ByVal hModule As IntPtr, ByVal procName As String) As IntPtr
End Function
I just want to learn the pointer 'IntPtr' value of this function. How can I do it?
Note: I will show you the exact thing that I want in C++
void* fnGetProcAddress;
fnGetProcAddress = GetProcAddress;
Well, you can continue using P/Invoke...
(Note, this is in C#, but easily convertible)
[System.Runtime.InteropServices.DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
[System.Runtime.InteropServices.DllImport("kernel32.dll")]
public static extern IntPtr GetModuleHandle(string moduleName);
var hModule = GetModuleHandle("kernel32.dll");
var procAddress = GetProcAddress(hModule, "GetProcAddress");
I want to get this address and write it in a BinaryStream as UInt32
This is a very troublesome plan. Short from the wrong data type, you have no guarantees whatsoever that the address you write is still valid when you read the stream:
The DLL might simply not be loaded when you read the stream. It does require making the LoadLibrary() call to get it in the process. So at a very minimum you'd also have to serialize the DLL path.
DLLs do not promise to get loaded at the exact same address again. The load address embedded in the DLL header is merely a request, it is very common that the requested address is already in use by another DLL, forcing Windows to relocate the DLL. That relocated address is not predictable. A far bigger problem is that relocation is intentionally done on modern Windows versions. A feature called Address Space Layout Randomization, enabled when the DLL was linked with the /DYNAMICBASE linker option. It is an anti-malware feature, making it intentionally hard for malware to patch code.
Surely there's a better way to do what you want to do. You however made the common mistake of not explaining your reasons, it is impossible to guess at.
I'm exploring the idea of building a bridge between a DLL plugin for a 3rd party app and a C# app. I'm writing both the plugin DLL and the C# application. The plugin will be loaded into the 3rd party app and then I want to use call the plugin from C# to indirectly get data from the 3rd party app.
I am able to successfully call an exported function from the DLL from C#. For example:
C++ DLL:
extern "C" __declspec(dllexport) char * HelloFromDll()
{
char *result;
result = "Hello from my DLL";
return result;
}
C#:
using System.Runtime.InteropServices;
[DllImport(#"MyDll.dll")]
private static extern string HelloFromDll();
I can then call this DLL function from C# and display the string in the UI. However, as soon as I create an export function that calls a function from my 3rd party app, I get an AccessViolationException. For example,
extern "C" __declspec(dllexport) char * GetData()
{
char *result;
result = 3rdPartyLibrary::SomeFunction();
return result;
}
Through some testing, the error seems to occur as soon as I make a call to a 3rd party function. How can I fix this?
This function is very difficult to use in a C program as well. Returning strings from functions is a poorly supported scenario. There's a memory management problem, it isn't clear who owns the string. In most cases the caller is expected to take ownership of the string and free it after using it. That's not going to work out well for your function, the program will crash since you returned a string literal.
The .NET pinvoke marshaller needs to solve this problem as well. With the extra problem that it cannot use the allocator that's used by the C code. It is going to call CoTaskMemFree (the COM allocator). That causes an undiagnosable memory leak on XP, a crash on Vista and Win7.
Just don't write C code like this. Always let the caller pass the buffer for the string. Now there's no guessing who owns the memory. Like this:
extern "C" __declspec(dllexport) void HelloFromDll(char* buffer, int bufferSize)
{
strcpy_s(result, bufferSize, "Hello from my DLL");
}
With your C# code like this:
[DllImport("foo.dll", CharSet = CharSet.Ansi)]
private static extern void HelloFromDll(StringBuilder buffer, int bufferSize);
...
var sb = new StringBuilder(666);
HelloFromDll(sb, sb.Capacity);
string result = sb.ToString();
From your question it seems that this is the scenario:
ProcessA (3rd party App) --> loads X.DLL --> initializes the plugin --> does other stuff.
ProcessB (Your C# App) --> loads X.DLL --> calls GetData();
Does X.DLL loaded in ProcessA have any mechanism to talk to X.DLL loaded in ProcessB?
if not then this approach is flawed. Your code probbably crashes because "3rdPartyLibrary" class hasn't been initialised in your C# app as it is completely different copy of the DLL.
For you to extract this data you need a query interface defined by X.DLL which can talk across processes, maybe sockets?
Then ProcessB talks to this interface and extracts the data. if using sockets, then your X.DLL would implement both server and client code, where your GetData() would use this mechanism (maybe sockets) and query the data and return it.
So : X.DLL in ProcessA should act like a server.
And: X.DLL (or write a Y.DLL) in ProcessB should act like a client and get this information from ProcessA.
btw, if the query is only needed to be done once, just hard code this is in X.DLL and dump to disk, and then explore at your convinience :-)
Generally, a returned char* needs to be returned as an IntPtr:
[DllImport(#"MyDll.dll")]
private static IntPtr HelloFromDll();
Then, you'll need to convert that IntPtr into a string:
string retVal=Marshal.PtrToStringAnsi(HelloFromDll());
Strings are a bit difficult in P/Invoke. My general rule of thumb is:
Input char* parameter = c# string
Return char * = IntPtr (use PtrToStringAnsi)
Output char* parameter = c# StringBuilder - and be sure to pre-allocate it large enough
before (ie = new StringBuilder(size)) calling the function.
I'm encountering a strange memory read/write error while calling a compiled DLL from C#. I use DllImport to get a handle to the function we need, which writes a return value to a parametric pointer to an int (i.e., int* out). This function is called multiple times within a thread, and runs successfully over the execution life of the first thread. However, if one launches another thread after the first has completed, the call to the external dll throws an AccessViolationException. Since the multiple calls from the first thread execute successfully, I'm thinking this is somehow related to the first thread not releasing the pointers to the relevant integer parameters(?). If so, how can I explicitly release that memory? Or, perhaps someone has a different insight into what might be going on here? Thank you very much.
EDIT: Danny has requested more specifics, and I'm happy to oblige. Here is where the external routine is invoked:
int success = -1;
unsafe
{
int res = 0;
int* res_ptr = &res;
int len = cmd.ToCharArray().Length;
int* len_ptr = &len;
CmdInterpreter(ref cmd, len_ptr, res_ptr);
success = *res_ptr;
}
Where CmdInterpreter is defined as:
[DllImport("brugs.dll", EntryPoint="CmdInterpreter",
ExactSpelling=false, CallingConvention = CallingConvention.StdCall)]
public static unsafe extern void CmdInterpreter(ref string cmd, int *len, int *res);
Please let me know if there is any additional info that would be helpful. Thank you!
Given that the problem only occurs when multiple threads are involved, it may be that the command interpreter DLL is using some sort of thread-local storage and doing it incorrectly. It could also have to do with the COM initialization state of the second thread (the one that generates the error).
It would be interesting to know what happens if you launch your new thread and have it call into the DLL before making any calls into the DLL on your first/main thread. If it works, that might support the thread-local storage theory. If it fails, that would support the COM state theory.
It may be the [DllImport]. If you post the [DllImport] signature, and the DLL's ptototype, maybe we can spot a problem.
I read that the Managed, Native, and COM Interop Team released the PInvoke Interop Assistant on CodePlex. http://www.codeplex.com/clrinterop/Release/ProjectReleases.aspx?ReleaseId=14120