I am using VS 2008 C#
Windows Application.
I have this DLL Import I am trying to use.
[DllImport("Mapi32.dll", PreserveSig = true)]
private static extern void
WrapCompressedRTFStream(
[MarshalAs(UnmanagedType.Interface)]
UCOMIStream lpCompressedRTFStream,
uint ulflags,
[MarshalAs(UnmanagedType.Interface)]
out UCOMIStream lpUncompressedRTFStream
);
public const uint MAPI_MODIFY = 0x00000001;
public const uint STORE_UNCOMPRESSED_RTF = 0x00008000;
I have a compressed string that is in CompressedRFTFormat.
How do I pass the string into the WrapCompressedRTFStream? I do not understand what the method is expecting.
I am trying to use it on a button.
RichText1.text = WrapCompressedRTFStream(_CompressedRichText.ToString(),something,somethingelse);
The first error I get is "cannot convert from 'string' to 'System.Runtime.InteropServices.UCOMIStream"
I hope someone who understands this posts an answer that helps!
ok, so I end up in the same situation when I use the IStream.
[DllImport("Msmapi32.dll", PreserveSig = true)]
private static extern void WrapCompressedRTFStream(
[MarshalAs(UnmanagedType.Interface)]
IStream lpCompressedRTFStream,
uint ulflags,
[MarshalAs(UnmanagedType.Interface)]
out IStream lpUncompressedRTFStream
);
The real issue here is I do not understand what / how to deal with the input and output of this method.
I suppose it's not a good idea to use legacy native-code libraries & I would investigate some more time to find analogous code in .net
Try out com interop or p-invoke .net technologies to use legacy code.
If you can't find a native .NET method for doing this, a good approach would be to contain your approach in a Managed C++ wrapper.
What this will let you do is create C++ code to perform your work, while exposing a managed class to call the method. This may be more complicated since it will require you to learn Managed C++, but allows you to do any C++ work necessary, returning a .NET string containing your "answer".
UCOMIStream is deprecated, use ComTypes.Istream instead. Then look at System.Runtime.InteropServices.ComTypes.IStream to System.IO.Stream
Related
I am building C# library (.dll), where some classes use native Windows API functions. To be specific, functions GetPrivateProfileString and WritePrivateProfileString, like:
static class NativeMethods
{
// external functions for working with ini files
[DllImport("kernel32.DLL", EntryPoint = "GetPrivateProfileStringW",
SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern int GetPrivateProfileString(string lpAppName, string lpKeyName,
string lpDefault,
string lpReturnString,
int nSize,
string lpFilename);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern bool WritePrivateProfileString(string lpAppName,
string lpKeyName,
string lpString,
string lpFileName);
}
And using them:
NativeMethods.GetPrivateProfileString(section, key, "", result, 127, this.path);
NativeMethods.WritePrivateProfileString(section, key, " " + value, this.path);
When I am using this class directly in another project (without using it from dll), it works without problem. But when I build it into dll, then reference this dll in another project, then these functions aren't working. They simply do nothing.
Your pinvoke for GetPrivateProfileString is wrong as Matthew says. You need to use StringBuilder when passing string data back to the caller.
You are not checking for errors. So it's entirely plausible that the functions are failing without you knowing that.
In order to know why your calls are failing you'd first need to fix these issues. Then you can look at the return values. Knowledge also of the values of the parameters that you are using would help. But only you have the ability to do that, at present.
The bigger problem is that you are not meant to call these functions at all. The documentation says:
This function is provided only for compatibility with 16-bit Windows-based applications.
These functions contain numerous compatibility shims that make using them a complete minefield. Don't go there. Find a decent third party native C~ ini file class and pretend you never heard of GetPrivateProfileString and WritePrivateProfileString.
Oh, I found error. I forced to find ini file path in current directory (in my DLL class code). As I call it from DLL, it was automatically looking for file in C:\Windows. After using Directory.GetCurrentDirectory() + iniFile , it works.
I am trying to use MimeTex.dll in Mixed Mode of C++/CLI project. I include the dll by:
#pragma comment(lib,"MimeTex.dll")
and I tried to call this method:
CreateGifFromEq("expression","path");
but the compiler inform that it doesn't know CreateGifFromEq() method.
I didn't find resources in the web in how to use MimeTex.dll in C++. I just find how to use it with C# in this link by Pinvok like:
[System.Security.SuppressUnmanagedCodeSecurity()]
internal class NativeMethods
{
private NativeMethods()
{ //all methods in this class would be static
}
[System.Runtime.InteropServices.DllImport("MimeTex.dll")]
internal static extern int CreateGifFromEq(string expr, string fileName);
[System.Runtime.InteropServices.DllImport("kernel32.dll")]
internal extern static IntPtr GetModuleHandle(string lpModuleName);
[System.Runtime.InteropServices.DllImport("kernel32.dll")]
[return: System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.Bool)]
internal extern static bool FreeLibrary(IntPtr hLibModule);
}
and then call it like:
NativeMethods.CreateGifFromEq(equation, tempGifFilePath);
How I can call it without Pinvok in mixed mode of C++/CLI?
Surely you meant to write:
#pragma comment(lib,"MimeTex.lib")
In other words, you pass the .lib file to the linker rather than the .dll. When you compiled the DLL, a .lib file will have been generated.
But that's not your immediate problem. The compiler has no declaration for CreateGifFromEq. That's because you have not included the library's header file in your C++ code. Doing that should resolve the issue.
If all you need is that one function then it should be trivial to declare it in your C++ code.
__declspec(dllimport) extern int CreateGifFromEq(char *expr, char *fileName);
You probably will need to wrap that in an extern "C" block too.
Actually, having looked at the library, the header file that is supplied with the source does not declare that function, even though it's present in the library.
In C++/CLI you can use P/Invoke as in C#.
If you don't want to use P/Invoke, the other way is to load the DLL with LoadLibrary and get pointers to the functions with GetProcAddress.
Here's the equivalent of the C# code in C++/CLI:
using namespace System;
using namespace System::Runtime::InteropServices;
private ref class NativeMethods abstract sealed
{
internal:
[DllImport("MimeTex.dll")]
static int CreateGifFromEq(String^ expr, String^ fileName);
[DllImport("kernel32.dll")]
static IntPtr GetModuleHandle(String^ lpModuleName);
[DllImport("kernel32.dll")]
[returnvalue: MarshalAs(UnmanagedType::Bool)]
static bool FreeLibrary(IntPtr hLibModule);
};
As you can see it's almost identical to the C# code except for some minor syntax changes.
Here's how you would use LoadLibrary and GetProcAddress (which has the advantage of not requiring marshaling, which is unnecessary in C++ anyway):
HMODULE hModule = LoadLibrary(L"MimeTex.dll");
int (*fpCreateGifFromEq)(WCHAR*, WCHAR*) = GetProcAddress(hModule, "CreateGifFromEq");
(*fpCreateGifFromEq)(L"expression", L"filename");
You don't need to do that for GetModuleHandle and FreeLibrary, because they're from kernel32.dll so you can just include Windows.h and call them normally.
There's a cleaner way of doing things:
Create a C++/CLI project. It will be your interface between C# and C++ (this is what C++/CLI is aimed at).
Make your C# project have a reference to this new assembly.
Inside your new C++/CLI project, configure project options so as you point to the directory with mimetex .h files for the compiler to compile your project, and the directory with .lib/.dll for the linker.
Inside your C++/CLI part, you just write C++ inside the functions. They are exposed to your C# assembly, but in the inside it's just calls to C++ functions as usual.
(You should check a C++CLI tutorial to know what to do with strings to convert them to native char or std::string. I remember I had to look at that.)*
In your C# part, you just call the C++CLI project assembly exposed functions like normal C# functions, without noticing it's native code called behind.
I've import dll in my code like that:
[DllImport("dll.dll", CharSet = CharSet.Ansi)]
private static extern int function(String pars, StringBuilder err);
I was wondered that function works, but it is not inside project and not inside Debug or Release folders. I.e. "dll.dll" should not be availabe because it is not in the current project folder, however it IS available. Now I want to know the exact full path of the dll used at runtime, but don't know how to get it.
You're going to have to use the win32 API.
First use GetModuleHandle passing "dll.dll" to it. Then pass that handle to GetModuleFileName.
string GetDllPath()
{
const int MAX_PATH = 260;
StringBuilder builder = new StringBuilder(MAX_PATH);
IntPtr hModule = GetModuleHandle("dll.dll"); // might return IntPtr.Zero until
// you call a method in
// dll.dll causing it to be
// loaded by LoadLibrary
Debug.Assert(hModule != IntPtr.Zero);
uint size = GetModuleFileName(hModule, builder, builder.Capacity);
Debug.Assert(size > 0);
return builder.ToString(); // might need to truncate nulls
}
[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("kernel32.dll", SetLastError=true)]
[PreserveSig]
public static extern uint GetModuleFileName
(
[In] IntPtr hModule,
[Out] StringBuilder lpFilename,
[In][MarshalAs(UnmanagedType.U4)] int nSize
);
See Dynamic-Link Library Search Order -- this should hold true with P/Invoke, but the behavior is slightly alterable depending upon load method. However it doesn't say how to determine the filename of a loaded DLL ;-)
A completely un-tested and perhaps ill-advised solution to find the DLL path at run-time. This assumes that P/Invoke and LoadLibrary use the same resolution (e.g. P/Invoke doesn't use LoadLibraryEx with LOAD_WITH_ALTERED_SEARCH_PATH) and that there are no awful conflicts with this approach.
Load the DLL with LoadLibrary or LoadLibaryEx.
Find the filename of the module using GetModuleFileName and the handle obtained in step #1.
Unload the module with FreeLibrary. P/Invoke should keep the module reference-count > 0, but again, this is untested ;-)
(There is no guarantee about the correctness or validity of the above solution. Suggestions, warnings and/or corrections welcome. YMMV.)
Happy coding.
If you really want to find out, use dependency-walker
It can even 'monitor' your application in runtime and detect dynamic loads so nothing remains hidden
I am having some strange problem. I have written a small module in VC++ using OpenCV.
It works fine. The code aggregates feed from the CCTV camera connected to the USB port.
however, I had to write the rest of my application in C#, so I made a DLL of the VC++ code and called the VC++ method from C#.
Now, I have ended up getting an error
Attempted to read or write protected memory.
This is often an indication that other memory is corrupt.
Can anyone please suggest me any solution to this. Is there any Access Violation while accessing it in a managed code?
If TrackBlob returns a string, you should be able to define your dllimport as such:
[DllImport("Tracking.dll", EntryPoint = "TrackIt")]
public extern static string TrackBlob();
and skip trying to marshal it.
By returning it as an IntPtr, you're trying to get a pointer into memory owned by the unmanaged DLL... returning it as a string will return a copy of the string for you to work with.
Let me know if that works!
James
* Edit *
Try one of these:
[DllImport("Tracking.dll", EntryPoint = "TrackIt")]
public extern static [MarshalAs(UnmanagedType.BStr)] string TrackBlob();
or
[DllImport("Tracking.dll", EntryPoint = "TrackIt")]
public extern static [MarshalAs(UnmanagedType.AnsiBStr)] string TrackBlob();
Check out this MSDN link on string marshalling:
http://msdn.microsoft.com/en-us/library/s9ts558h.aspx
I have a dll which comes from a third party, which was written in C++.
Here is some information that comes from the dll documentation:
//start documentation
RECO_DATA{
wchar_t Surname[200];
wchar_t Firstname[200];
}
Description:
Data structure for receiving the function result. All function result will be
stored as Unicode (UTF-8).
Method:
bool recoCHN_P_Name(char *imgPath,RECO_DATA *o_data);
Input:
char * imgPath
the full path of the image location for this
function to recognize
RECO_DATA * o_data
data object for receiving the function
result.
Function return:
True if Success, otherwise false will return.
//end documentation
I am trying to call the recoCHN_P_Name from my C# application. To this end, I came up with this code:
The code to import the dll:
public class cnOCRsdk
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct RECO_DATA{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=200)]
public string FirstName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 200)]
public string Surname;
}
[DllImport(#"cnOCRsdk.dll", EntryPoint="recoCHN_P_Name")]
public static extern bool recoCHN_P_Name(byte[] imgPath, RECO_DATA o_data);
}
The code to call the function:
cnOCRsdk.RECO_DATA recoData = new cnOCRsdk.RECO_DATA();
string path = #"C:\WINDOWS\twain_32\twainrgb.bmp";
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
byte[] bytes = encoding.GetBytes(path);
bool res = cnOCRsdk.recoCHN_P_Name(bytes, recoData);
And the error I'm getting is
""Unable to find an entry point named 'recoCHN_P_Name' in DLL 'cnOCRsdk.dll'."
I'm suspecting that I'm having an error in converting a type from C++ to C#. But where exactly ... ?
First make sure the function is actually exported:
In the Visual Studio Command Prompt, use dumpbin /exports whatever.dll
C# doesn't support C++ name mangling and you either need to declare the C++ functions with
extern "C" {...}
(may not an option if they're from a third party), or call the mangled name directly if you can get it to work. It may be easier to get the third party to provide a non-mangled interface to the functionality.
Solved - at least to the point where the program does not break and actually returns me a bool value.
The key, I guess, was to specify the entry point as the 'mangled' name
[DllImport(#"cnOCRsdk.dll", EntryPoint="?recoCHN_P_Name#CcnOCRsdk##QAE_NPADPAURECO_DATA###Z")]
public static extern bool recoCHN_P_Name(ref string imgPath, ref RECO_DATA o_data);
After that I got some other errors but the 'unable to find entry point' went away.
I solved the same problem in these steps:
step 1) If you program your custom DLL in C++ using Visual studio,then at the property page of your project set the Common Language Runtime Support (/clr)parameter to Common Language Runtime Support (/clr).
step 2) To function deceleration in .h file use __declspec(dllexport) keyword like below:
__declspec(dllexport) double Sum(int a,int b);
step 3) Build and export DLL file, then use the Dependency Walker software to get your function EntryPoint.
step4) Import DLL file In the C# project and set EntryPoint and CallingConvention variable like below:
[DllImport("custom.dll", EntryPoint = "?Sum##YAXHHHHHHNNN#Z", CallingConvention = CallingConvention.Cdecl)]
public static extern double Sum(int a,int b);
I'd write a wrapper using C++/CLI. This wrapper will be able to include the .h files and link to the .lib files you got from the third party vendor. Then it is both easy and safe to write a managed interface for your C# program.
Correct EntryPoint string could be found in ".lib" file that comes along with main unmanaged dll.
We had this problem when we want to access to DB and solved it by changing EF core to EF 6.4.4
It may be you have a problem like this and need to change or downgrade your version of EF (If you used EF)
We had this problem .we change EntityFramework.core to EntityFrameWork 6.4.4 and after that the program worked fine. you most change you're Framework Version.
you may get this error due to string marshalling mismatch between DLL and your application . for example, one is using ANSI and the other is unicode.
you can try something like this:
[DllImport("yourDLL.dll", CharSet = CharSet.Unicode )]
public static extern String YourFunction(String name);
checkout HERE for a list of other possible reasons.
You could try using the unmangled name while specifying a CallingConvention in the DllImport