I hope this question will not be regarded as a duplicate as I know there are many similar questions on stackoverflow. I should know. I already read most of them. So bear with me...
I am writing a C# application that relies on the OpenCV libraries to function. The OpenCV libraries are written in c++ code and to use them in c#, I wrote 2 libraries: a static library containing the methods I want from OpenCV; a CLR DLL that acts like a bridge between the static lib and the C# project.
What perplexes me is the fact that everything worked fine until I reinstalled Windows 8.1 due to a virus. Before the reinstall, the app compiled and ran just like intended. After the reinstall, the very same project throws a "BadImageFormatException" when trying to debug:
namespace G19_GUI
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new GUI.GUI()); //this is the line producing the exception
}
}
}
Additional information: Could not load file or assembly 'clrLib, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. An attempt was made to load a program with an incorrect format.
I know the most common cause for this exception is that the application is trying to load a 32bit library into a 64bit compiled application or vice-versa. As such, I verified that the OpenCV libraries I am trying to use are destined for use in a 32bit application and indeed they are. I tried switching to the 64bit dlls, action that produced 39 errors of type "LINK2028: unresolved token".
Keep in mind that the project itself did not change at all between the 2 installations of Windows. I used the same property sheet and the same OpenCV libraries. Everything was kept on an external drive, which was unplugged at the time I foolishly double clicked the virus executable, and backed up on DropBox, the only thing I had to do after reinstalling Windows was to reset the path and OpenCV environment variables, which I did using a .bat file, the same .bat file used to set those very same variables in the first install of Windows. Therefore, I highly doubt the possibility of the virus messing with my project files. Even so, I double-checked everything and couldn't find anything wrong.
I proceeded to documenting the exception online. As a result, I ended up trying every possible combination of configuration builds and target platforms I dared have the patience to try for all of the 3 projects I had in my solution.
Indeed, trying to build and compile for a 64bit machine removed the exception but another DLL my C# project depended on was destined for 32bit use and when trying to load that DLL, the very same exception popped up (which was expected). Unfortunately, the DLL did not come with a 32bit version or with a source code to try and build my own 64bit version of said DLL.
Thus, I am forced to build my application either for both target platforms (any cpu, mixed platform, whatever) or only for 32bit. Which, of course, produces the exception at start-up.
I know all my DLLs are made for 32bit use. For the life of me, I cannot figure out what the problem is, nor why this problem did not exist before I reinstalled the os.
Below is the code of my clrLib dll:
#include "Stdafx.h"
#include "clrLib.h"
#include <vector>
namespace clrLib
{
public ref class mapper
{
private:
static openCVProc * myProc;
public:
static mapper(void)
{
myProc = new openCVProc();
}
char * mapStringToChar(String ^ path)
{
return (char*)(void*)Marshal::StringToHGlobalAnsi(path);
}
array<int>^ getRGBfromHSV(int h, int s, int v)
{
array<int>^ values = gcnew array<int>(3);
std::vector<int> myVals = myProc->hsv2rgb(h, s, v);
values[0] = myVals[0];
values[1] = myVals[1];
values[2] = myVals[2];
return values;
}
array<int>^ getHSV(String^ src)
{
array<int>^ vals = gcnew array<int>(3);
vals[0] = (myProc->getHSV(mapper::mapStringToChar(src)))[0];
vals[1] = (myProc->getHSV(mapper::mapStringToChar(src)))[1];
vals[2] = (myProc->getHSV(mapper::mapStringToChar(src)))[2];
return vals;
}
void openCam()
{
myProc->startCam();
}
void closeCam()
{
myProc->stopCam();
}
int^ getBrightness()
{
int^ b;
b = myProc->getB();
return b;
}
bool^ camState()
{
return myProc->camState();
}
array<Byte>^ mapper::getFrameData()
{
cv::Mat f = myProc->getFrame();
int width = f.cols;
int height = f.rows;
array<Byte>^ bitmapData = gcnew array<Byte>(width*height * 3);
int c = 0;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
bitmapData[c] = f.at<cv::Vec3b>(i, j)[0];
bitmapData[c + 1] = f.at<cv::Vec3b>(i, j)[1];
bitmapData[c + 2] = f.at<cv::Vec3b>(i, j)[2];
c += 3;
}
}
return bitmapData;
}
Size^ mapper::getFrameSize()
{
std::vector<int> size = myProc->getFrameSize();
Size^ frameSize = gcnew Size(size[0], size[1]);
return frameSize;
}
};
}
The other 2 libraries are a bit lengthy, but I will include them if need be.
Thank you for taking the time to read my post.
Related
For a long time I have a problem with a project that I have to implement in mine, I'll explain it to you.
My goal is to call a C ++ class from a C # application (Project 1), the problem is that the C ++ project (Project 3) is not compatible with CLR.
What I have done so far has been created an intermediate project also in unmanaged C ++ (Project 2) to be compatible with the project 3.
Project 2 consists of a very simple method that initializes a class from project 3 and uses this object for different operations.
I'm working in Visual Studio and it does not give me an error when compiling, but at run time I get the following error:
Unable to load the DLL file 'PROJECT-ROUTE \ Project2.dll': The specified procedure could not be found. (Exception from HRESULT: 0x8007007F)
in project1.process ()
The thing is that the previous error comes out only when within the project2 method I initialize the class from project 3, if I comment the initialization line then it goes well, I can not understand why between 2 C ++ projects of the same type gives me this type of problems.
Can somebody help me?
thank you
C# Code (Project 1)
private const string DllFilePath = #"PATH_TO_DLL\Proyect2.dll";
[DllImport(DllFilePath, CallingConvention = CallingConvention.Cdecl, EntryPoint = "process")]
public extern static void process();
[HandleProcessCorruptedStateExceptions]
public static string Prox(string a, string b)
{
string str = "OK";
try
{
process();
}
catch (System.AccessViolationException exception)
{
return exception.Message + " " + exception.StackTrace;
}
catch (Exception exception)
{
return exception.Message + " " + exception.StackTrace + " ";
}
return str;
}
}
Middle proyect Unamanged C++ Code (Project 2)
Project2.h
#include <stdexcept>
#include "Project3.h"
using namespace std;
namespace FinalProcess
{
extern "C" { __declspec(dllexport) void __cdecl process(); }
}
Project2.cpp
#include "Project2.h"
#include <iostream>
#include <chrono> // To measure execution time
namespace FinalProcess
{
void process()
{
OCTA::Analyzer& ld = OCTA::Analyzer::getInstance(); // <-- Singleton
// if I comment this line then it goes well
}
}
Assuming that the information that you present here is correct (and I have my doubts because you've not copied it verbatim as can be seen from the DLL name of Proyect2.dll) then the error cannot be that the function process is not found. In which case the error has to be in the linking to Project3.
Your Project2.dll is presumably attempting to link to Project3.dll and to a function that is not exported from Project3.dll. That would explain the behaviour that you report. This would happen typically if the Project3.lib file that you linked when building Project2.dll did not match the Project3.dll file found by the executable at runtime.
Make sure that the version of Project3.dll that is being loaded is up to date and matches the .h and .lib files you used to build Project2.dll.
Rather than give an absolute path of the DLL in your C# code, you just the file name of the DLL. Place both DLLs in the same directory as your C# executable.
I have a C# UWP application that uses a custom UWP Runtime Library written in Visual C++.
In one of my Visual C++ classes I convert a vector of strings to a collection of platform strings, which are understandable to the C# UWP application.
My problem is a Windows Runtime Bindable exception is thrown only in release mode of the application. Everything works perfectly in debug mode.
Visual C++:
// internalModel.cpp - the model I get my vector of strings from
std::vector<std::string> InternalModel::getAllPackages() {
std::vector<std::string> names;
for (auto i = 0U; i < packageOptions.size(); i++) {
// these are strings
names.push_back(packageOptions[i]["name"]);
}
return names;
}
// .h - the method signature called by my C# program
Windows::Foundation::Collections::IVector<Platform::String^>^ GetAllPackages();
// .cpp - the method body called by my C# program
Windows::Foundation::Collections::IVector<Platform::String^>^ VisualModel::GetAllPackages() {
auto s_packages = internalModel->getAllPackages();
auto p_packages = ref new Platform::Collections::Vector<Platform::String^>();
for each (auto s_package in s_packages)
{
p_packages->Append(WinUtil::toPlat(s_package));
}
return p_packages;
}
// WinUtil.h - the util class that converts standard string vector to platform collection of strings
template <class A, class B>
static Platform::Collections::Vector<B^>^ toPlat(std::vector<A*>* s_vector) {
auto p_vector = ref new Platform::Collections::Vector<B^>();
for each (A* s_elem in s_vector) {
p_vector->Append(ref new B(s_elem));
}
return p_vector;
}
C#:
// where I call the Visual C++ from
var packages = VisualLib.GetAllPackages();
foreach (var package in packages)
{
// package should be string here
}
I'm unable to figure out what is causing the exception because my debugger can't enter the UWP Runtime Library.
Perhaps the way I'm converting the vector to platform collection is not right, but then again, it works in debug mode just fine. Also other parts of my program use this same utility function:
static Platform::Collections::Vector<B^>^ toPlat(std::vector<A*>* s_vector)
The exception thrown:
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'Exception_WasThrown, Microsoft.CSharp.RuntimeBinder.RuntimeBinderException. For more information, visit http://go.microsoft.com/fwlink/?LinkId=623485'
I have a .net application that references the Microsoft.SqlServer.Smo assembly.
The assembly is not distributed with the application. Instead the sql sdk is installed in the system and the dll is registered in the GAC so that the application can load.
There is no problem with this except that on some target machines I have the v12 of the SDK, while on others I have the v13 of the SDK (that usually comes installed with SSMS).
I would like the application to load the latest version of whatever is available on the system, so v13 or, if not available, v12.
Is it possible to achieve this in code or through the application config?
The short answer to the question is to set SpecificVersion to false as correctly suggested by #sevzas.
Anyway, if on the system is installed SSMS 2016 update 13.0.16000.28, the 13.100.0.0 of the dll will be registered in the GAC and with the above change, this is the version that it will be loaded. Unfortunately this version is not meant to be used by 3rd party developers but only by Microsoft products, so trying to load it will generate an exception (see here). Someone could wonder at this point why they register it in the GAC if they don't want people to use it.
Anyway, I found a way to load the v13.0 (or previous, or future 14) with the below code by using the assembly resolve event.
static int Main(string[] args)
{
//we set an event handler at the begging of our program
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
//your stuff
}
private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
//if the dll is a sqlserver dll, we do our trick
if(args.Name.StartsWith("Microsoft.SqlServer"))
return LoadSqlAssembly(args.Name);
return null;
}
private static readonly int[] SqlVersions = new int[] {14, 13, 12, 11};
private static bool _reEntry = false;
private static Assembly LoadSqlAssembly(string name)
{
if (_reEntry)
return null;
name = name.Split(',')[0];
foreach (var version in SqlVersions)
{
try
{
_reEntry = true;
var ret = Assembly.Load($"{name}, Version={version}.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL");
//Logger.InfoFormat("Loaded {0} version {1}", name, version);
return ret;
}
catch (Exception)
{
//ignore exception
}
finally
{
_reEntry = false;
}
}
return null;
}
```
I'd like to run my WPF application from a python script, however am having difficulty.
To achieve this I have converted the WPF application to a COM library as follows:
namespace MyWpfApp
{
[Guid("F75D3377-D677-41BF-B3D5-C677C442228F")]
public interface IMyWpfAppInterface
{
void ShowCOMDialog();
void ClickButton1();
void ClickButton2();
}
[ClassInterface(ClassInterfaceType.None)]
[Guid("D936A84B-8B1C-4D62-B090-C06E3EB5EEE9")]
public class MyWpfClass : IMyWpfAppInterface
{
private static Thread m_runDlgThread;
private static MainWindow m_mainWindow = null;
private static Application m_app = null;
public MyWpfClass() { }
public void ShowCOMDialog()
{
m_msgHelper = new MessageHelper();
m_runDlgThread = new Thread(runDlg);
m_runDlgThread.SetApartmentState(ApartmentState.STA);
m_runDlgThread.Start();
}
public void ClickButton1(){// to do}
public void ClickButton2(){// to do}
private void runDlg()
{
Application m_app = new Application();
m_mainWindow = new MainWindow();
m_app.Run(m_mainWindow);
}
}
}
I have installed my assembly to the global assembly cache and registered the dll as follows
gacutil.exe" /i MyWpfApp.dll
REGASM MyWpfApp.dll /tlb:com.MyWpfApp.tlb
I have tested that I can successfully import the Typelib and run my WPF application from a win32 console application.
#include "stdafx.h"
#import "..\MyWpfApp\bin\Debug\com.MyWpfApp.tlb" named_guids raw_interfaces_only
int _tmain(int argc, _TCHAR* argv[])
{
CoInitialize(NULL); //Initialize all COM Components
// <namespace>::<InterfaceName>
MyWpfApp::IMyWpfAppInterfacePtr pDotNetCOMPtr;
// CreateInstance parameters
// e.g. CreateInstance (<namespace::CLSID_<ClassName>)
HRESULT hRes =
pDotNetCOMPtr.CreateInstance(MyWpfApp::CLSID_MyWpfClass);
if (hRes == S_OK)
{
const DWORD cTimeout_ms = 500;
HANDLE hEvent = CreateEvent(0, TRUE, FALSE, 0);
BSTR str;
pDotNetCOMPtr->ShowCOMDialog ();
bool toggle = true;
while(true)
{
DWORD dwWait = WaitForSingleObject(hEvent,cTimeout_ms);
if(toggle)
{
pDotNetCOMPtr->ClickButton1();
toggle = false;
}
else
{
pDotNetCOMPtr->ClickButton2();
toggle = true;
}
}
//call .NET COM exported function ShowDialog ()
}
CoUninitialize (); //DeInitialize all COM Components
return 0;
}
When I attempt to access the COM component from Python
import win32com.client
from win32com.client import constants as c
myWpf = win32com.client.Dispatch("MyWpfApp.MyWpfClass")
This fails, reporting
File "C:\Python27\lib\site-packages\win32com\client\dynamic.py", line 114, in _GetGoodDispatchAndUserName
return (_GetGoodDispatch(IDispatch, clsctx), userName)
File "C:\Python27\lib\site-packages\win32com\client\dynamic.py", line 91, in _GetGoodDispatch
IDispatch = pythoncom.CoCreateInstance(IDispatch, None, clsctx, pythoncom.IID_IDispatch)
com_error: (-2147221164, 'Class not registered', None, None)
I can see the class "MyWpfApp.MyWpfClass" int the registry and also from OLE Viewer.
I've done this kind of thing many times for a C++ based application without any problems. However this was with either an ATL project or MFC app with automation switched on. In this case I have converted WPF application to a dll and converted to COM by hand.
Could someone please advise what else I need to do to run the app from python?
Thanks in advance.
Further Edit :
I can load the typelib in python but still can't access the com class
I ran
import win32com.client
import pythoncom
myApp = pythoncom.LoadTypeLib("D:\\MyWorkSpace\\testProgs\\ATL_COM\\WPF\MyWpfApp\\MyWpfApp\\bin\\Debug\\com.MyWpfApp.tlb")
downloads_stat = None
for index in xrange(0, myApp.GetTypeInfoCount()):
type_name = myApp.GetDocumentation(index)[0]
type_iid = myApp.GetTypeInfo(index).GetTypeAttr().iid
print type_iid
print type_name
if type_name == 'MyWpfClass':
downloads_stat = win32com.client.Dispatch(type_iid)
This confirms that the classes are loaded but I can't access them because they are reported as not registered.
>>>
{B5E3A6C6-09A0-315C-BF3A-CB943389F610}
MessageHelper
{FBE23BB0-3EDC-3A65-90EB-DF84F7545D70}
COPYDATASTRUCT
{8BEE824F-F708-3052-BC21-A9EC4E1BB002}
MainWindow
{8C0044EF-91A9-3CB3-9945-1ACA076F3D7E}
NextPrimeDelegate
{F75D3377-D677-41BF-B3D5-C677C442228F}
IMyWpfAppInterface
{D936A84B-8B1C-4D62-B090-C06E3EB5EEE9}
MyWpfClass
Traceback (most recent call last):
File "D:\MyWorkSpace\testProgs\ATL_COM\WPF\MyWpfApp\MyWin32App\Python\MyPythonClient.py", line 15, in <module>
downloads_stat = win32com.client.Dispatch(type_iid)
File "C:\Python27\lib\site-packages\win32com\client\__init__.py", line 95, in Dispatch
dispatch, userName = dynamic._GetGoodDispatchAndUserName(dispatch,userName,clsctx)
File "C:\Python27\lib\site-packages\win32com\client\dynamic.py", line 114, in _GetGoodDispatchAndUserName
return (_GetGoodDispatch(IDispatch, clsctx), userName)
File "C:\Python27\lib\site-packages\win32com\client\dynamic.py", line 91, in _GetGoodDispatch
IDispatch = pythoncom.CoCreateInstance(IDispatch, None, clsctx, pythoncom.IID_IDispatch)
com_error: (-2147221164, 'Class not registered', None, None)
>>>
I can also confirm that there is an entry 'MyWpfApp.MyWpfClass' in the registry with the class id {D936A84B-8B1C-4D62-B090-C06E3EB5EEE9}.
Further Edit:
I tried installing Python for .Net and ran the following command
import clr;
import sys
sys.path.append('D:\\MyWorkSpace\\testProgs\\ATL_COM\\WPF\\MyWpfApp\\MyWpfApp\\bin\\Debug')
clr.AddReference("MyWpfApp.dll")
However this produced the following error
FileNotFoundException: Unable to find assembly 'MyWpfApp.dll'.
at Python.Runtime.CLRModule.AddReference(String name) in C:\Users\Barton\Documents\Visual Studio 2008\Projects\PySharp\trunk\pythonnet\src\runtime\moduleobject.cs:line 375
My knowledge of COM, Assemblies and typelibs are quite limited so I would appreciate if someone could help me understand what I need to do to access the DLL from python.
When I look at the entry in OLE/COM Object viewer, it points to the tlb file, not the dll, i.e.
Win32=D:\MyWorkSpace\testProgs\ATL_COM\WPF\MyWpfApp\MyWpfApp\bin\Debug\com.MyWpfApp.tlb
So, it is only the tlb file that is registered, not the class. When I run the LoadTypeLib class I am loading this from a path on my hard drive. I need the dll to be registered when I attempt to dispatch. Otherwise, if I can access this directly from a fixed path this would also be good but I don't know how to do this.
Again, thanks for your help.
I'd like to consume Mono's compiler as a service from my regular .NET 3.5 application.
I've downloaded the latest bits (2.6.7), created a simple console application in Visual Studio and referenced the Mono.CSharp dll.
Then, in my console app (straight out of a sample online):
Evaluator.Run("using System; using System.Linq;");
bool ress;
object res;
Evaluator.Evaluate(
"from x in System.IO.Directory.GetFiles (\"C:\\\") select x;",
out res, out ress);
foreach (var v in (IEnumerable)res)
{
Console.Write(v);
Console.Write(' ');
}
This throws an exception at Evaluator.Run (the first line):
Illegal enum value: 2049.
Parameter name: access
This is because the dll was compiled using Mono.exe, not csc.exe, I believe.
I've tried downloading the Mono.CSharp dll directly from http://tirania.org/blog/archive/2010/Apr-27.html in the demo-repl.zip file...and that does not throw an exception...However the out parameter (res) after calling Evaluator.Evaluate is null...so I'm not sure what's going wrong. No exception is thrown...
So, I'd like to figure out why the dll I downloaded from the demo-repl.zip returns null.
EDIT: I figured out why it returns null. It seems like for some reason the compiler isn't picking up the System.Linq namespace...though I can't tell why...If I just Evaluate "System.IO.Directory.GetFiles (\"C:\\")", it works fine.
UPDATE: It definitely seems like there's something wrong with the Mono compiler picking up referenced System assemblies. If I directly copy the sample of their csharp console tool:
csharp> var list = new int [] {1,2,3};
csharp> var b = from x in list
> where x > 1
> select x;
csharp> b;
I get the exception:
{interactive}(1,25): error CS1935: An implementation of `Select' query expressio
n pattern could not be found. Are you missing `System.Linq' using directive or `
System.Core.dll' assembly reference?
Also, in order for the MCS to actually be a feasible solution, I'll need to modify the compiler so that it emits to one single dynamic assembly, instead of emitting one assembly per evaluate call (otherwise it presents a major memory leak, which I've dealt with before in the form of the CSharpCodeProvider). Does anyone have an idea of how difficult this will be or can anyone point me in the right direction here?
Thanks.
Ok, I think I have some answers.
To resolve the assembly load problem, I can either place a call to Assembly.LoadWithPartialName inside Mono.CSharp.Driver.LoadAssembly, or do the following in my application
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
private static bool isResolving;
static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
if (!isResolving)
{
isResolving = true;
var a = Assembly.LoadWithPartialName(args.Name);
isResolving = false;
return a;
}
return null;
}
To make Mono reuse the same dynamic assembly for each Evaluate/Compile call, all I had to change is the following (although there are probably complexities I'm missing here).....
Inside Mono.CSharp.Evaluator, I added the property:
/// <summary>
/// Gets or sets a value indicating whether to auto reset when evaluations are performed and create a new assembly.
/// </summary>
/// <value><c>true</c> if [auto reset]; otherwise, <c>false</c>.</value>
public static bool AutoReset { get; set; }
Then...make sure Reset is called at least once in Init:
static void Init ()
{
Init (new string [0]);
Reset();
}
And finally, in ParseString, simply don't reset unless AutoReset is true...
static CSharpParser ParseString (ParseMode mode, string input, out bool partial_input)
{
.
.
.
if (AutoReset) Reset ();
According to Miguel's blog page you linked, you have to add a reference to System.Core in order to use LINQ on .Net.
csharp> using System.Linq;
csharp> from x in "Foo" select x;