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.
CodePudding user response:
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.
CodePudding user response:
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?