calling DLL method from WinDev - c#

I want use a DLL (developed in C++) in WinDev application , my DLL works fine with C# code and i can call any method in there , however with Windev i can successfuly load the DLL using :
hInst = LoadDLL("MyDLL.DLL")
but when i want invoke a method this way :
CallDLL32("MyDLL", "GetCode", data, res1, res2)
i got an error "Attempted to read or write protected memory. This is often an indication that other memory is corrupt."
the method signature that i want call is like this way :
string GetCode([IN] byte[] Data, [OUT] string res1, [OUT] string res2)

This post in french suggest that you prefix the strings with & because it need to be pass by reference, it should probably looks like :
CallDLL32("MyDLL", "GetCode", &data, &res1, &res2)
Though I don't know how it works with an array of bytes.

You can call Directely: API function
API("USER32", "SendMessageA", hWnd, wMsg, lParam1, lParam2)
documentation: https://doc.windev.com/en-US/?3014005

Related

C# P/Invoke AccessViolationException when attepting to use string parameters

I'm trying to wrap a C++ dll for which I only have the header file for. The function I am trying to get working at the moment is giving me an AccessViolationException:
"Attempted to read or write protected memory.
This is often an indication that other memory is corrupt."
The C++ function prototype is:
RunSimulation( LPCSTR, LPSTR);
Meanwhile, my C# wrapper is:
[DllImport("thedll.dll", EntryPoint = "RunSimulation")]
public static extern uint RunSimulation(string simID, ref string outputID);
I suspect the problem is with the C# function, specifically with how the strings are implemented. Since I'm relatively new to platform invocation and such, I'm not sure how to proceed.
Should the string parameters be pointers to where the strings are? Or is there something else wrong with the wrapper maybe?
Edit:
This is how the function is called on the managed end of things:
string outputID = "";
try
{
RunSimulation(id, ref outputID);
}
catch (Exception e)
{
Logging.Log_Warning.SendException("Threw an exception", e);
}
Edit 2:
Upon changing the second parameter to a StringBuilder, the same exception occurs. The only difference is that the exception break doesn't stop at the line where the function is called, Visual Studio opens a new "Break" tab saying the exception happened. The function documentation recommends setting aside 16 bytes or more, so I used the capacity constructor with a values of 1024 and 4096 to test.
Edit 3:
After doing a clean and rebuild, the problem presented itself as a driver error. Since this shows that the API is functioning, the solution was indeed to change my ref string parameter to a StringBuilder as suggested in the comments.
The solution to my problem ended up being to use StringBuilder instead of String to make sure the space in memory was allocated ahead of time. So my signature ended up looking like:
[DllImport("thedll.dll", EntryPoint = "RunSimulation")]
public static extern uint RunSimulation(string simID, StringBuilder outputID);
And to use it:
string id = "someID";
int requiredSize = 512;
StringBuilder outputID = new StringBuilder(requiredSize);
RunSimulation(id, outputID);
Hope that helps!

Variable corrupted when calling C++ COM from C#

I'm calling C++ COM interface from C# code using a dll.
At the C++ side, i have a WCHAR* global variable which is updated through a method with a BSTR parameter.
The problem is that, when i first call the C++ wrapper method from C# to change the variable, everything works fine, but at the moment that i call another C++ wrapper method from C#, unexplainably the WCHAR* global variable points to a different memory position and its value gets corrupted.
Some code:
//THE C# side:
capture.filename = PATH + "\\" + DIRECTORY_NAME + "\\";
capture.MaxMinutesPerFile = MAX_MINUTE_PER_FILE;
"capture" is an object of the C++ wrapper class (i think it is autogenerated when building the C++ code to a DLL. Not my code).
"filename" property calls a "put_FileName" C++ method and "MaxMinutesPerFile" a "put_MaxMinutesPerFile" method.
//C++ code
WCHAR *m_bstFileName = L"None";
(...)
STDMETHODIMP CCaptureMF::put_FileName(BSTR PathName)
{
EnterCriticalSection(&m_critsec);
HRESULT hr = S_OK;
m_bstFileName = PathName;
LeaveCriticalSection(&m_critsec);
return hr;
}
STDMETHODIMP CCaptureMF::put_MaxMinutesPerFile(LONG Minutes)
{
MaxMinutes= Minutes;
return S_OK;
}
So, after calling "put_FileName", "m_bstFileName" is updated correctly with the "PathName" value, but just after calling "MaxMinutesPerFile" (or any other interface wrapper method), "m_bstFileName" gets corrupted pointing to a different memory position and fulfilled with strange data.
Thank you.
EDIT:
To make a buffer of "m_bstFileName" and then copy the "PathName" data, i used the following code, taking in mind that "m_bstFileName" size can change at runtime:
m_bstFileName = (wchar_t*)malloc(sizeof(PathName));
wcscpy(m_bstFileName, PathName);
That code works fine, but the rest of the program behaves bad. I´m not sure why, i should investigate more, but for now, could you analyze that pice of code and tell me if it is correct or if i should implement it in other way?
SOLUTION:
Ok, following your recomendations i have finally implemented the following code, which works perfect for the whole application:
CComBSTR m_bstFileName = L"None";
(...)
STDMETHODIMP CCaptureMF::put_FileName(BSTR PathName)
{
EnterCriticalSection(&m_critsec);
HRESULT hr = S_OK;
m_bstFileName = PathName;
if (g_pCapture)
{
g_pCapture->SetPath(m_bstFileName);
}
LeaveCriticalSection(&m_critsec);
return hr;
}
If you think that this can be implemented better, just tell.
Thank you for your help!
In the most basic case you'll need to make a buffer to do a string copy into. Same operation could be accomplished via assignment with cstring, ccombstr, std::string, etc. depending on the framework you're using.
You need to copy the string to m_bstFileName, not just assign it. Use something like
strcpy(m_bstFileName, PathName);

How to open a file when file handle number is known?

I open a file in C# with FileStream, and I got the file handle number with this line:
IntPtr file_handle = fs.SafeFileHandle.DangerousGetHandle();
Now I want to pass this handle to C++ code and use this handle value to access the file. Is this possible? How to open a file with merely a file handle in C++?
Thanks.
Update
I use C# to P/Invoke into a C++ Win32 DLL(not a COM DLL). I open the file in C# as FileStream, and pass the handle to the C++. Here is some of my code in the C++ DLL:
extern "C" __declspec(dllexport)void read_file(HANDLE file_handle)
{
char buffer[64];
::printf("\nfile = %d\n",file_handle);
if(::ReadFile(file_handle,buffer,32,NULL,NULL))
{
for(int i=0;i<32;i++)
cout<<buffer[i]<<endl;
}
else
cout<<"error"<<endl;
}
And here is my C# code:
[DllImport("...",EntryPoint = "read_file", CharSet = CharSet.Auto)]
public static extern void read_file(IntPtr file_handle_arg);
But I get this error:
Unhandled Exception: System.AccessViolationException: Attempted to read or write
protected memory. This is often an indication that other memory is corrupt.
Thanks.
You can use win32 calls, the same way the filestream/file constructors do (via p/invoke).
Cracking it open in .NET Reflector, it looks like it is using this function:
[DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)]
private static extern SafeFileHandle CreateFile(
string lpFileName,
int dwDesiredAccess,
FileShare dwShareMode,
SECURITY_ATTRIBUTES securityAttrs,
FileMode dwCreationDisposition,
int dwFlagsAndAttributes,
IntPtr hTemplateFile);
Here is an official reference:
http://msdn.microsoft.com/en-us/library/aa363858(VS.85).aspx
This is just to open the file, though, as you asked when you said:
How to open a file with merely a file handle in C++
If you want to read an already open file, you might have more trouble. I'm not sure. You might be able to use this function:
[DllImport("kernel32.dll", SetLastError=true)]
internal static extern unsafe int ReadFile(
SafeFileHandle handle,
byte* bytes,
int numBytesToRead,
IntPtr numBytesRead_mustBeZero,
NativeOverlapped* overlapped
);
http://msdn.microsoft.com/en-us/library/aa365467(v=VS.85).aspx
That entirely depends -- but it's unlikely that you will be able to do this. I'm assuming that your C# code and C++ code are running in different processes -- if you're in the same process you should just be able to marshall over the IntPtr over as a HANDLE.
The problem is that file handles are specific to a process -- you won't be able to use that handle in another process.
That said, you're probably better off:
Passing the name of the file to the C++ code and opening it there
Passing the data actually contained whithin the file to the C++ and dealing with it there.
If the C++ code is C++/CLI, then don't bother with the handle at all. Just pass the FileStream object directly to your C++ code.
If the C++ is native code, then you can use the file handle anywhere you'd normally use a Windows HANDLE value for files, such as ReadFile and WriteFile. You wouldn't use the handle to open a file because it's already open. If you want another copy of the handle, or if you want to give the handle to another process, then use DuplicateHandle. If you need to the value with POSIX-like functions like _read and _write, then call _open_osfhandle to get a file descriptor. You can wrap the file descriptor into a C FILE* stream with _fdopen.
Turns out the title isn't really what the OP was after.
But if someone ever really needs to do this (say: Re-opening a file with different permissions), you can probably use a combination of GetFileInformationByHandle to get the File ID and OpenFileById.
FWIW.

pinvoke to clutter function

I'm trying to pinvoke to a clutter function.
The function is defined in the docs as
ClutterActor * clutter_texture_new_from_file (const gchar *filename, GError **error);
The code I have is as follows:
[DllImport ("libclutter-glx-1.0.so.0")]
private static extern IntPtr clutter_texture_new_from_file (string filename, IntPtr errorData);
And I call it like this:
IntPtr texture = clutter_texture_new_from_file("myImage.jpeg",IntPtr.Zero);
however when called like this in monodevelop on ubuntu I get the following error.
Unix Transport Error
Eventally I would like to get the error reporting working so I can get the gerror result however firstly I need to get past the Unix Transport Error.
The errorData parameter should be marked as "ref IntPtr", although I don't think that should be causing this error since that parameter should be allowed to be NULL. Otherwise, try running this outside Monodevelop. This kind of error may be the result of a segfault elsewhere in your program.

Protected Memory Violation calling FORTRAN DLL from C#

I am trying to call out to a legacy dll compiled from FORTRAN code. I am new to Interop, but I've read some articles on it and it seems like my case should be fairly straightforward.
The method I really want to call has a complex method signature, but I can't even call this simple GetVersion method without getting a protected memory violation.
Here's my DllImport code:
[DllImport("GeoConvert.dll",
EntryPoint="_get_version#4",
CallingConvention=CallingConvention.StdCall)]
public static extern void GetGeoConvertVersion([MarshalAs(UnmanagedType.LPStr, SizeConst=8)]
ref string version);
Here's the FORTRAN code:
SUBROUTINE GetVer( VRSION )
C
!MS$DEFINE MSDLL
!MS$IF DEFINED (MSDLL)
ENTRY Get_Version (VRSION)
!MS$ATTRIBUTES DLLEXPORT,STDCALL :: Get_Version
!MS$ATTRIBUTES REFERENCE :: VRSION
!MS$ENDIF
!MS$UNDEFINE MSDLL
C
CHARACTER*8 VRSION
C
VRSION = '1.0a_FhC'
C
RETURN
END
Here's my unit test that fails:
[Test]
public void TestGetVersion()
{
string version = "";
LatLonUtils.GetGeoConvertVersion(ref version);
StringAssert.IsNonEmpty(version);
}
Here's the error message I get:
System.AccessViolationException
Message: Attempted to read or write protected memory.
This is often an indication that other memory is corrupt.
Other things I've tried:
Using the default marshalling
Passing a char[] instead of a string (get method signature errors instead)
...snip...
OK, I got it to work, the problem was passing by ref. I'm not sure why, but this works:
...snip...
You need to pass by reference because that is the semantic being used by the FORTRAN code. The client code is passing in a buffer that the FORTRAN code is going to write to in lieu of using a return value.
...snip...
!MS$ATTRIBUTES REFERENCE :: VRSION
...snip...
This attribute in your FORTRAN code specifies that this parameter is passed by reference. That means the FORTRAN code is going to write to this address. If the DllImport doesn't declare it as a ref value also, you will get an access violation.
OK, I got it to work, the problem was passing by ref. I'm not sure why, but this works:
[DllImport("GeoConvert.dll",
EntryPoint="_get_version#4",
CallingConvention=CallingConvention.StdCall)]
public static extern void GetGeoConvertVersion([MarshalAs(UnmanagedType.LPArray)]
byte[] version);
With this test:
[Test]
public void TestGetVersion()
{
//string version = "";
byte[] version = new byte[8];
LatLonUtils.GetGeoConvertVersion(version);
char[] versionChars = System.Text.Encoding.ASCII.GetChars(version);
string versionString = new string(versionChars);
}
Have you tried using a StringBuilder?
Create your String as a StringBuilder and pass that into the dll function.
Im unsure as to what Marashlling statement to use, perhapse the default might work.
Have a look at: Marshal C++ “string” class in C# P/Invoke
Heres a good article the might help as well: Interop Marshalling
I cannot try this solution since I do not have a FORTRAN compiler, but I think this would work for you:
[DllImport("GeoConvert.dll",
EntryPoint="_get_version#4",
CallingConvention=CallingConvention.StdCall,
CharSet=CharSet.Ansi)]
public static extern void GetGeoConvertVersion(StringBuilder version);
Thank you all guys, I've been trying to pass a string from c# to a subroutine from fortran dll and this method was the only working one among lots of others

Categories