Project reference vs. DLL Reference - Which is better? - visual-studio

I know there are other questions regarding this subject, and I've looked at this question, but I'd like to see a little bit more discussion and information on both sides of this - is it a better practice to add a project to a solution and reference the project, or to add a reference to the .dll?

It's not much of a choice. If you have a solution with both projects then use a project reference. If your solution doesn't have the project then you have to use an assembly reference.
So the real question should probably be: do I create a solution with both projects? Yes, as long as the project is still in the debug stage and liable to require bug fixes.

If you only have the dll then you're stuck with a dll reference (obviously).
If you have the source then it's usually better to use a project reference. There might be cases where you have a utility library that's never going to change, but if there's the slightest chance of you needing a bug fix then having a project reference is going to make debugging a lot easier.

Summary - Project Reference by Project vs by DLL
Reference by project
code is visible
finds all references e.g. on a class (because code is visible)
better for testing (over all)
better for code redesign (impact)
Reference by DLL
code is hidden
separation between e.g. framework and project (for deliver of framework)
quicker compilation (because DLL is already compiled)

Well, project references are helpful when you are building and testing in both debug and release mode. If you directly add a DLL then you are locked into whatever that particular DLL was built as. The project reference allows this to be a build time decision.

Relative to your project architecture, you should always stick to projects within your problem domain. You should be using the GAC, if that is applicable to your environment.

Related

How to use JNI4NET when your C# library depends on existing managed dll?

My .NET program I want to use in Java depends on SlimDX, a managed wrapper over DirectX. I add it to the project references as normal without hiccup.
However, when it comes to using JNI4NET's build.cmd, I get a CS0400 error suggesting that it does not know what the hell SLimDX is, even though I referenced it properly and put it in the folder with proxygen. It cannot be found in the 'global namespace'.
This ('global::net.sf.jni4net.utils.Convertor.StrongJp2C')
is one of the offending lines.
Actually, I figured it out! It's simple, there is a -dp option in proxygen to add .NET dependencies.

"always rebuild" due to C++/CLI referencing COM in same solution

I have a problem similar to VS2010 always thinks project is out of date but nothing has changed (I'm also on VS 2010):
I Enabled C++ project system logging which told me that:
00000727 29.93245506 [5864] Project 'C:\foo.vcxproj'
not up to date because 'C:\foo\INTEROP\INTEROP.bar.1.0.DLL'
was modified at 01/22/2014 11:02:49,
which is newer than 'C:\foo\RELEASE\METAGEN.WRITE.1.TLOG'
which was modified at 01/22/2014 16:02:30.
This is apparently telling me that foo project must be rebuilt because either bar.dll or the interop have changed.
foo is a C++/CLI project.
bar is a COM DLL.
foo has bar.dll as one of it's references.
I haven't rebuilt bar.dll (date for the dll file is yesterday).
I haven't modified any settings in project foo (to affect interop).
My question is: Why is Visual Studio deciding the interop is out of date and triggering a re-build on every single run of the application?
Note: This is a web application. foo is directly referenced from the web. bar is not directly referenced by the web.
EDIT:
I've created a simple look-alike solution with just 4 projects (2 for COM, website, and C++/CLI assembly). It seems the C++/CLI assembly always updates the INTEROP.bar.*.DLL file every time any build is triggered. This doesn't seem to be the case in the solution having problems.
This was my mis-understanding: I thought the interop DLL should only be updated if 1) the reference is re-added. 2) The COM object being referenced (possibly just the API) changed.
Apparently, interop.dll is updated every build of caller.
Finally this wording is extremely confusing to me and seems incorrect:
A was modified at 11:02:49, which is newer than B which was modified
at 16:02:30.
How could something from 11:02 be "newer than" something from 16:02? (almost feels like a backwards >= / <= check)
PS - I'm not adding the example solution here, because it doesn't fail like the real solution does.
Sorry for the confusion. It looks like I was leaving out one level of indirection in the dependencies. The chain was: ASP.NET Website -> C++/CLI Assembly -> COM DLL -> C/C++ Native DLL. All in a single solution.
We ended up refactoring to move all the COM DLL code into the C++/CLI Assembly changing it to merely: Web -> C++/CLI Assembly -> C/C++ Native DLL. At this point the problem went away.
It's not a very satisfying answer, but I don't have enough spare cycles to really dig into it now that it's no longer causing trouble.

General Compilation Problems VS 2010

I'm running VS2010 Version 10.0.30319.1 RMTRel
I've noticed problems compiling VB.NET application. When I "rebuild" the solution it reports the build was successful. When I then click the run icon to begin debugging, then the compiler will report build errors(often related to referenced projects). I've confirmed all the projects are targeting the same framework and after an undeterministic number of times repeating the same steps, it will eventually compile. This seems consistent enough to me with other code bases to believe that it's a problem with VS. Anyone have any thoughts that might help improve my experience?
You should also check your configuration manager - probably some of projects are disabled for building in current build plan.
is this a rather large solution? If so, the order of build may be out of whack and the way to solve that is to set the build order of the projects to make sure all of the dependent projects are built first.
One common reason is circular references. You cannot do this in a pair of projects, but it can be done if you cobble together a long string of projects. The way to catch this is a dependency mapping tool with a visual representation of dependencies. You will see the items that refer back up to the top.

Is this the correct way to eliminate warning C4945 (symbol already imported from another assembly)?

I've got a .net solution (written in C++/CLI) which references some .dll projects as follows:
MainProject->ProjectA->ProbjectB
MainProject->ProjectB
Originally I'd referenced both ProjectA and ProjectB from MainProject which gave me the warnings as mentioned above.
I can remove the warnings by removing the reference to ProjectB from ProjectMain but it makes it less obvious that MainProject relies on ProjectB. Is this the right thing to do to get rid of the warnings?
Speaking in general terms, a system of dependencies can be depicted by a directed graph where each node is a software component and each edge is a dependency. In my opinion, the more simplification that can be done to the graph, the better.
Yeah that's fine.
If you have ReSharper, you can view the dependency graph by right-clicking ProjectMain --> Project Hierarchy.
I just want to describe, but not explain, following relevant behaviour.
project CSCommon in C#
project CS1 in C#, using CSCommon
project CPP1 in C++, using CSCommon
project CPPMain, using CPP1
If each project has its own output path, I recieve C4945.
If all projects have common outputh path, warning disappears.
I had the same problem as you. And I solved it exactly as you described it: remove the reference to 'Project B' (in your specific case).
That is the only way I know how to fix this error, short of disabling it.
No, removing the reference is probably not the correct way to handle it.
See https://stackoverflow.com/a/12423588/321013
Set Use Dependencies in Build=false for your references.
The point is, that you should have all references that the code in the project itself uses as direct references, but the setting Use Dependencies in Build=TRUE interferes with that, as it pulls in the transitive references also, generating conflicts if you also have direct references. (At least on my VS2005)

Strange VB6 build problems (related to nlog)

This I think is related to my use of the nlog C++ API (and my question on the nlog forum is here); the purpose of my asking this question here is to get a wider audience to my problem and perhaps to also get some more general ideas behind the VB6 IDE's failure to build in my particular scenario.
Briefly, the problem that I am having is that I am having trouble building VB6 components which reference unmanaged C++ components which have calls to nlog's C\C++ API (which is defined in NLogC.DLL). The build problems are not occurring during compile time, they are occurring when the binary is being built which suggests to me that it's some kind of linker type problem? Don't know enough about how VB6 binaries are produced to tell. The VB6 binary is produced, but it is corrupted and crashes shortly after it is invoked.
Has anyone had any similar experiences with VB6 (doesn't have to be related to nlog or C++)?
edit: Thanks for all the responses to this rather obscure problem. Still no headway unfortunately; my findings since I posted this:
'Tweaking' the compile options doesn't appear to help in this problem.
Adding a reference to the nlog-enabled C++ component from a 'blank' VB6 project doesn't crash it or cause weird build problems. So it isn't a 'native' VB6 issue, possibly an issue with the interaction between nlog and the various components and 3rd party libraries used by other referenced components?
As for C++ calling conventions: the nlog-enabled C++ component is - as far as I can see - compliant to these conventions and indeed works fine when referenced by VB6 as long as it is not making any nlog API calls. Not sure if the nlogc.DLL itself is VB6 compliant but I would have thought that that is immaterial since the API calls are being made from the C++ component; VB6 shouldn't know or care about what the C++ component is referencing (that's as far as my understanding on this goes...)
edit2: I should also note that the error message obtained during build is: "Errors during load. Please refer to "xxx" for details". When I bring up the log file, all that there is in there is: "Cannot load control xxx". Interestingly, all references to that particular control disappears from that particular project resulting in compile errors if I were to try to build again.
Got around the problem by using NLog's COM interface (NLog.ComInterop.DLL) from my unmanaged C++ code. Not as easy to do as the C\C++ API but at least it doesn't crash my VB6 components.
I would try tweaking some of the Compile options found in the Project, Properties menu, Compile panel to see if they yield any additional hints as to what is going wrong.
For example if you compile the executable to p-code rather than native code does it still crash on startup.
What error message do you get when you run your compiled binary?
I doubt the compiler/linker is the problem: project references in a VB6 project are not linked into the final executable. A project reference in VB6 is actually a reference to a COM type library (which may or may not be embedded in a .dll or other binary file type). Project references primarily serve two purposes:
The IDE extracts type information from the referenced type libraries which it then displays in the Object Browser (and in the Intellisense drop-down)
At compile-time, the compiler extracts the type information stored in the referenced libraries, including the CLSID of each class that you instantiate, and embeds this data into the executable. This allows your executable to create instances of classes contained in the libraries that you referenced.
Note that the compiled binary doesn't link to any code in the referenced libraries, and it doesn't even contain the filenames of the referenced libraries. The final executable only contains the CLSID's and other type information that it needs to instantiate COM objects at run-time.
It is much more likely that the issue is with NLog, or with how you are calling it from your code, rather than something gone awry in the VB6 compile process.
If you think it might be a linker problem, this should crash it the same way:
create a new standard project (of any kind)
add a new module and copy the "declare"-statements into it
compile
If it doesn't crash it is something else.
It would help an exact description of the error or a screenshot of what going on.
One thing to check is wherever NLogC.DLL or the C++ DLL you built have the correct calling convention defined. Basically you can't have the DLL function names mangled or use anything but the STDCALL calling convention. If the C++ DLL has not been created with those two things in mind then it will fail to work with VB6.
MSDN Article on Calling convention.
"Cannot load control xxx" errors can be caused by .oca files which were created from a different version of an .ocx than currently used. If that is the case, deleting the .oca files helps.

Resources