How to find from where the dll is loaded when we use DllImport - dll

I'm using DllImport in my C# code to invoke a function from a dll. I register this dll using regsvr32 command and all works good. Then I unregister the dll and deleted it. But still my code works. Later I found that I have a copy of the same dll in C:\Windows\System32 directory. I may have this dll path added in system environment path. My question is how can I find, from which loacation the dll is loaded?
This is how I use DllImport in my code
[DllImport("abcd.dll", CharSet = CharSet.Auto, SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CanStart();

Related

New (.NET Core) C++/CLI project has compile issues when definition and implementation are split

I created a "CLR Empty Project (.Net Core)" project using Visual Studio 2019.
I simply created a new class using the 'add class' menu option and it generated this class.
I added the function called Test in the header:
using namespace System;
public ref class Class1 {
// TODO: Add your methods for this class here.
void Test();
};
Then using visual studio's generate implementation option it created this function defenition in the .cpp file:
#include "EngineEditorLayer.h"
#include "pch.h"
void Class1::Test() { throw gcnew System::NotImplementedException(); }
When compiling it gave me this error :
error C2653: 'Class1': is not a class or namespace name
I can only resolve this error by moving the implementation to the header file.
Am I missing something? Is there a setting I have to change to enable .cpp compilation?
Is there a compiler bug that prevents me from doing this currently?
Hans Passant from the comments was right. The pch.h has to be included first.
I unfortunately never got the warning. This was my output log:
1>------ Build started: Project: EngineEditorLayer, Configuration: Debug x64 ------
1>EngineEditorLayer.cpp
1>E:\Other Projects\PixEngine\EngineEditorLayer\EngineEditorLayer.cpp(7,18): error C2653: 'Class1': is not a class or namespace name
1>Done building project "EngineEditorLayer.vcxproj" -- FAILED.

How to specify the path to a VS extension DLL from an MSBuild <UsingTask> tag

I'm developing a Visual Studio extension. The extension's associated VS project template includes a call to a custom task in the extension's DLL:
<UsingTask TaskName="MyTask" AssemblyFile="path to MyDLL.dll" />
The extension will be installed in the usual place, through use of the VSIX installer.
My question is: Is there a good MSBuild property or macro that I can use to construct the path to the extension's DLL (i.e., MyDLL.dll)? I'm aware of $(DevEnvDir) and could extend that path when using the project and extension in Visual Studio 2015 (append \VendorName\ProductName\Version), but that doesn't seem to work in VS 2017, where the appended path uses a mangled name that can't be predicted ahead of time (or can it?). There's also the issue that the project/extension should work in the VS experimental instance, which does not appear to reflect $(DevEnvDir).
Is there any good way to do this with MSBuild properties, or will I need to look at alternatives like environment variables or the registry?
Is there any good way to do this with MSBuild properties, or will I need to look at alternatives like environment variables or the registry?
You can use environment variables or the registry to achieve it.
environment variables
you could use environment variables like this:
<UsingTask TaskName="MyTask" AssemblyFile="$(yourenvironmentvariablesname)MyDLL.dll" />
For more information, please refer to:
https://learn.microsoft.com/en-us/visualstudio/msbuild/how-to-use-environment-variables-in-a-build
registry
You could use registry like this:
<UsingTask TaskName="MyTask" AssemblyFile="$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework#DbgManagedDebugger)MyDLL.dll" />
Note: please change related registry path as you want.
https://blogs.msdn.microsoft.com/msbuild/2007/05/04/new-registry-syntax-in-msbuild-v3-5/
The solution that made sense for me was to create a wizard and to set the path to the extension install location in the replacements dictionary and use the replacement in the template with the UsingTask.
public class ProjectLocationWizard : IWizard
{
public void BeforeOpeningFile(ProjectItem projectItem)
{
}
public void ProjectFinishedGenerating(Project project)
{
}
public void ProjectItemFinishedGenerating(ProjectItem projectItem)
{
}
public void RunFinished()
{
}
public void RunStarted(object automationObject, Dictionary<string, string> replacementsDictionary, WizardRunKind runKind, object[] customParams)
{
var wizardDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
replacementsDictionary.Add("$installlocation$", wizardDirectory);
}
public bool ShouldAddProjectItem(string filePath)
{
return true;
}
}
<UsingTask AssemblyFile="$installlocation$\MyTask.dll" TaskName="MyTask" />
Although the wizard docs say to sign the wizard assembly, I did not, and it works fine without.

DLL Pinvoke with Windows Mobile C++ libraries porting to C#

I am trying to use OpenCV as here, and I am stuck at one moment where I get PInvoke, namely:
my DLL.cpp
#define DLL_API __declspec(dllexport)
//...
DLL_API short processImage(const char* in_file, const char * out_file)
//...
my form.cs
[DllImport("DLL", EntryPoint = "processImage")]
private static extern short _ProcessImage(byte[] in_file, byte[] out_file);
public static short binarizeImage(string in_file, string out_file)
{
return _ProcessImage(StringToASCIIByteArray(in_file), StringToASCIIByteArray(out_file));
}
public static byte[] StringToASCIIByteArray(string str)
{
return Encoding.ASCII.GetBytes(str + "\0");
}
I think that this might be a problem with target architecture (in my VS 2008 project). When I use 'Any CPU' it compiles & runs but throws Pinvoke, when I set it to 'Windows Mobile 6 Professional SDK (ARMV4I)' it compiles but doesn't want to deploy and I got this in output window:
1>------ Deploy started: Project: DLL, Configuration: Debug Windows Mobile 6 Professional SDK (ARMV4I) ------
1>The system cannot find the path specified.
1>
2>------ Deploy started: Project: smartDeviceOcr, Configuration: Debug Any CPU ------
2>Deploying 'D:\VS 2008 Projects\C++\SmartDevice\ocr\smartDeviceOcr\bin\Debug\smartDeviceOcr.exe'
========== Deploy: 1 succeeded, 1 failed, 0 skipped ==========
Does the specific ARMV4I matter ? I have ARM920T on my mobile. Can/should I edit this to make it work ?
EDIT:
Just to be clear the Pinvoke points to :
return _ProcessImage(StringToASCIIByteArray(in_file), StringToASCIIByteArray(out_file));
and the exception message is :
System.MissingMethodException was unhandled
Message="Cannot find the library DLL PInvoke 'DLL'."
StackTrace:
in smartDeviceOcr.Form1.binarizeImage(String in_file, String out_file)
in smartDeviceOcr.Form1.button1_Click(Object sender, EventArgs e)
in System.Windows.Forms.Control.OnClick(EventArgs e)
in System.Windows.Forms.Button.OnClick(EventArgs e)
in System.Windows.Forms.ButtonBase.WnProc(WM wm, Int32 wParam, Int32 lParam)
in System.Windows.Forms.Control._InternalWnProc(WM wm, Int32 wParam, Int32 lParam)
in Microsoft.AGL.Forms.EVL.EnterMainLoop(IntPtr hwnMain)
in System.Windows.Forms.Application.Run(Form fm)
in smartDeviceOcr.Program.Main()
EDIT2:
Ok now it's really strange. I have changed few things. I have added the openCV's dlls to the deployment list in the project properties so that I can see that they are being copied on deployment and I have copied manually all the dlls to exe directory on the PC.
I have also changed some of the deployment options in DLL project so that the dlls are copied to the proper directory (automatically) on the phone and ....
now I have the error on runtime (when trying to access the function from the dll - opencv) :
The remote connection to the device has been lost
As I don't see any answers I post my answer (although I still have problems with this)
The problem can be solved by adding directories to which dlls should be deployed to:
Project-> Properties -> Deployment -> Remote Directory
and properly specify files in:
Project-> Properties -> Deployment -> Additional Files
as like
highgui200.dll|$(SolutionDir)\opencv_winmo\dll|%CSIDL_PROGRAM_FILES%\smartDeviceOcr|0
cv200.dll|$(SolutionDir)\opencv_winmo\dll|%CSIDL_PROGRAM_FILES%\smartDeviceOcr|0
cxcore200.dll|$(SolutionDir)\opencv_winmo\dll|%CSIDL_PROGRAM_FILES%\smartDeviceOcr|0
ml200.dll|$(SolutionDir)\opencv_winmo\dll|%CSIDL_PROGRAM_FILES%\smartDeviceOcr|0
msvcr90.dll|$(BINDIR)\$(INSTRUCTIONSET)\|%CSIDL_PROGRAM_FILES%\smartDeviceOcr|0

Is it possible to Export a C++ CLI interface with MEF and Prism

I have a C++/CLI interface defined in a C++ library (Compiled with the /clr switch)
I also have a C# library.
My C# library defines:
- a class that implements Prism IModule interface.
- a class that implements the C++/CLI interface and is decorated with MEF Export attribute.
both the C# and the C++\CLI library are deployed into the same folder.
I am getting a ModuleLoadException from Prism saying that it can't find my C++/CLI assembly or one of its dependencies.
If I replace the C++/CLI assembly with a .NET one, everything works fine!
My question is then , is it at all possible to export a class that implements a C++\CLI interface with the export type being that interface?
Why do I have the interface defined in a C++/CLI library? I was hoping that a legacy C++ DLL we have could actually define their contracts in that C++\CLI libraries and have C# libraries reference that contract dll.
Maybe my approach is wrong, please let me know if you think there is a better way to achieve this.
I haven't really spent much time with C++/CLI before, but as it's a CLS-compliant language, it should just work. Here is an example
// CPPMEF_CPP.h
#pragma once
using namespace System;
using namespace System::ComponentModel::Composition;
namespace CPPMEF_CPP {
[InheritedExportAttribute]
public interface class ILogger
{
public:
virtual void Log(System::Object^ obj) = 0;
};
}
And in my C# console app:
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition.Hosting;
using System.Linq;
using System.Text;
using CPPMEF_CPP;
namespace CPPMEF_CSharp
{
class Program
{
static void Main(string[] args)
{
var catalog = new AssemblyCatalog(typeof(Program).Assembly);
var container = new CompositionContainer(catalog);
var logger = container.GetExportedValue<ILogger>();
logger.Log("Test");
Console.ReadKey();
}
}
public class ConsoleLogger : ILogger
{
public void Log(object obj)
{
Console.WriteLine(obj);
}
}
}
There should be no special requirements for deploying C++/CLI assemblies, as it's all the same at deployment anyways. Can you check that any dependencies are deployed with your C++/CLI assembly too?

Extract an unreferenced assembly from xap file

I have a xap file that contains an unreferenced assembly: b.dll.
This assembly was put in the xap file manually (by a post build step, in which I just add the dll to zip(xap) file).
Now at runtime I want to access b.dll and call CreateInstance on it.
This is where I am stuck. How can I get an Assembly instance for b.dll from the xap file?
Thank you!
You can initialise a StreamResourceInfo object with a downloaded zip stream (Xap or otherwise).
You can then use Application.GetResourceStream to pull a stream for file from that zip using a Uri. In this case the dll which can then load with AssemblyPart and then call a CreateInstance on it:-
WebClient client = new WebClient()
client.OpenReadCompleted += (s, args) =>
{
StreamResourceInfo zip = new StreamResourceInfo(args.Result, "application/zip");
StreamResourceInfo dll = Application.GetResourceStream(zip, new Uri("b.dll", UriKind.Relative));
AssemblyPart assemblyPart = new AssemblyPart();
Assembly assembly = assemblyPart.Load(dll.Stream);
_someClassFromB = assembly.CreateInstance("b.SomeClass");
};
client.OpenReadAsync(new Uri("your.xap", UriKind.Relative));