There are two models for handling components that are shared between applications.
The first is to isolate and deploy a copy of the componenents with each application. Other than using disk space, this is actually a really good model. Even unintentonal "bug fixes" can break an app unexpectedly. In this model, each app is well isolated from the others and you deploy updates to each app when they are tested. A change to the components doesn't accidentally break an existing, installed app. If you have "versioning" issues, you can still do this with a data-layer and a database value that specifies the minimum required version to access the database... that way, a required update can block apps that haven't been updated and you can co-ordinate releases.
The second is to use the Global Assembly Cache and install your components there. Thetrick here is that you will have to roll out "publisher policy" as well (which is really kind of an empty assembly) to force apps to use the updated components. If you do that, all apps will use the latest version of your assemblies (unless they have local app.config entries to opt out. Fun eh
??) If you use this model, then it's best to have a seperate MSI installer for your components. Then, you build a bootstrapper package to install that MSI installer, and include that bootstrapper package with your applications' Prerequisiste bootstrappers. That way, whenever you install an app, it will run the bootstrapper pacakge if it needs to, which will upgrade the components, and then install (or upgrade) your app.
I really encourage you to use Windows Installer for your apps. There are a few things to learn, but when you do there are a lot of good benefits of using Windows Installer.
Hope this helps.