Advertisement

Truly modular library

Started by March 17, 2000 07:31 AM
6 comments, last by null_pointer 24 years, 9 months ago
I'm rewriting my game development library, and I want to make both my library's DLL and any programs that use it truly modular. To do that, I'm using namespaces and declaring all my interfaces in the main DLL: namespace GDL { class Window { public: Create(Rectangle& rcDesiredClient) = 0; Destroy() = 0; }; }; That code is just for illustration, I just mean I'm declaring basically "codeless" classes in my DLL. All of the C++ library-based classes (like String, for example) that I create will have implementations in the main DLL. For the OS-/API-specific stuff, I'll have separate DLL's that I load at run-time (via LoadLibrary) that provide the implementations for my "codeless" classes. So, what I have is one main DLL that users statically link their programs to. That main DLL is their only #include or lib. The main DLL then links statically with the standard C Run-Time library, and it also links dynamically with the OS-specific DLLs, depending on the current operating system, or install options or something. The OS-specific DLLs all provide the same "codeless" interface, but they supply the code in their .cpp files. I've already eliminated windows.h from the main DLL, but I have a couple quick questions. 1) How do I eliminate the run-time library from being linked or #include-ed in the program that uses my library (I can create a generic starter project for the users of my library -- I just want to know how to do it). 2) I can probably override the Window::operator new functions for my class (and the operators of all other classes), then provide a custom "allocator" function in the DLLs to make the objects -- kind of like an object factory in COM. This is messy, but then only the library creator (me) has to work with it -- it'll be transparent to the user. My question, then, is how do I override the allocation of things on the stack? 3) How can users of my library create one .EXE file that will run under all major operating systems -- Windows, Mac, Linux, etc.? I can re-define the entry point, but will that simply enable it to run in different environments? The program's themselves will not link or even #include code from any specific OS or OS-specific API -- only mine. 4) This is beginning to sound like a C++-based virtual machine...anyway, does anyone know how I can override or handle the generic exceptions, like an access violation? If I can't allow users to create these objects on the stack, then I want to know how to make sure they know why they're getting access violations with temporary objects. 5) Cast operators (apparently) don't work with pointers to classes. When I do this: class String { public: operator const char*() { return m_pData; } }; pStringObject = new String("test"); const char* pMyString = (*pStringObject); Does that create a temporary object on the stack? 6) I just though of another one! Since the pure C++ classes (the ones that only use the run-time library) will be implemented in the main DLL, the OS-specific DLLs have to link to it statically. Does that prevent the main DLL from linking to the OS-specific DLLs dynamically? (and does it prevent them from unloading dynamically?) 7) I just realized - I'll have to create my own substitute for LoadLibrary/FreeLibrary (you can tell I learned C++ from Windows...). Wait...do they exist in the standard C Run-Time library? Or does someone have source code to create functions like those for C++? Anybody have links to a tutorial on something like that? 8) When I get this project off the ground, would this be a project people would be interest in joining? Or is it worthless to anyone but me? I'd be really grateful for any (polite) answer to these questions! (any COM techies, please respond!) Thanks! - null_pointer Edited by - null_pointer on 3/17/00 7:46:37 AM
Wow man, you are asking a lot here. But it shows you thought about this stuff which is very good!!

Anyway, I''ll see what I can answer (not much probably).

1) How do I eliminate the run-time library from being

Isn''t this a standard option in vc++?


2) I can probably override the Window::operator new functions for my class (and the operators of all other classes), then provide a custom "allocator" function in the DLLs to make the objects -- kind of like an object factory in COM. This is messy, but then only the library creator (me) has to work with it -- it''ll be transparent to the user. My question, then, is how do I override the allocation of things on the stack?

You don''t. Why not create a factory interface which let''s the user instantiate everything. THe implementation of that factory wil use new internally. That way the user will never new things. (which the use shouldn''t be doing anyway cause it''s interfaces we are talking about which aren''t really instantiatable). The you refcount these interfaces so they can destroy themselfs when needed. Standard COM stuff.


3) How can users of my library create one .EXE file that will run under all major operating systems -- Windows, Mac, Linux, etc.? I can re-define the entry point, but will that simply enable it to run in different environments? The program''s themselves will not link or even #include code from any specific OS or OS-specific API -- only mine.

You can''t. Running your application on different osses with the same binary is not possible (yet), unless you are using Java. Simply recompile. If you create everything structured this shouldn''t be a problem.

4) anyway, does anyone know how I can override or handle

Sorry can''t help you here.

5) Cast operators (apparently) don''t work with pointers to classes. When I do this:


class String
{
public:
operator const char*() { return m_pData; }
};

pStringObject = new String("test");
const char* pMyString = (*pStringObject);

What the h*ck are you trying to do here man? You are converting a class (which can contain everything) to a character array. This is scary man . You cannot know what is in the class. Why not let the class have a method:

char* GetCharPointer();

Or am I missing something?

6) I just though of another one! Since the pure C++ classes

Don''t quite understand you here.

7) I just realized - I''ll have to create my own substitute for LoadLibrary/FreeLibrary (you can tell I learned C++ from Windows...). Wait...do they exist in the standard C Run-Time library? Or does someone have source code to create functions like those for C++? Anybody have links to a tutorial on something like that?

Nope. But Loadlibrary is win32 only. Linux uses another system for dynamically linking that has something to do with .os files. I could look it up for you if you want to. My bet is that you need a different LoadLibrary for each O.S. And the runtime has no dynamic loading feature.

8) When I get this project off the ground, would this be a project people would be interest in joining? Or is it worthless to anyone but me?

THis is a great and ambitious project. I once started such a thing and had great plans about extensibility and platform independacy but then i got a new job that I''m working really hard on now. So I don''t have time for it anymore.

ANwyay, goodluck.

Jaap Suter


I''d be really grateful for any (polite) answer to these questions!

(any COM techies, please respond!)

____________________________
Mmmm, I''ll have to think of one.
____________________________Mmmm, I''ll have to think of one.
Advertisement
s9801758: Thanks! I guess it''s not very possible, but I heard about COM object binaries being able to run on different OSes without re-compiling...

I suppose I''ll have to make a slightly different version of the main DLL for every OS. The OS-specific DLLs will be segregated anyway, so that won''t be a problem. As for the programs, I''ll just have to stick as close as possible to ANSI C++ when I''m making the interfaces.

I feared I''d have to make a custom allocator for each class There should be a way to have language-level support for this -- just like you can re-define the global operator new. You should be able to re-do the stack as well, although that would probably be pretty difficult and require an OS that links DLL code almost directly with the program, giving them the same stack. *sigh* Using something like CoCreateInstance on each class isn''t what I need -- that''s overkill for a library. What that does is enable each class to be in its own DLL (or EXE or whatever) -- all I want to do is put together a collection of classes for a library.

However, what I could do is create a scripting language identical to C++, with my own memory managment -- make using the stack identical to using new and delete with a smart_pointer. If I''m going that far, it''d be better to simply make my own compiler...well, that''s enough in that direction

HINT: Someone needs to create an OS where the stacks of the program and DLL are the same! haha ok maybe that''s a stupid request

Do you have any experiences on things you could do as work-arounds, besides COM? From what I''ve seen, I don''t like COM -- I think natively in C++ now... Would it be possible to do something in asm?

Thanks!


- null_pointer

You certainly are going to have your hands full!

Whether or not the project gets off the ground I am betting you learn lots along the way!

I know that you mentioned that you didn''t like COM, but its not all that bad of a way to go. Maybe its just because I have been forced to work with it and don''t know any better, but I think it would solve just about everything your looking to do, except for the platform independence.

While you may not gain platform independence by using COM, you can pretty much gain client independence...meaning that your objects can be used from C, C++, VB, Delphi (?) and any other language that can take advantage of early binding.

If you make a little exta effort and provide IDispatch support for your objects, you gain the audience of any automation compatible client: C/C++, VBScript, Java Script, PowerBuilder, ad nausem... Even possibly use on another platform via Java.

If you keep your supporting code contained enough to begin with, it should be a simple process of changing the interface (interface being how the client is going to use your libary: COM, Mac C++, Linux C++).

For example, I have a class that uses STL and straight C++ to decode delimited files.... this class is csv_driver. It has all the methods necessary to decode a csv file, and return csv_row (vector) objects that is essentially a collection of csv_field (string).

Now, this is fine, I have used this class for a long time..but then someone came to me and asked if they could get the functionality in VB.

No problemo...I created an object (CSVDriver) that contains the ICSVConnection and ICSVRow interfaces.

ICSVConnection is essentially a passthrough, or wrapper for csv_driver. ICSVRow is a wrapper for csv_row.

The .cpp file that implements CSVDriver is all of 150 lines of code...the majority just handing off to the internal csv_driver class or providing conversion between BSTR -> NULL terminated string.

...and now the object is used from VB, VBScript and Java Script in addition to C++.

The concern about using CoCreateInstance(..) being overkill may not really be true. I haven''t seen a real speed issue with it, but I am only talking about using it with a couple hundred to a few thousand objects at best. That is, as long as the COM libraries have already been loaded. Thats just my personal experience.

Anyways...thought I would drop a line or three ...good luck!

-mordell
__________________________________________

Yeah, sure... we are laughing WITH you ...
mordell: I didn''t mean overkill as far as performance is concerned. I mean that this code in C++:


void Window::DisplayTrackingRectangle(int nMouseID)
{
// fictious function -- here to display stack-based objects

Point pt1;
Point pt2;

const Mouse& GetMouse(nMouseID);

pt1 = Mouse.GetLastLeftClickPoint();
pt2 = Mouse.GetLastLeftClickUpPoint();

Rect rcDrag(pt1, pt2);

// and on, and on, and on...
}


That would be a little harder to do with COM (well, maybe not harder, but a lot more complex). Imagine all the calls to CoCreateInstance and Release, then try to add exception processing into the mix...no thanks! I don''t wanna bash COM or anything, but C++ "native" code seems MUCH simpler there...I meant it wouldn''t work well in that circumstance... I just wanted to do something similar with native C++ code, using C++ as a language that''s independent of any OS. People talk so much about portable code these days, I just wanted to see how far I could take the concept.

Thanks!


- null_pointer



Yes, I could see where that would be overkill!

But, consider this. Say you have a CWindow class (for lack of a better name), that implements your IWinodw COM interface. This CWindow class encapsulates your Window class.

Now, this CWindow has a method called DisplayTrackingRectangle( short nMouseID );

So, your implementation would look something like this:

//: your passthrough
//:
HRESULT CWindow::DisplayTrackingRectangle( short nMouseID ) {

//: m_pWindow is a pointer to your Window class
//:
m_pWindow->DisplayTrackingRectangle( nMouseID );

return S_OK;

}

The user just has to instantiate a IWindow interface pointer in order to call DisplayTrackingRectangle.

Your internal classes Point and Rect would not really be needed to be implemented as interfaces, however you would probably want to export them in the midl file so that people would know how they were laid out in memory...especially if you have methods that may be returning Point''s or Rect''s.

HTH,

-mordell


__________________________________________

Yeah, sure... we are laughing WITH you ...
Advertisement
Yes, I think I know how to make the library now! Thanks, everyone!

I''ll put all the classes that just use the C++ library functions or standard types into the main DLL. That way, they can be used or called by the interfaces for the OS-specific DLLs.

Then, I can put the OS-specific stuff into different libraries. When the user decides to move between platforms, he simply creates a new project type in his compiler, and includes the main lib, which is different for each OS. However, the library interface will remain the same. That way, all the user has to do is recompile.

Finally, putting the regular classes into the main DLL will solve the problem of inheritance/polymorphism. I was going to let the user override or derive from some classes. There will also be template classes, etc.

Perhaps it would be a good idea to put the OS-specific stuff into COM interfaces, that way the main DLL could theoretically be used by any language. Unfortunately, I couldn''t allow the user to do much derivation, as that would defeat some of the purpose of hiding the code with COM.

Ideas...Ideas...Ideas...... (If you haven''t noticed by now, the above was just a pulling-together of everyone''s input )

Now, if I could just find a good book on COM -- really technical stuff for OOP-geeks like me (maybe 1000+ pages)

Thanks!


- null_pointer


Two excellent sources for information on COM are:

"Inisde COM", Dale Rogerson

www.amazon.com/exec/obidos/ASIN/1572313498/qid=953647024/sr=1-1/103-6138682-2397460

"Essential COM", Don Box

www.amazon.com/exec/obidos/ASIN/0201634465/ref=sim_books/103-6138682-2397460

Good luck!

-mordell

Edited by - mordell on 3/21/00 7:58:37 AM
__________________________________________

Yeah, sure... we are laughing WITH you ...

This topic is closed to new replies.

Advertisement