My intention is, to run a Web service which accesses C++ native functions. Therefore I created a WCF Service Application (which contains contract and implementation) which references a C++/ CLI Wrapper around my Native C++ code. I did the following steps (following 2b from http://blogs.msdn.com/b/jorman/archive/2007/08/31/loading-c-assemblies-in-asp-net.aspx)
The native C++ API is exported.
native C++ dll's are loaded with "delayed loaded"
I set a path for native dll and its 3rd party dll's in the Web.config
defined asp-compatibility in the web.config file
Defined a Global.asax File for accessing the loading path for native dll's
I can run the service as long as I don't create the wrapper-object, which creates the native C++ object in the constructor.The problem is the creation of the native C++ object. If I test it with the WCFTestClient I get the unspecific errors:
Failed to invoke the service. Possible causes: The service is offline or inaccessible.
My question is: Is something wrong in this concept? I can use this wrapper and the native C++ object if I call it from a C#-Project. Do I have to choose another project type than a WCF Service Application?
Thank you for your help!
The concept is right, and it should work fine. I think when the service try to create the native C++ object, an error/exception happens, and which crashes the service. I suggest you write a small C# test program, which calls the C++/CLI DLL to create the native C++, if this small programs works fine, then move the code to your service.
Or you can debug the service, find the actual error, that would help too.
Related
The user's main application is ms-access (with ms-sql server). Ton of code in vba.
One of the main features i have to manifest is controlling my client's voip telephony. My plan is to make a COM DLL that the ms-access can use.
As of now, i've managed to write a C# project (vs2019 .net framework) that handles the voip pbx well, using json, and do all missions necessary, such as invoking calls, sending sms, get calls list, recodings list, get recordings wav files and convert them to mp3. I use Newtopsoft.Json and NAudio.Lame.
BUT it only works as a standalone .net project or exe.
As a COM DLL (class library) - ms-access can handle and use it UNTIL it gets to the part where the code uses ANY external dll's functionality - and it crashes (with newtonsoft) or just not working (with naudio), although the dll's are in the working folder.
I know i have to found a way to make these external dll's to work under the office (32bit) enviroment.
I was trying and guessing many code samples for a couple of days. I tried to follow the Assembly.Load/From/File examples to dynamically load and include the dll's, but i failed to assimilate it in my code or even to understand it enough.
I hope i'll get a solution here.
Thanks :)
Hum, I am able to create a COM object for use with Access. External library code (in my case Newton soft) for serializing data works just fine when that class code is used as a COM object from Access.
You don't mention if the other libraries are managed code, or external win32 .dll? I have however used un-managed .dll’s with a .net COM object, and then have consumed that from MS-access.
The only issue would be in project explorer is to ensure that you have a copy local setting = true for the external referenced .net .dll libraries. (And that is the default, so I am sure you do.
The next issue of course is of course is there any use of configuration files? (app.config) etc.? The reason for this of course that since your application is being launched with msaccess.exe, then the config and settings will be assumed to be in the office install folder, and not the local application. As a result, it not all so practical to move/copy those app.config files to the office folder where msaccess.exe resides. And the config file name will not only have to be in the same folder, but also named.
Msaccess.exe.config.
In place of
YourDotNet.exe.config
Now of course, if you build your project as a .net exec? Well then of course any config settings (application ones, not user) will be placed in this config file, and of course that file will have to be placed in the same folder as the .exe file.
So, one might add a “test” function (any function is a method of that class) to the class that you test/call from VBA to ensure that such settings are being seen and read (if you are using any settings).
Eg:
System.Reflection.Assembly.GetExecutingAssembly().Location + ".config"
So, return that to access and display this result.
The other issue is of course to FORCE your project to x86. I would not use “any” CPU. While this “may” work, since you are using access x32, then I would force compile your .net class to x86 as opposed to “any” CPU. This would also spit out some errors in case some of the external assemble(ies) are compared to a particular bit size and thus x86 settings will result in your class not consuming some of the external .net .dll’s.
Now you “note” that your project works as an .exe, and then “sort of” works as a class and “.dll” registered as a COM.
However, you don’t mention how you are “flipping” this from an .exe to a class, or do you simply have a .net “test” project that you run as an .exe, and it of course has a reference to that class .dll. And you NOT using “COM” for this testing.
If your test.exe program can use that external assembly?
Then I would create a test2 project, but this time around do NOT reference the assembly (as .net), but try using .net CreateObject(). (I think c# has this choice – vb.net certainly does).
So you could try + use a CreateObject() in this .net test sample, and thus test from .net as COM.
So this test .net program (one that has NOT referenced the assembly) would a intermediate test before you jump all the way into ms-access + VBA test code.
However, I would first test/check if an app.config file is being used here, since as noted when you flip to a COM object, and then create a instance of that object in Access/VBA?
Then the config file will NOT be used. You can in .net code force/change the app.config file in that running assembly, and I can’t seem to find my code example that does this. But I am not going to dig too hard until such time we confirm that you are using app.exe.config file here.
Edit
Out of cuirous, I googled naudio. It is managed code. So, that library should work just fine. If that project is compiled as "ANY CPU", you COULD try re-compile as x86, and also re-compile your test program as x86. Then when you create a COM object, then again compile that as x86.
As noted, I do quite a bit of COM stuff for ms-access, and I have without issue used Newtonsoft (for jason serializing/de-serializing) as a COM object that is consumed by ms-access.
And given that naudio is managed code then I don't see why it would be an issue. Any other 3rd party .dll's you using here? As a quick test, I would set all projects to x86. You seem to "mention" that "some" of the COM object works, but just not all.
I will give you a brief description of my software before I ask questions.
So there is a front end C# code which provides the user interface and a back end C++ code that deals with the hardware.
The C# project creates an executable (.exe) file and the C++ project creates a DLL which talk with each other using pinvoke calls (import/export functions). All this worked fine on WEC7.
Now, we are moving to WEC2013 with Toradex. I downloaded the WEC2013 SDK from Toradex’s website and was able to port my code and build it on VS2013.
I copied all the required files on a USB and when I tried running it the C# exe is not able to communicate with the C++ Dll. The error I get is :
missingmethodexception can't find pinvoke dll “xyz.dll”
I have made sure the dll exists at the specified location. The dll also has the required export functions.
First I thought the function parameters in the export functions could be an issue, but I tried calling function which requires no parameter with the same result.
Any help will be really appreciated.
I have a third party DLL to integrate with their application. It is a 32 bit C++ DLL that does not expose itself via COM, and I have not been supplied source code or a header file.
It was supplied with working VB.NET example code in a WinForms example. This works, as long as the executable is run from the same directory as the API DLL and the application for which the API is interfacing.
I was using the example function declaration:
Declare Ansi Function GetVersion Lib "ThirdPartyAPI.dll" () As Integer
However, we’ll be using the API calls from a C# library to be used in a web site or web service, so I converted the example VB code to
[DllImport("ThirdPartyAPI.dll", SetLastError = true, CharSet = CharSet.Ansi)]
public static extern int GetVersion();
If I call this from within the C# library I get the error
Unhandled Exception: System.DllNotFoundException: Unable to load DLL
'ThirdPartyAPI.dll': A dynamic link library (DLL) initialization
routine failed. (Exception from HRESULT: 0x8007045A)
I took an alternative route and put the original working VB code from the example into its own VB.NET DLL and called that via C#. I got the same error. Strangely, a call to the VB.NET DLL from a VB.NET console app works.
In summary:
A simple VB.NET console app will work
A simple VB.NET WinForms app will work
A simple VB.NET console app can call GetVersion via a VB.NET DLL
A simple C# console app cannot call GetVersion via a VB.NET DLL
A simple C# console app cannot call GetVersion directly.
This could be to do with incorrectly defining the function calls. At
this stage, I’m not too worried about this.
32 bit compilation does not fix the issue
I have tried this on Server 2008 R2 and Windows 7 Enterprise
I created a WCF host via an NT service to expose the functions, hoping this would work around file locations and dependencies. This was written in VB.NET and placed in the same folder as ThirdPartyApi.dll.
None of the code in the NT service could access GetVersion
None of the code in the WCF service could access GetVersion
Please note, in all of the above cases, the executables are in the same directory as ThirdPartyApi.dll. All of its dependencies also exist in this directory.
Can anyone explain this behaviour, or suggest how this can be made to work within a C# web site?
Thanks
The error code is 0x8007045A. That is a COM error code that maps to the Win32 error code ERROR_DLL_INIT_FAILED. Which is described as:
A dynamic link library (DLL) initialization routine failed.
What this means is that your DLL was found, in spite of the perhaps misleading exception class DllNotFoundException. However, the DLL failed to load. You can gain no more information from the system. There is no mechanism for the DLL to report reasons why it failed to load. I suggest that you contact the vendor of the DLL and ask for support.
I'm noob in C# and I already searched on the web. Anyway I'm still not sure about this and I do not have the total control of the code I have to implement, this is why I would like to be sure I needn't make any dll. I have a C++ file with a method, and I want to call this method from C# code. I just added "extern C" to the function.
When I just add the .h and .cpp files to the C# project they aren't detected. And of course, when I try to add it as reference, it doesn't work.
So do I absolutly have to make a dll ?
Your options for accessing the C++ code from C#:
Compile C++ as unmanaged DLL and access using p/invoke. This requires the C++ code be exposed using a C style API.
Compile C++ as unmanaged DLL and access using COM. This requires that you wrap your C++ in as COM objects.
Compile C++ as mixed/mode C++/CLI assembly and access the assembly as a managed reference. This requires that you wrap the original C++ as managed C++ ref classes.
All of these options, by necessity, involve the creation of another module/assembly. You cannot link the C++ code directly into your C# assembly.
You might like to try using the PInvoke Interop Assistant to generate the C# necessary to interact with the DLL via Platform Invoke. Be aware that this is imperfect though so YMMV.
Another alternative, if you have the knowledge and patience, is to make a COM component out of your native C++ DLL and consume that from C# by using the Type Library Importer to create a managed wrapper.
You won't be able to interact with .cpp/.h files since you need at least a binary object (assembly) for C# to interact with and C# won't generate any binaries from .cpp/.h. That's on the subject about adding these files as references to the project.
As for the argument that you don't have control over the code - well, don't make a DLL out of the actual .cpp/.h, but make your own thin DLL that has a wrapper object that just includes the headers, calls whatever method you would be calling and links to the appropriate .o files or .lib or whatever you have. If the interface changes you would just changed your thing wrapper which should be easy.
I have com dll written in c# and everything works ok when I use it from the normal exe project in visual basic 6, but when I try to use it from the visual basic 6 dll then I get this error: configuration system failed to initialize. This is a dll, so it don't have any app.config file.
I get this error on this line:
request = (HttpWebRequest)WebRequest.Create(ApiUrl);
where ApiUrl is something like: https://www.api.com/
Anyone knows what can be wrong?
Edit:
Maybe there is something with permissions? The vb6 dll is called from the web service hosted on the iis on the same server.
Edit2:
It must be something with IIS_USER, because when I call the vb6 dll from normal exe project, then works.
The impression I get of your setup is:
You have a client (of some sort) that is connecting to a web service that is written in C#, that is calling a VB6 dll that in turn calls a COM-exposed C# dll?
When I've seen this error in the past, I've had multiple Configuration elements in the *.config file. You will have a *.config file for the main service, so I'd start looking there.
A quick google found this URL which backs what I've found in the past too: http://social.msdn.microsoft.com/Forums/vstudio/en-US/b7603703-3805-4e73-ac6a-755a7c14e722/configuration-system-failed-to-initialize?forum=vbgeneral
(apologies for offering as an answer, I can't add comments due to having <50 rep)