How to add native DLLs to ClickOnce deployment of .NET app - visual-studio

I've been trying for days to figure out how to get my native C++ DLL dependencies included in my ClickOnce deployment of a C# WinForms app built with VS2019. The native DLLs do not appear under Publish -> Application Files on the Properties page of the main .NET app (though the .NET DLLs do).
I've read this a hundred times:
Set the Build Action for the native DLLs to 'Content'.
... and I think I'm interpreting/doing that wrong.
Output from the native C++ projects is naturally not 'included' in any projects, (an apparent prerequisite for exposing the Build Action property,) and thus does not appear in Solution Explorer to allow me to set it to 'Content'. So I
[Solution Explorer] -> Project -> Add -> Existing Item -> [select native C++ DLL]
to add the native C++ DLLs to the Project to enable the Build Action property, which I then set to 'Content'. {Important Note: It has to be 'included' in a Project, rather than just the Solution to get a Build Action property.}
So I do that and it works, but of course I had to select a specific platform and configuration (e.g., x64 & release) of the native DLL, and this selection is fixed (not controlled by the selections in the VS2019 GUI when I build), and worse -- not even labeled as to which platform & configuration is 'included' in the project. {Side note: How did I not have to select which version (x86 vs x64) of the .NET DLLs to use under Publish -> Application Files ? It just automatically picks the right ones? How do I set up an x86 version and a x64 version that I can switch back & forth between & build each?} I cannot imagine this is the way it is supposed to be done. It is fragile and opaque. Surely there is a better way. I think I'm missing something that everyone else finds 'obvious'. Any other developer who tries to use or maintain this configuration will curse my name, and be right for doing so.
What is the 'right way' of making the ClickOnce deployment (via the VS2019 GUI) include my native DLLs (the projects for which are included in the same solution) in the ClickOnce deployment package?
Note, I found one promising setting in the Properties Page for the native C++ projects: Custom Build Setup -> General -> Treat Output as Content. But it does not seem to have any effect.
I'd be eternally grateful for any pointers.

After refining this for another day or so, I've found that the VS2019 GUI just comes up short for this purpose. The better answer is to just manually edit your .csproj file for the .NET project to Include the native DLLs as Content. Find the other elements in that project file and add the native DLLs like this:
<ItemGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<Content Include="..\bin\MyApp\x64\Release\native1.dll">
</Content>
<Content Include="..\bin\MyApp\x64\Release\native2.dll">
</Content>
</ItemGroup>
<ItemGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<Content Include="..\bin\MyApp\x86\Release\native1.dll">
</Content>
<Content Include="..\bin\MyApp\x86\Release\native2.dll">
</Content>
</ItemGroup>
(where *..\bin\MyApp{x86|x64}{Debug|Release}* is your output folder where your native DLLs, native1.dll and native2.dll have been copied, post-compile, to be used by your .NET app, MyApp.exe). Of course the x86 folder contains the 32-bit native DLLs, the x64 folder contains the 64-bit native DLLs, etc. - you know the drill.
No confusing extra links and whatnot to clutter up the solution/project, and the .dll files appear where they are supposed to, rather than in separate child sub-directories.
Of course you could add additional elements for the remaining conditions -- namely the debug builds, but who wants ClickOnce deployments for debug versions? You're probably running those directly from Visual Studio, right?

Adapted from here :
Compile your solution.
Right click on the managed project and select "Add/Existing Item". Do not use "Add Reference".
Navigate to your compiled native DLL and select it (adjust file types as needed to expose it).
Click on the down arrow in the "Add" split button and select "Add As Link" (this allows us to not keep multiple copies of the DLLs floating around).
Right click on that freshly added file and select "Properties".
Make sure "Build Action" is "Content" and "Copy To Output Directory" is set to "Do not copy" (since you already automated that task elsewhere, long before getting to the deployment stage of development).
Note that you'll get a 'File Not Found' error upon initial build after a proper cleaning of all output folders, but the native DLL will be created anyway, preempting that error on the next full build.
On the Properties page for the .NET app, do Publish -> Application Files -> Reset All to populate the native DLLs into the list. Adjust 'Publish Status' et. al. as needed.
Publish.
I found that I can maintain a 'virtual' folder structure in the project to store the links to the various versions (e.g., x86 vs. x64 and debug vs. release) of the native DLLs without cluttering up the file system, (and to ensure the DLLs aren't stale): Add the folder structure (e.g., ".\NativeDLLs\x64\Release", etc.) via the Solution Explorer, and add Links only (no real files) to the folders. Then delete the folders from the file system using Windows Explorer or shell commands. They will remain in Solution Explorer after deletion from the file system because they still contain the links.
The hierarchy of those virtual folders now exists only in the project file ([appname.csproj]) as Content elements (containing the Links) within Item Group elements (which seems to be the key to getting them to appear in the ClickOnce deployment world).
One pointer (for myself) that would have helped: Don't be afraid to hit the Reset All button on the Publish -> Application Files dialog.

Related

Windows 10 Universal application - embedding different native libraries depending on architecture

I created a blank Windows 10 Universal application with Visual Studio 2015 RC:
File > New > Project ... > Windows Universal > Blank App (Windows Universal)
I want to use existing native libraries provided by a third-party. Those libraries are built from a C codebase and only use whitelisted Windows Store APIs.
I copied foo.dll beside App1.vcxproj then added it to the project and modified link settings to use foo.lib (the import library corresponding to foo.dll) for the x86 architecture. I also right-clicked foo.dll and set the Content property to Yes which makes Visual Studio embed the .dll with the application.
So far so good, I can use / debug my app that makes use of the third-party library. Visual Studio somehow deploys foo.dll next to App1.exe inside the AppX folder. And foo.lib (the import library for foo.dll) manages to load foo.dll successfully when the application start (this is because foo.dll is deployed next to App1.exe).
Now, for that third-party library, I have one .dll file per architecture:
foo/bin/x86/foo.dll
foo/bin/x86/foo.lib
foo/bin/x64/foo.dll
foo/bin/x64/foo.lib
foo/bin/arm/foo.dll
foo/bin/arm/foo.lib
And here comes my question: while keeping a single Visual Studio project for my app, how can I convince Visual Studio to:
deploy foo/bin/x86/foo.dll next to App1.exe when building for x86
deploy foo/bin/x64/foo.dll next to App1.exe when building for x64
deploy foo/bin/arm/foo.dll next to App1.exe when building for arm
What I tried so far is putting the different foo.dll files inside solution folders, e.g.
third-party/foo/x86/foo.dll
third-party/foo/x64/foo.dll
third-party/foo/arm/foo.dll
That could have worked since I can conditionally set the Content property to Yes for each .dll file. However, using solution folders makes Visual Studio deploy the .dll file in a sub-folder, e.g. AppX\third-party\foo\x86\foo.dll for the x86 architecture. Consequently when the application starts it doesn't find the shared library anymore. I wish there was a way to control deployment target location, I think that would solve my use case.
Hope my explanations are clear enough.
Just use a pre-build command line — per configuration so you can copy the right DLL from different source folders to project folder before packaging.

Howto save the Target Platform in a VisualStudio Solution (with version control and testing in mind)

Visual Studio (at least VisualStudio 2010) stores the target platform settings in the *.suo file which obviously shall not be version controlled.
In my case this is no problem for the central build because that uses a command line option on msbuild that force the target platform to be x86 as required.
However, if a colleague checks out my project he will always end up building for AnyCPU and testing that. Because he has no *.suo file VisualStudio will use the default settings.
Bad or not, the colleague is obliged to test for x86.
Is there an easy way to safely persist the target platform for a Solution? An environment variable forcing the default is not exactly what we need but would be good enough and easy enough.
Visual Studio ... stores the target platform settings in the *.suo file
It doesn't, it stores it in the project file. A relevant snippet from one I created:
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>x86</PlatformTarget>
// etc...
</PropertyGroup>
It is configured with Project + Properties, Build tab, Platform target combo box. Repeat for the Release configuration. Only the setting on the EXE project matters, that's the one that determines the bitness for the process. DLLs have no choice and ought to use AnyCPU.
In all likelihood you are being tripped up by a rather drastic design mistake in VS2010. Another item is the solution platform name, prominently displayed in the Build + Configuration Manager dialog for example. This was always AnyCPU for managed projects, VS2010 screwed this up royally by renaming the default to "x86". And creating a big old mess of it when you import projects from earlier versions, yielding a "Mixed platforms" configuration. And yes, the last selection is saved in the .suo file.
This is irrelevant to managed projects, it only matters to C++ projects. Where the setting selects a different set of build tools. The 64-bit compiler and linker are different programs. A non-existing issue for managed projects, bitness is determined at runtime by the jitter selection and you use the exact same C# compiler regardless of the desired platform target.
The best way to eliminate these kind of mistakes is by aggressively deleting platforms and only keeping one. Use Build + Configuration Manager, select the "Edit" entry in the upper-right combo box and click Remove for extraneous platforms until you only have AnyCPU left. Updating your VS version is also recommended, this mistake was corrected again in VS2012.

VS2010 "Copy to Output" from secondary reference

I have 3 C# projects, A (WPF application), B (class library), and C (class library), such that A references B, and B reference C. Project C needs to call some native methods from a C++ DLL via P/Invoke. I added the native DLLs to the C# project and marked them a "Copy to Output Directory". When I build my solution, the native DLLs show up in the output directory for Projects B and C (correctly), but not for Project A. Is there a project setting that allows these to be copied by any project that ultimately references Project C (even if not directly)? Or do I just need to post-build event on Project A to copy this files to my application output folder?
I've looked at Dependencies of references not copied to output directory, but this was referring to project references, so I'm wondering if there is a solution in my case.
I also considered embedding the native DLLs as resources and modifying my DLLImport as in this MSDN article: http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.dllimportattribute.dllimportattribute.aspx. But I get an E_ACCESSDENIED error (I've seen others with this same issue as well, as well as some concerns about triggering antivirus behavior when extracting the DLL to disk). I also noticed the article mentions linking the resource, rather than embedding it. Is this something I need to do as an MSBuild task, rather than through some project properties?
Worst case, I could just add a post-build event to my WPF application that copies the native files, but it would be nice if Visual Studio would recognize that these files should be copied.
I solved this by customizing the output for debug/release mode compiles (on the project properties window) so that all of my projects outputted to the same folder... Much like how an ASP.NET application is published where all DLLs end up in a single /bin folder. That fixed my issue.

DirectX SDK integration with VS 2010

I'm not sure if anyone has noticed but there seems to be a conflict with the DirectX SDK and VS2010's Windows SDK. If you look inside the folder under the directory
C:\Program Files (x86)\Microsoft
SDKs\Windows\v7.0A\Include
You will see it contains the old headers for DirectX 11. The above directory is by default included to each VS 2010 project file and is required in order for VS 2010 to be able to compile correctly.
The same is true for .lib files for DirectX.
Now here lies the problem, to include the Directx SDK to your project in VS2010 you add the directories via the project property sheet. This automatically means you are including both the old headers and libs for DirectX as well as the new ones... :(
If you think you're building with the latest DirectX libs and header files you may very well be mistaken as the compiler could be using the unintended files.
How can I get around this problem as I can't seem to compile anything without keeping the default project settings ?
Also bare in mind I am using C++ and VS2010 Ultimate from MSDNAA.
Short answer: It probably doesn't matter.
Updated DXSDK installation won't update the system DLLs that ship with windows. It doesn't matter if you are including/linking with the DXSDK directory or the v7.0A directory. When the app runs, it loads the same DLLs either way. (Notable exception: the D3DX_xx.dll for helper functions - as those aren't OS components, they ship with the SDK and are meant for inclusion in the app setup package). The header files that ship with DXSDK should be nearly identical to what's in the v7.0a directory.
And if I'm not mistaken, include and lib directories specified in the Project Settings dialog for your app take predence BEFORE default SDK dirs. So updating your Project Settings dialog should be ok.
But if you really want to be sure... Instead of adding the DXSDK header/libs for each project, make them default search directories for all projects.
From the top-level menu for Visual Studio: Select Tools->Options.
From the left-nav menu on the Options dialog select "Project & Solutions", and "VC++ Directories" underneath that.
Then on the dropdown in the top right for "Show Directories for", select "Include Files".
Makes sure your $(DXSDK) include directory comes before the $(WindowsSdkDir) entry. If it's not already there, add it.
Repeat this for the "Library Files" option under the "Show Directories for" menu option.

How to perform "shell" icon embedding in Visual Studio 2010?

As far as I can tell, there have been (at least?) three types of icon embedding. There's the original style used by shell32.dll and friends, .NET's embedding, and the new type that WPF uses. I'm looking for how to perform the first one, as I want to have a few other icons available as resources for a jumplist, which can only accept that style. However, I can't figure out how to embed in this style, only the other two.
How do I do this? All the results I find on google, etc are for adding icons to ResX files or similar.
I never heard the term "icon embedding" before. If you are talking about the icon that's visible for a EXE or DLL in Explorer or a desktop shortcut: that's done the same way for any Windows program. Both WF and WPF give the assembly an unmanaged resource with the selected icon using the /win32res compile option. You can see it in Visual Studio with File + Open + File, select the EXE or DLL.
To create a .res file, first create a .rc file. You can create one with the C++ IDE. Right-click the solution, Add New Project, Visual C++, Win32, Win32 Console Application. Right-click the Resource Files folder, Add + Resource, select Icon, Import. select your file. Repeat as needed. After you build, you'll get a .res file in the project's Debug build directory.
Back to your C# project, Project + Properties, Application tab. Select the Resource File option and navigate to the .res file.
I'd highly recommend taking a look at this solution posted here (http://einaregilsson.com/add-multiple-icons-to-a-dotnet-application/). It integrates right into a ms build post build event and doesn't require an unmanaged project (to create an assembly from a .rc/.res file).
This removes a dependency on managing a second solution / assembly anytime you want update an icon and saves you from IL Merging the compiled c++ assembly.
I'd also recommend taking a look at WIX for your deployment. I've written a guide that accompanies this answer located here.

Resources