Click here to Skip to main content
Rate this: bad
good
Please Sign up or sign in to vote.
See more: C++ DLL
Hi guys,
 
I came across an interesting problem at work where we're trying to merge 2 standalone .exes into one. The smaller one has already been enclosed in a DLL, however, back when it was implemented, it was written as one large DLL.
 
What we'd like to do at this point would be to separate it out into smaller pieces and merge it into the larger application piece-by-piece. Being that it's currently all in one DLL, we expect to run into some dependency problems in the process, and probably tons of Link errors. Any advices on strategies to approach this project?
 
Thanks in Advance!
Posted 20-Jan-11 5:20am
Comments
Nishant Sivakumar at 20-Jan-11 11:28am
   
Interesting question, voted 5.
Manfred R. Bihy at 20-Jan-11 12:51pm
   
Agreed, refactoring big monolithic DLLs can be a challenge! 5+
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 1

If you have enclosed the smaller one in a DLL, one quick and dirty way to merge it with the main executable is to convert the DLL project into a static lib project. Now your main exe can statically link to it, which means you will end up with just a single binary.
 
I reckon there will be some glitches, but I can't think of any major issues in doing it this way.
  Permalink  
v3
Comments
Rock Bottom at 20-Jan-11 11:35am
   
Thanks for the quick response that was one approach that I've considered earlier, but we ultimately decided if we were to do something of this scale, we might as well do it right. The idea is to completely merge it in wherever possible as the 2 applications do share similarities in many places. The separation of the classes weren't very clear back when the application was first written, and a lot of the logic is intertwined. This is not a problem when everything was together with everything else, but it's probably going to be a huge problem now when we try to part things out.
John Simmons / outlaw programmer at 20-Jan-11 11:37am
   
Sounds to me, then, like you should take this opportunity to refactor everything now that there is a grasp of the class interdependencies and program requirements. Merely stuffing everything into a single bucket is not going to be of any use to anyone a few months down the road.
John Simmons / outlaw programmer at 20-Jan-11 11:35am
   
Proposed as answer
SAKryukov at 20-Jan-11 12:05pm
   
Nishant, I really don't understand how LIB project could help. I doubt it can, but... could you elaborate?
Nishant Sivakumar at 20-Jan-11 12:08pm
   
They originally had 2 exes. They've converted one to a DLL which is now called from the other exe. So right now there's an exe and a dll. They want to get rid of the double binaries and have just a single binary. My suggestion was to change the dll to a static lib, and the main exe will use this static lib and result in a single binary. Obviously there's probably a fair bit of code in the dll that's also present in the exe, which is why I used the word "dirty" in my original response. But it's a quick way to get this working. But based on the OP"s reply, they don't want to do it that way, and he would rather design it in a clean fashion now that they have the opportunity. And I agree with that approach, and that would have been my first preference too had I been making this decision (provided time and other factors were in our favor).
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 2

Like Nish said, it should be a simple matter to move the code into static LIB files, and just link them in. If you're careful with your includes, you shouldn't even have too many issues.
 
Hopefully, you're starting with a fresh project and not modifying the one that already works. Smile | :)
  Permalink  
Comments
SAKryukov at 20-Jan-11 12:24pm
   
Important note of fresh project - my 5. Even if it is just in case.
 
John, I now I understand better why LIB project are better: they will tolerate unresolved references down the road, right? But when you move to decomposition into a set of DLLs, as requires, each DLL build will need all static references resolved. So how LIB form of the project help the transition? My idea was layering of everything from the very beginning.
John Simmons / outlaw programmer at 20-Jan-11 12:33pm
   
But he's refactoring an existing app. It would be nice to be able to start fresh, but I don't think he has that luxury.
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 3

The approach is to draw a layered diagram based on available dependencies -- a manual work, but it will direct you very well in structuring future development (for this project, but for new ones as well).
This served me well in many big projects.
 
With .NET I developed a simple utility: using Reflection to draw dependencies from executables is a snap. With C++ I saw some some restructuring utilities, but many years ago. Even manual work will help.
 
Would you look at my answer to similar question?
 
Here: Help on re-engineering a big project into DLL modules.[^].
 
Apparently, that my answer would hardly help OP because she or he was actually lost in linking technique (but the Question marked "solved"). Maybe you would be able use the idea and get job done?
  Permalink  
Comments
Espen Harlinn at 20-Jan-11 12:07pm
   
5+ Sounds like a good structured approach
SAKryukov at 20-Jan-11 12:17pm
   
Thank you very much. It really served me well - for a long time already.
I would say the credit should go to my original answer, referenced above :-D
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 5

This is kind of a refinement of SAKryukov’s answer, he’s, in my view, definitely heading in the right direction.
 
Depending on the size of the project - DoxyGen[^] together with Graphwiz[^] can help you get a detailed overview of the project with a graphical representation of the inheritance tree and other class interaction.
 
Doxygen can be set up to use Graphwiz to generate the various graphical representations based on the source code. DoxyGen can be set up to work with all of the code - even if it's a documentation tool, it can generate output for undocumented code, private variables, and so on.
 
This may help you decide how to organize the code into separate dll’s.

Depending on the size of the project, it’s also possible to use DoxyGen as a foundation for a tool that may partially automate the process – probably not a trivial task - it’s open source so you may modify it in any way you want.
 
Update for database layer
This is a great tool, easily modifiable to suit your needs, Database Helper v 2.0.0[^] - The tool also shows how to use SMO.
 
Regards
Espen Harlinn
  Permalink  
v2
Comments
SAKryukov at 20-Jan-11 12:20pm
   
Great, Espen - my 5.
This is what I meant to say about the tool. I don't do massive C++ development, and .NET is much easier for development of such meta-tools.
 
So, productive teem work again, eh?
--SA
Espen Harlinn at 20-Jan-11 13:29pm
   
Yes, and it's way more fun this way, SAKryukov!
Rock Bottom at 20-Jan-11 13:52pm
   
Doxygen is a great tool, thanks for the recommendation!
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 4

The first thing to do is make sure that you don't loose any of the dependency isolation you've got with the EXE + big DLL. What I mean by that is don't allow anything to leak across the boundary between the two as you do your integration. Using unit tests can be a good way to make sure you don't make things worse.
 
Once you've done that make sure all the class declaration and definitions are in their own files and that any of the source files can compile on it's own without any fancy compiler settings or fiddling. This is really important as it's hard to look for ways for breaking dependencies when source files can be compiled standalone. It's also harder to write unit tests for them as well.
 
The next thing to do is to look to see where you can split the DLL into smaller chunks. Look for things you can wall off behind interfaces. Instead of passing concrete classes around refactor the code so it's passing references to an interface class instead.
 
As a rough and ready example say you've got two bits of code. Chunk A creates an object of class cA and passes it to chunk B. B uses some subset of it's functionality. You can introduce a new interface class, iA that does the bits B wants of cA and derive cA from it. Then refactor B to only use iA. What've you done is remove any dependency on cA from B and left a smaller dependency on IA.
 
After this phase hopefully you'll have something like a bunch of small clusters of classes which only talk to each other through abstract, interface classes.
 
Next start to look for things that you can bundle up into new classes or interfaces. API calls all over the shop is a sign that the code can do with this sort of attention. Instead of directly using libraries and APIs wall them off behind another interface and you'll see even more places you can separate the code into more manageable chunks.
 
Then you've got all the balls ache of actually abstracting out the clusters into their own libraries and linking them with the main EXE. That shouldn't be too hard though if you've factored them into nice little bundles with minimal dependencies on the others.
 
Cheers,
 
Ash
  Permalink  
Comments
SAKryukov at 20-Jan-11 12:03pm
   
All useful - my 5.
--SA
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 6

Hey guys,
 
So I started getting my hands wet after looking and playing around with the code a bit. I'm currently extracting the database layer, which should sit above the base class but below the controls and UI layers.
 
A difficulty is that the separation between the GUI and the business logic is not very clear-cut and sometimes classes are bundled together in the same file just for convenience. To separate those out would be one of my first tasks.
 
Another difficulty is that a lot of the dependencies trace back into a full circle, with components both above and below my layer.
 
I plan to create a bare minimum base class and derive the rest above my layer. Any suggestions on general rules of thumb on what I should bring down and what I shouldn't (ie. should I bring down as much as I could? as little as I could?)
 
Also, after refactoring and restructuring the project, I'm getting blocks and blocks of linking errors (mainly LNK2001 on the statics), how would I resolve them?
 
I guess this is more of an update/followup question than an answer, but I just want to make sure it reaches everyone who has helped me thus far and has been following the question.
 
Thanks!
  Permalink  
Comments
Espen Harlinn at 25-Jan-11 15:30pm
   
See update answer :) May help to automate a bit of your work
Rock Bottom at 25-Jan-11 15:34pm
   
Hi Espen,
The tool seems like it might be a little new for our old application (Borland OWLNext old). Your help is still appreciated though.
Thanks!
Espen Harlinn at 25-Jan-11 16:06pm
   
I've played around with it before - getting it to spit out java code wasn't all that hard. It depends on the size of the project - if it's large, and you are going to make lot's of modifications along the way, then it's going to be well worth the effort.
Rock Bottom at 25-Jan-11 17:33pm
   
Any advices on the mounds of LNK2001s that I'm getting?
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 7

The Project has taken on an interesting turn, and is now creating some new problems. (Please see here.)
  Permalink  

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



Advertise | Privacy | Mobile
Web03 | 2.8.141015.1 | Last Updated 11 Feb 2011
Copyright © CodeProject, 1999-2014
All Rights Reserved. Terms of Service
Layout: fixed | fluid

CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100