I'm very new to OwlNext 6.30 having used BC5.02 / Owl 5 for many years (30+ :-) so its marvellous to see OwlNext's development. I recently ran into an issue with DEP settings in Windows and have read here that OwlNext provides better compatibility and supports DEP.
I now need to convert all my old code from 5 to 6.30 initially as per the documents provided. I have managed to convert my main EXE to run under 6.30 relatively easily however I now need to do the same with a number of DLL's.
I have a clean compiled code for the one of the DLL under 6.30 but the module crashes. I have also tried creating a simple MDIClient window (Using MDIFile example provided by Boland BC5.02) by passing the MDIClient parameter from the main EXE. This also crashes from the DLL but works fine if called from the EXE directly.
My question is therefore can I still pass a MDIClient pointer from the MAIN EXE to a DLL for that DLL to create its own windows control and behaviour etc. This is a critical part of my code as there are many DLL's to recompile.
My main application is a CAD window with Terrain modelling information and the DLL's are various design modules for sewer, road, stormwater and water design etc which interact with the CAD and Terrain data.
Please can someone assist? Thanks in advance.
Last edit: Keith Simon 2023-11-17
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I'm very new to OwlNext 6.30 having used BC5.02 / Owl 5 for many years (30+ :-) so its marvellous to see OwlNext's development.
Wow, what took you so long? Did you ever have a look at OWLNext before now? If so, why did you decide to stick with OWL and outdated development tools?
It would be interesting to know what the friction points are, so that we can make porting easier and more inviting.
I have a clean compiled code for the one of the DLL under 6.30 but the module crashes. I have also tried creating a simple MDIClient window (Using MDIFile example provided by Boland BC5.02) by passing the MDIClient parameter from the main EXE. This also crashes from the DLL but works fine if called from the EXE directly.
Regarding DLL issues, I think the most prominent stumbling blocks are (1) resources, (2) module confusion and (3) low-level incompatibilities (ABI, RTL, compilation settings).
Regarding (1) and (2), make sure that you initialise your DLLs correctly. For example, see this discussion:
"Are you calling OWLInitUserDLL() in your DllEntryPoint()? It is needed to correctly initialize the global gModule variable." [discussion:46f29a4e]
Regarding (2), make sure that you are clear about which module you intend your code to refer to (e.g. see "module" parameter in constructors). See FAQ for this and other issues.
If this does not help, please share your MDIFile test case. To make sure that you are not running into any bugs particular to 6.30, and to give yourself better debugging tools, I recommend you set up your test case with latest OWLNext 7 and Visual Studio 2022. When you get it working, you can backport to 6.30 and Borland C++.
By the way, do you really need DLL modularisation? You may simplify development and deployment by converting your application to static linking instead.
PS. What is your planned porting destination? OWLNext 6.30 on Borland C++? I hope not! I recommend you take the opportunity to upgrade to modern development tools and the latest version of OWLNext 7.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
Anonymous
-
2023-11-18
Hi Vidar
Thanks for the quick response. Responding to your items in order.
Yes - I have been aware of OWLNext for quite a number of years - always browsed but never tried to change my code until the DEP problems arose on Windows. I'm truly grateful for the work you guys have done supporting OWL. My software runs just fine on almost all Windows versions it's just lately a number (3 or 4) simply won't run because of DEP.
I have a few million lines of code in BC5.02 / OWL and also other DLL modules written in C++ Builder 2010, 10.4 as well but to change from BC5.02 / OWL will take me years - I'm 60 and near retirement ..... if ever I get there. Bear in mind I'm a Civil Engineer with a passion for IT and not a programmer per se - though I have been improving my code base since 1990 onwards with a number of very happy users of my engineering design software suite. As a practicing engineer I keep expanding on the tools as well.
My son is a BSc Computer Science graduate - maybe he can take the baton further....
I could ask him to assist the OWLNext group with regards documentation / support in the future if he can master the tools available. Currently he's working for me as a young developer - 2 years experience only though he needs experience in OWL first!
Regarding the problems:
I have passed the MDIClient client variable back to the EXE and initiated the function call there from the DLL - and it worked so the MDIClient is being passed correctly back and forth.
I do suspect its related to the gmodule / module variable - though I have no idea where or how to use it. Can you provide an example perhaps? I have also tried calling a simple DIALOG box creation in the DLL from the EXE but it also fails. (A simple AboutDialog with no real function). I can't find many examples on OWLNext as opposed to the original BC examples so I'm a little lost.
I would prefer to keep the DLLs - to keep sane managing this development project. Maybe in the future I can combine them though I will need to redesign the entire MDI interface at which point I could use C++ Builder 10 and above.
I would ideally like to move to the latest OWLNext as per your upgrade FAQ. Though I'm still at Step 1 - porting all my code to OWLNext 6.30 first using BC5.02. Can OWLNext be used with Builder 2010, Builder 10.4 etc? Please advise. I'm not much of a fan of MS compilers and Borland has thus far been an excellent tool for me personally.
Thanks for the help thus far. I'm pretty sure its Module related but unable to fix myself. Yes - I have found that same post regarding the call to OWLInitUserDLL on the discussion forums though I have no idea what parameters are needed so I just used the call as follows:
OWLInitUserDLL(hinst, _T("");
If this does set the MODULE variable - where do I use it? Lots of the module related calls simply have TModule *module = 0;
I have also checked and this code (OWLInitUserDLL) is being called when the DLL loads.
Thanks.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
Anonymous
-
2023-11-18
Hi Vidar
I clicked on REPLY and sent a long post - I'm not sure if you received it as is does not appear here?
Regards
Keith
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I clicked on REPLY and sent a long post - I'm not sure if you received it as is does not appear here?
Remember to log in. Anonymous messages go into a moderation queue and need approval by administrators before they are seen. In this case, your message was for some reason also caught by the spam filter, where messages may easily get lost.
I will reply to your message in full later.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I have a few million lines of code in BC5.02 / OWL
Wow. I don't envy you the task of maintaining such a sizable code base with tools from the 1990s. I spent some hours today with the Borland C++ IDE, looking at creating a step-by-step porting guide based on the example you presented. Tonight, I am close to losing the will to live. :-)
I'm a Civil Engineer with a passion for IT
Cool! I'm a lone programmer, who ended up devoting his career to a civil engineering application (Lima VVA) and the framework on which it depends (OWLNext).
I could ask [my son] to assist the OWLNext group
You are both very much welcome!
Regarding the problems [...] I do suspect its related to the gmodule/module variable — though I have no idea where or how to use it. Can you provide an example perhaps?
I suspect it is related to resources. With multiple modules, you have to be careful about where the resources reside and how they are located. I was able to make your example work, with a few changes:
// In "mdifile.cpp":void__importCmFileNew(TMDIClient&client);voidTMDIFileApp::CmFileNew(){::CmFileNew(*Client);}// In DLL, "module.cpp":void__exportCmFileNew(TMDIClient&client){TMDIChild*child=newTMDIChild(client,"",newTEditFile(0,0,0));TModule*module=child->GetModule();TMenuDescrmenu(IDM_EDITFILE_CHILD,0,2,0,0,0,0,module);child->SetMenuDescr(menu);child->SetIcon(module,IDI_DOC);//...child->Create();}
Note that I pass the child's module pointer to the TMenuDescr constructor. Since it is not specified in the TMDIChild constructor, the child inherits the module pointer from its parent (the TMDIClient). This means TMenuDescr will look for the menu resource in the application module, since this is where the TMDIClient was created, and where the resource happens to be located. Likewise, I pass the child's module pointer to SetIcon, so that it looks for the icon resource in the same module.
This compiles and runs fine with OWL 5 and OWLNext 6.30 on Borland C++ 5.02.
I then started work on porting this to Borland C++ 5.5 and ran into problems. I suspect it has much to do with bugs in the Tools55 add-on for the IDE. So, at this point in the porting process, I recommend transitioning to a makefile-based build setup, making sure that compiler and linker settings match those expected by OWLNext (see its makefile).
That said, still in the IDE, I did get the example to run with OWLNext 6.30 on Borland C++ 5.5, albeit with a mysterious crash at shutdown. Trying to port further to OWLNext 6.36 hit a wall, though. I just got a blank window. Which is curious, since the AClock example in 6.36 works fine with Borland C++ 5.5.
I have attached my example below with the working configurations for OWL 5 and OWLNext 6.30 on Borland C++ 5.02. Let me know if you have more luck than me with porting this to 6.36 on Borland C++ 5.5.
I would prefer to keep the DLLs - to keep sane managing this development project.
You can keep the modularity without creating DLLs. You can simply switch to static libraries. And, of course, you can modularise your code using folders, classes, namespaces, and other organisational methods and C++ language features (such as latest C++20 modules).
I would ideally like to move to the latest OWLNext as per your upgrade FAQ. [...] Can OWLNext be used with Builder 2010, Builder 10.4 etc? Please advise.
I'm pretty sure [the crash is] Module related but unable to fix myself.
I suspect it rather has to do with not finding the resources. Note that my test code doesn't even define an entry-point for the DLL, and it still works fine. However, the entry point and proper initialisation of the global module pointer may be crucial for more complex code. Note that OWLNext 6.32 and later versions encapsulate the global pointer with an initialising accessor function owl::GetGlobalModule [feature-requests:#18].
See the DLL Module example for another example of module resource handling, as well as DLL API design.
Thanks for the assistance. I really appreciate your efforts - please don't do any harm to yourself because of my query.... ;-)
Yes - this is the solution I suspect - I have briefly progressed further and my code is at least creating the window correctly from the DLL though it now hangs when I try to interact with it - I will investigate further.
That definitely helps the system to find the correct resources in the DLL itself.
Once I get the code working correctly under 6.30 I will then progress and advise what happens under BC5.5
Regarding your design software - is it freeware? it certainly looks impressive. It's very similar to what I have done with my Civil Suite Engineering Design suite - www.civilsuite.com
Thanks.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
please don't do any harm to yourself because of my query.... ;-)
I got really frustrated with the IDE, but to be fair to good old Borland C++, the frustration was exacerbated by bugs and instability with the Tools55 add-on for BCC 5.5. I have now removed any recommendation of this add-on in our documentation. Instead, I recommend moving to a makefile-based build solution at this point in the porting process. Makefiles make it much easier to control and compare compiler and linker settings.
Although some (like me) might find creating makefiles daunting, luckily there is a command to generate makefiles in the IDE (Project | Generate makefile). And AI assistants, such as Bing Chat, can be helpful with such tasks as well.
I have briefly progressed further and my code is at least creating the window correctly from the DLL [...] Once I get the code working correctly under 6.30 I will then progress and advise what happens under BC5.5
Good to hear. I hope the porting process progresses smoothly from here. Keep us updated.
Regarding your [Lima VVA road design software] - is it freeware?
Lima VVA is now (since 2017) open-source software freely available with a GPLv3 licence. So you can download and use the application free of charge. But usage has some restrictions and requirements, especially regarding the use and modification of the source code. See the licence for details.
I recently (last June) completed the English translation of the software, so I would very much appreciate feedback from a real civil engineer on any mistranslation of terms, etc. So let me know if you take a closer look.
Indeed! In the "Lima VVA" name, the "VVA" part stands for "veg, vann og avløp" in Norwegian, which translates to "road, water and drainage/sewerage" in English. "Lima" is inherited from the predecessor software "LIMA", which stood for "linjepålegg and masseberegning" in Norwegian, which translates to "vertical alignment and earthworks" in English.
While the main function of Lima VVA is the design and earthwork calculation for simple roads, version 4 also draws longitudinal section and horizontal plan for water and drainage networks associated with the road. However, version 5 (in development) drops the latter functionality and focuses on road design and earthworks.
It seems that the response table from the main EXE is being used and not the respnse table in the DLL. This only applies to the menus. The normal buttongadgets are responding / activating correctly. Only the Menu response are not activating.
The MDI application swops correctly between the EXE and DLL windows and sets the menu correctly for the appropriate window. Its just that the responses are still coming from the EXE response table. Any ideas what could be wrong?
I read through a number of articles and discussions here about response tables and know there were some changes implemented but only after 6.4 i think. Thanks.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I've hit the wall a bit with my MENU in the DLL [due to issues with the event handling].
Strange. The best advice I can come up with is to recreate the issue in a minimal test case. If you still cannot identify the cause and resolve it, then share the test case.
I read through a number of articles and discussions here about response tables and know there were some changes implemented [in 6.40].
That's correct. From the top of my head, I cannot recall any relevant changes in 6.30. You might have run into a corner-case.
PS. Make sure your menu command IDs are unique across the application.
Last edit: Vidar Hasfjord 2023-11-23
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I have adapted the MDI File example from the Borland C++ 5.02 OWL folder as follows:
I have two MDI children (SEWER AND ROAD) which are created successfully as child windows in the EXE and which adapt the menus according to each child window accordingly. (See the creation of New Sewer MDI Child and New Road MDI Child (EXE) in the menus when first loaded.)
I then created the ROAD MDI Child window in the DLL as per the attached code. This fails to create the window successfully (using Dynamic Linking) or if it creates the window it simply crashes the moment I click onto this child window (using Static linking).
I have included the IDE Project files for the MDIFile and RoadDLL. I have not included any OWLNEXT libraries - I'm currently using OWLNext 6.30.
Please could you review and possibly advise why the MDI Child created in the DLL fails? If you do get this working please check if the Child DLL responds to the menu items for the road menu?
I have spent a long time this week checking my original code in my main application and it fails similarly and doesn't respond to the menus. I therefore created this simple EXE and DLL in asking for your assistance.
Thanks once again for assisting.
👍
1
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Please ignore the message above - I had a bug in the line below..
// mainFrame->AssignMenu(104);
mainFrame - a global variable was not defined.
I can confirm both BC5.02 + OWL and BC5.02 and OWLNext both now work with the MDI Child in either the DLL or the EXE and both child windows respond to their menu items.
Thanks - some progress at least.... :-)
I will test as a static build next and report any funny results.
👍
1
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
This fails to create the window successfully (using Dynamic Linking) or if it creates the window it simply crashes the moment I click onto this child window (using Static linking).
You have an uninitialised global variable mainFrame in your DLL, which you dereference in TRoadMDIChild::EvMDIActivate, hence causing undefined behaviour (e.g. crash).
You can eliminate the global variable by calling TApplication::GetMainWindow instead, after which the code seems to work in my tests, including menu item handlers in the DLL (TRoadMDIChild::RoadTest1 etc.).
voidTRoadMDIChild::EvMDIActivate(THandlehActivated,THandlehDeactivated){DefaultProcessing();if(Handle==hActivated){//mainFrame->AssignMenu(104); //*** VH: Use of uninitialised global variable.GetApplication()->GetMainWindow()->AssignMenu(104);//*** VH: Fix::MessageBox(this->Handle,"Checks Road","TEST",MB_OK);}}
Some tips:
Simplify your shared test cases to the bare minimum. Don't include unnecessary cruft.
Don't include binaries/executables in shared zip files (virus risk).
Add the DLL module in the main project file of your test case to simplify (e.g. allowing stylesheets to make it easier to inspect and modify settings).
The MDI implementation in OWL has automatic menu merging, so I don't quite get why you need to override EvMDIActivate and assign the main menu explicitly.
There's a bug in PreProcessMsg overloads; you use operator "|" rather than "||" for boolean operations. If it is intentional, as to always call both base functions (and not get the short-circuiting behaviour of "||"), then instead separate the calls into two statements.
Consider creating a common base class for your MDI children, rather than repeatedly using multiple inheritance and duplicated code.
Immediately start using a version control system, if you're not already doing so. This keeps you sane, as it allows simple inspection of changes between versions of code.
Last edit: Vidar Hasfjord 2023-11-27
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
By the way, Bing Chat was able to spot this issue. See below.
(We're living in quite remarkable times as humanity creates intelligent agents.)
Me: Hi! I'm having problems with the following code. It either crashes or doesn't work as intended. Can you spot the issue? [test case]
Bing: The problem seems to be that you’re inheriting from both TMDIChild and TDecoratedFrame. This is causing ambiguity in your code because both classes have similar methods and the compiler doesn’t know which one to use. [...] I hope this helps! Let me know if you have any other questions.
Me: Thanks, that a good thing to look for, but that's not it. I've tested that part and the multiple inheritance works fine in other code (my EXE module). Any other ideas?
Bing: I see. If the multiple inheritance isn’t the issue, then let’s look at other possibilities.
One thing that stands out is the DLL_CmNewRoadWindow function. This function is marked with _export, which suggests that it’s intended to be used as a DLL export. However, it seems to be defined in the same file as the rest of your code. If this code is meant to be compiled into a DLL, then it should be fine, but if it’s being compiled into an EXE, this could potentially cause problems.
Also, in the DLL_CmNewRoadWindow function, you’re creating a new TRoadMDIChild object with new, but it doesn’t seem like this object is ever deleted. This could potentially lead to a memory leak.
Another potential issue is the use of the mainFrame global variable. This variable is used in the EvMDIActivate method, but it’s not clear where it’s being set. If it’s not being properly initialized before EvMDIActivate is called, this could potentially lead to a crash.
Lastly, the EvLButtonDown, EvRButtonDown, and EvMouseMove methods are empty. If these are being called in response to mouse events, and the intention is to do nothing, then it should be fine. However, if there’s supposed to be code in these methods, then this could be why the program isn’t behaving as expected.
I hope this gives you some ideas on what to look for. Debugging can be a complex process, and it often involves a lot of trial and error. Good luck!
Me: Super! The uninitialised global variable was the issue. Thanks!
Bing: I'm glad to hear that you found the issue! Remember, global variables can be tricky to manage due to their scope. It's generally a good practice to avoid them when possible, or ensure they are properly initialized before use. If you have any more questions or need further help, feel free to ask. Happy coding!
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
Anonymous
-
2023-11-28
Just some feedback - I see that OWL5_COMPAT must be defined else the child windows won't respond the menu messages.
I have thus far managed to compile and link one of my design DLL modules into the EXE and all seems to work just fine. I can now finalise that module before attempting the other modules. Without OWL5_COMPAT I note even the MDI window was not being created correctly (i.e. not maximized, icons missing, window would hang / crash if moved etc).
At what stage should I be removing OWL5_COMPAT - when i switch to a higher compiler and OWLNext version above 6.30?
Thanks again for the assistance and hints as listed - they proved very useful. I'm progressing to OWLNext 7 albeit at a crawl. :-)
👍
1
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I have thus far managed to compile and link one of my design DLL modules into the EXE and all seems to work just fine. I can now finalise that module before attempting the other modules.
That's excellent news! And it is particularly noteworthy that the modularity of your application design is now paying back. Modularity is a key concept to manage complexity efficiently.
I see that OWL5_COMPAT must be defined else the child windows won't respond the menu messages. [...] Without OWL5_COMPAT I note even the MDI window was not being created correctly
This is curious. Thanks for the feedback.
It would be good to understand why this is. I know there is a change in 6.32 that affects the window setup sequence [bugs:#102] and is disabled by OWL5_COMPAT, and there are major changes to Windows message dispatch in 6.44, some of which may be disabled by OWL5_COMPAT. However, I cannot recall any relevant documented changes in 6.30. So any clarification on this would be welcome.
That said, I guess this issue shows an unfortunate dependency on OWL implementation details in your application. Consider eliminating such dependencies. Even if that means you have to give up some neat custom behaviour in you application, it may be worth removing such customisations during the porting process. Then, when you arrive at OWLNext 7, you can consider reintroducing customisations where it makes sense.
For example, in your test case, the explicit custom implementation of menu merging (EvMDIActivate) and the overriding of message processing (PreProcessMsg) are alarming. If you can eliminate such complexity (at least temporarily during the porting), your application code should become less brittle.
On the other hand, you may have run into a bug in OWLNext. To eliminate this possibility, please try to recreate the issue in a very simple test case (e.g. based on the MDIFile example), and if you can, report the issue as a bug.
There is also the possibility that your application code has a transient bug which is otherwise unrelated to OWL5_COMPAT, but just so happens to reveal itself in this build mode. For example, this could be an uninitialised variable, just as in the test case you shared. And, of course, it is even possible that OWLNext 6.30 has transient bugs. A minimal test case will help investigate the true cause.
At what stage should I be removing OWL5_COMPAT?
According to our recommended step-by-step approach, you should ideally stop depending on the OWL5_COMPAT mode after having ported to OWLNext 6.36 and modern tools.
I'm progressing to OWLNext 7 albeit at a crawl. :-)
Good — and don't despair about the slow progress. You are learning valuable lessons about porting, about the strength and weaknesses of your application code, and about OWL and OWLNext design, implementation and stumbling blocks.
To be honest I've made no progress since December. We've had holidays for the Construction Industry for a month here in South Africa. Getting back to work mid January brought along other challenges in the office and I have simply had no time to restart my development work. I also haven't installed your Lima VVA as yet either. Hopefully from next month onwards things will get back to normal . we're tendering for Civil Engineering work and implementing projects which need my immediate attention first. Some engineering clients are also not assisting which is the really frustrating part.
I managed to get my application converted to OwlNext but have not moved further. I've also been fixing the old code base and adding some new features which were missing - then I need to take that code into OwlNext again. effectively managing two code bases which isn't ideal. (Production application in legacy BC5.02 / OWL and then Development in both Legacy / OWL and OwlNext).
How are you doing? Still enjoying semi-retirement or having other software development plans?
Moderator: Removed superfluous email headers and quoted contents.
Last edit: Vidar Hasfjord 2024-02-08
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I managed to get my application converted to OwlNext
That's great! Please continue to update us on your progress with the OWLNext porting.
Still enjoying semi-retirement or having other software development plans?
Indeed, I am enjoying my semi-retirement. There's still a lot of work to be done on Lima VVA and OWLNext/Owlet, which keeps me occupied whenever I feel like diving back into software development.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi
I'm very new to OwlNext 6.30 having used BC5.02 / Owl 5 for many years (30+ :-) so its marvellous to see OwlNext's development. I recently ran into an issue with DEP settings in Windows and have read here that OwlNext provides better compatibility and supports DEP.
I now need to convert all my old code from 5 to 6.30 initially as per the documents provided. I have managed to convert my main EXE to run under 6.30 relatively easily however I now need to do the same with a number of DLL's.
I have a clean compiled code for the one of the DLL under 6.30 but the module crashes. I have also tried creating a simple MDIClient window (Using MDIFile example provided by Boland BC5.02) by passing the MDIClient parameter from the main EXE. This also crashes from the DLL but works fine if called from the EXE directly.
Here are the code segements below:
Crash occurs on the CREATE call.
My question is therefore can I still pass a MDIClient pointer from the MAIN EXE to a DLL for that DLL to create its own windows control and behaviour etc. This is a critical part of my code as there are many DLL's to recompile.
My main application is a CAD window with Terrain modelling information and the DLL's are various design modules for sewer, road, stormwater and water design etc which interact with the CAD and Terrain data.
Please can someone assist? Thanks in advance.
Last edit: Keith Simon 2023-11-17
Hi Keith, welcome to the forum!
Wow, what took you so long? Did you ever have a look at OWLNext before now? If so, why did you decide to stick with OWL and outdated development tools?
It would be interesting to know what the friction points are, so that we can make porting easier and more inviting.
Regarding DLL issues, I think the most prominent stumbling blocks are (1) resources, (2) module confusion and (3) low-level incompatibilities (ABI, RTL, compilation settings).
Regarding (1) and (2), make sure that you initialise your DLLs correctly. For example, see this discussion:
"Are you calling OWLInitUserDLL() in your DllEntryPoint()? It is needed to correctly initialize the global gModule variable." [discussion:46f29a4e]
Regarding (2), make sure that you are clear about which module you intend your code to refer to (e.g. see "module" parameter in constructors). See FAQ for this and other issues.
If this does not help, please share your MDIFile test case. To make sure that you are not running into any bugs particular to 6.30, and to give yourself better debugging tools, I recommend you set up your test case with latest OWLNext 7 and Visual Studio 2022. When you get it working, you can backport to 6.30 and Borland C++.
By the way, do you really need DLL modularisation? You may simplify development and deployment by converting your application to static linking instead.
See FAQ | Should I use static or dynamic linking?
PS. What is your planned porting destination? OWLNext 6.30 on Borland C++? I hope not! I recommend you take the opportunity to upgrade to modern development tools and the latest version of OWLNext 7.
Related
Discussion: 46f29a4e
Hi Vidar
Thanks for the quick response. Responding to your items in order.
Yes - I have been aware of OWLNext for quite a number of years - always browsed but never tried to change my code until the DEP problems arose on Windows. I'm truly grateful for the work you guys have done supporting OWL. My software runs just fine on almost all Windows versions it's just lately a number (3 or 4) simply won't run because of DEP.
I have a few million lines of code in BC5.02 / OWL and also other DLL modules written in C++ Builder 2010, 10.4 as well but to change from BC5.02 / OWL will take me years - I'm 60 and near retirement ..... if ever I get there. Bear in mind I'm a Civil Engineer with a passion for IT and not a programmer per se - though I have been improving my code base since 1990 onwards with a number of very happy users of my engineering design software suite. As a practicing engineer I keep expanding on the tools as well.
My son is a BSc Computer Science graduate - maybe he can take the baton further....
I could ask him to assist the OWLNext group with regards documentation / support in the future if he can master the tools available. Currently he's working for me as a young developer - 2 years experience only though he needs experience in OWL first!
Regarding the problems:
I have passed the MDIClient client variable back to the EXE and initiated the function call there from the DLL - and it worked so the MDIClient is being passed correctly back and forth.
I do suspect its related to the gmodule / module variable - though I have no idea where or how to use it. Can you provide an example perhaps? I have also tried calling a simple DIALOG box creation in the DLL from the EXE but it also fails. (A simple AboutDialog with no real function). I can't find many examples on OWLNext as opposed to the original BC examples so I'm a little lost.
I would prefer to keep the DLLs - to keep sane managing this development project. Maybe in the future I can combine them though I will need to redesign the entire MDI interface at which point I could use C++ Builder 10 and above.
I would ideally like to move to the latest OWLNext as per your upgrade FAQ. Though I'm still at Step 1 - porting all my code to OWLNext 6.30 first using BC5.02. Can OWLNext be used with Builder 2010, Builder 10.4 etc? Please advise. I'm not much of a fan of MS compilers and Borland has thus far been an excellent tool for me personally.
Thanks for the help thus far. I'm pretty sure its Module related but unable to fix myself. Yes - I have found that same post regarding the call to OWLInitUserDLL on the discussion forums though I have no idea what parameters are needed so I just used the call as follows:
OWLInitUserDLL(hinst, _T("");
If this does set the MODULE variable - where do I use it? Lots of the module related calls simply have TModule *module = 0;
I have also checked and this code (OWLInitUserDLL) is being called when the DLL loads.
Thanks.
Hi Vidar
I clicked on REPLY and sent a long post - I'm not sure if you received it as is does not appear here?
Regards
Keith
Remember to log in. Anonymous messages go into a moderation queue and need approval by administrators before they are seen. In this case, your message was for some reason also caught by the spam filter, where messages may easily get lost.
I will reply to your message in full later.
@keithcsimon wrote:
Wow. I don't envy you the task of maintaining such a sizable code base with tools from the 1990s. I spent some hours today with the Borland C++ IDE, looking at creating a step-by-step porting guide based on the example you presented. Tonight, I am close to losing the will to live. :-)
Cool! I'm a lone programmer, who ended up devoting his career to a civil engineering application (Lima VVA) and the framework on which it depends (OWLNext).
You are both very much welcome!
I suspect it is related to resources. With multiple modules, you have to be careful about where the resources reside and how they are located. I was able to make your example work, with a few changes:
Note that I pass the child's module pointer to the TMenuDescr constructor. Since it is not specified in the TMDIChild constructor, the child inherits the module pointer from its parent (the TMDIClient). This means TMenuDescr will look for the menu resource in the application module, since this is where the TMDIClient was created, and where the resource happens to be located. Likewise, I pass the child's module pointer to SetIcon, so that it looks for the icon resource in the same module.
This compiles and runs fine with OWL 5 and OWLNext 6.30 on Borland C++ 5.02.
I then started work on porting this to Borland C++ 5.5 and ran into problems. I suspect it has much to do with bugs in the Tools55 add-on for the IDE. So, at this point in the porting process, I recommend transitioning to a makefile-based build setup, making sure that compiler and linker settings match those expected by OWLNext (see its makefile).
That said, still in the IDE, I did get the example to run with OWLNext 6.30 on Borland C++ 5.5, albeit with a mysterious crash at shutdown. Trying to port further to OWLNext 6.36 hit a wall, though. I just got a blank window. Which is curious, since the AClock example in 6.36 works fine with Borland C++ 5.5.
I have attached my example below with the working configurations for OWL 5 and OWLNext 6.30 on Borland C++ 5.02. Let me know if you have more luck than me with porting this to 6.36 on Borland C++ 5.5.
You can keep the modularity without creating DLLs. You can simply switch to static libraries. And, of course, you can modularise your code using folders, classes, namespaces, and other organisational methods and C++ language features (such as latest C++20 modules).
See Supported Compilers.
I suspect it rather has to do with not finding the resources. Note that my test code doesn't even define an entry-point for the DLL, and it still works fine. However, the entry point and proper initialisation of the global module pointer may be crucial for more complex code. Note that OWLNext 6.32 and later versions encapsulate the global pointer with an initialising accessor function owl::GetGlobalModule [feature-requests:#18].
See the DLL Module example for another example of module resource handling, as well as DLL API design.
Related
Feature Requests:
#18Wiki: Supported_Compilers
Last edit: Vidar Hasfjord 2023-11-20
Thanks for the assistance. I really appreciate your efforts - please don't do any harm to yourself because of my query.... ;-)
Yes - this is the solution I suspect - I have briefly progressed further and my code is at least creating the window correctly from the DLL though it now hangs when I try to interact with it - I will investigate further.
TModule* module = child->GetModule();
TMenuDescr menu(IDM_EDITFILE_CHILD, 0, 2, 0, 0, 0, 0, module);
That definitely helps the system to find the correct resources in the DLL itself.
Once I get the code working correctly under 6.30 I will then progress and advise what happens under BC5.5
Regarding your design software - is it freeware? it certainly looks impressive. It's very similar to what I have done with my Civil Suite Engineering Design suite - www.civilsuite.com
Thanks.
@keithcsimon wrote:
I got really frustrated with the IDE, but to be fair to good old Borland C++, the frustration was exacerbated by bugs and instability with the Tools55 add-on for BCC 5.5. I have now removed any recommendation of this add-on in our documentation. Instead, I recommend moving to a makefile-based build solution at this point in the porting process. Makefiles make it much easier to control and compare compiler and linker settings.
Although some (like me) might find creating makefiles daunting, luckily there is a command to generate makefiles in the IDE (Project | Generate makefile). And AI assistants, such as Bing Chat, can be helpful with such tasks as well.
Good to hear. I hope the porting process progresses smoothly from here. Keep us updated.
Lima VVA is now (since 2017) open-source software freely available with a GPLv3 licence. So you can download and use the application free of charge. But usage has some restrictions and requirements, especially regarding the use and modification of the source code. See the licence for details.
I recently (last June) completed the English translation of the software, so I would very much appreciate feedback from a real civil engineer on any mistranslation of terms, etc. So let me know if you take a closer look.
Indeed! In the "Lima VVA" name, the "VVA" part stands for "veg, vann og avløp" in Norwegian, which translates to "road, water and drainage/sewerage" in English. "Lima" is inherited from the predecessor software "LIMA", which stood for "linjepålegg and masseberegning" in Norwegian, which translates to "vertical alignment and earthworks" in English.
While the main function of Lima VVA is the design and earthwork calculation for simple roads, version 4 also draws longitudinal section and horizontal plan for water and drainage networks associated with the road. However, version 5 (in development) drops the latter functionality and focuses on road design and earthworks.
Version 4 uses OWLNext 8 (prerelease) and C++17, while version 5 uses Owlet (my experimental branch) and C++20 (or later).
I will have a look at your software. Great work!
PS. By the way, here is my company website (in Norwegian, but automatic translation to English in Chrome and Edge works well): Hasfjord Software AS
Last edit: Vidar Hasfjord 2023-11-22
Thanks again for the assistance.
I've hit the wall a bit with my MENU in the DLL.
It seems that the response table from the main EXE is being used and not the respnse table in the DLL. This only applies to the menus. The normal buttongadgets are responding / activating correctly. Only the Menu response are not activating.
The MDI application swops correctly between the EXE and DLL windows and sets the menu correctly for the appropriate window. Its just that the responses are still coming from the EXE response table. Any ideas what could be wrong?
I read through a number of articles and discussions here about response tables and know there were some changes implemented but only after 6.4 i think. Thanks.
@keithcsimon wrote:
Strange. The best advice I can come up with is to recreate the issue in a minimal test case. If you still cannot identify the cause and resolve it, then share the test case.
That's correct. From the top of my head, I cannot recall any relevant changes in 6.30. You might have run into a corner-case.
PS. Make sure your menu command IDs are unique across the application.
Last edit: Vidar Hasfjord 2023-11-23
Hi Vidar
I have adapted the MDI File example from the Borland C++ 5.02 OWL folder as follows:
I have two MDI children (SEWER AND ROAD) which are created successfully as child windows in the EXE and which adapt the menus according to each child window accordingly. (See the creation of New Sewer MDI Child and New Road MDI Child (EXE) in the menus when first loaded.)
I then created the ROAD MDI Child window in the DLL as per the attached code. This fails to create the window successfully (using Dynamic Linking) or if it creates the window it simply crashes the moment I click onto this child window (using Static linking).
I have included the IDE Project files for the MDIFile and RoadDLL. I have not included any OWLNEXT libraries - I'm currently using OWLNext 6.30.
Please could you review and possibly advise why the MDI Child created in the DLL fails? If you do get this working please check if the Child DLL responds to the menu items for the road menu?
I have spent a long time this week checking my original code in my main application and it fails similarly and doesn't respond to the menus. I therefore created this simple EXE and DLL in asking for your assistance.
Thanks once again for assisting.
Please ignore the message above - I had a bug in the line below..
// mainFrame->AssignMenu(104);
mainFrame - a global variable was not defined.
I can confirm both BC5.02 + OWL and BC5.02 and OWLNext both now work with the MDI Child in either the DLL or the EXE and both child windows respond to their menu items.
Thanks - some progress at least.... :-)
I will test as a static build next and report any funny results.
@keithcsimon wrote:
Too late! :-)
You have an uninitialised global variable mainFrame in your DLL, which you dereference in TRoadMDIChild::EvMDIActivate, hence causing undefined behaviour (e.g. crash).
You can eliminate the global variable by calling TApplication::GetMainWindow instead, after which the code seems to work in my tests, including menu item handlers in the DLL (TRoadMDIChild::RoadTest1 etc.).
Some tips:
Last edit: Vidar Hasfjord 2023-11-27
By the way, Bing Chat was able to spot this issue. See below.
(We're living in quite remarkable times as humanity creates intelligent agents.)
Me: Hi! I'm having problems with the following code. It either crashes or doesn't work as intended. Can you spot the issue? [test case]
Bing: The problem seems to be that you’re inheriting from both TMDIChild and TDecoratedFrame. This is causing ambiguity in your code because both classes have similar methods and the compiler doesn’t know which one to use. [...] I hope this helps! Let me know if you have any other questions.
Me: Thanks, that a good thing to look for, but that's not it. I've tested that part and the multiple inheritance works fine in other code (my EXE module). Any other ideas?
Bing: I see. If the multiple inheritance isn’t the issue, then let’s look at other possibilities.
One thing that stands out is the DLL_CmNewRoadWindow function. This function is marked with _export, which suggests that it’s intended to be used as a DLL export. However, it seems to be defined in the same file as the rest of your code. If this code is meant to be compiled into a DLL, then it should be fine, but if it’s being compiled into an EXE, this could potentially cause problems.
Also, in the DLL_CmNewRoadWindow function, you’re creating a new TRoadMDIChild object with new, but it doesn’t seem like this object is ever deleted. This could potentially lead to a memory leak.
Another potential issue is the use of the mainFrame global variable. This variable is used in the EvMDIActivate method, but it’s not clear where it’s being set. If it’s not being properly initialized before EvMDIActivate is called, this could potentially lead to a crash.
Lastly, the EvLButtonDown, EvRButtonDown, and EvMouseMove methods are empty. If these are being called in response to mouse events, and the intention is to do nothing, then it should be fine. However, if there’s supposed to be code in these methods, then this could be why the program isn’t behaving as expected.
I hope this gives you some ideas on what to look for. Debugging can be a complex process, and it often involves a lot of trial and error. Good luck!
Me: Super! The uninitialised global variable was the issue. Thanks!
Bing: I'm glad to hear that you found the issue! Remember, global variables can be tricky to manage due to their scope. It's generally a good practice to avoid them when possible, or ensure they are properly initialized before use. If you have any more questions or need further help, feel free to ask. Happy coding!
Just some feedback - I see that OWL5_COMPAT must be defined else the child windows won't respond the menu messages.
I have thus far managed to compile and link one of my design DLL modules into the EXE and all seems to work just fine. I can now finalise that module before attempting the other modules. Without OWL5_COMPAT I note even the MDI window was not being created correctly (i.e. not maximized, icons missing, window would hang / crash if moved etc).
At what stage should I be removing OWL5_COMPAT - when i switch to a higher compiler and OWLNext version above 6.30?
Thanks again for the assistance and hints as listed - they proved very useful. I'm progressing to OWLNext 7 albeit at a crawl. :-)
@keithcsimon wrote:
That's excellent news! And it is particularly noteworthy that the modularity of your application design is now paying back. Modularity is a key concept to manage complexity efficiently.
This is curious. Thanks for the feedback.
It would be good to understand why this is. I know there is a change in 6.32 that affects the window setup sequence [bugs:#102] and is disabled by OWL5_COMPAT, and there are major changes to Windows message dispatch in 6.44, some of which may be disabled by OWL5_COMPAT. However, I cannot recall any relevant documented changes in 6.30. So any clarification on this would be welcome.
See OWL Compatibility Build Modes in OWLNext.
That said, I guess this issue shows an unfortunate dependency on OWL implementation details in your application. Consider eliminating such dependencies. Even if that means you have to give up some neat custom behaviour in you application, it may be worth removing such customisations during the porting process. Then, when you arrive at OWLNext 7, you can consider reintroducing customisations where it makes sense.
For example, in your test case, the explicit custom implementation of menu merging (EvMDIActivate) and the overriding of message processing (PreProcessMsg) are alarming. If you can eliminate such complexity (at least temporarily during the porting), your application code should become less brittle.
On the other hand, you may have run into a bug in OWLNext. To eliminate this possibility, please try to recreate the issue in a very simple test case (e.g. based on the MDIFile example), and if you can, report the issue as a bug.
There is also the possibility that your application code has a transient bug which is otherwise unrelated to OWL5_COMPAT, but just so happens to reveal itself in this build mode. For example, this could be an uninitialised variable, just as in the test case you shared. And, of course, it is even possible that OWLNext 6.30 has transient bugs. A minimal test case will help investigate the true cause.
According to our recommended step-by-step approach, you should ideally stop depending on the OWL5_COMPAT mode after having ported to OWLNext 6.36 and modern tools.
Good — and don't despair about the slow progress. You are learning valuable lessons about porting, about the strength and weaknesses of your application code, and about OWL and OWLNext design, implementation and stumbling blocks.
Related
Bugs:
#102Wiki: OWL_Compatibility_modes
Wiki: Windows_Message_Dispatch_in_OWLNext
Last edit: Vidar Hasfjord 2023-11-28
@keithcsimon wrote:
How is your progress?
Hi Vidar
To be honest I've made no progress since December. We've had holidays for the Construction Industry for a month here in South Africa. Getting back to work mid January brought along other challenges in the office and I have simply had no time to restart my development work. I also haven't installed your Lima VVA as yet either. Hopefully from next month onwards things will get back to normal . we're tendering for Civil Engineering work and implementing projects which need my immediate attention first. Some engineering clients are also not assisting which is the really frustrating part.
I managed to get my application converted to OwlNext but have not moved further. I've also been fixing the old code base and adding some new features which were missing - then I need to take that code into OwlNext again. effectively managing two code bases which isn't ideal. (Production application in legacy BC5.02 / OWL and then Development in both Legacy / OWL and OwlNext).
How are you doing? Still enjoying semi-retirement or having other software development plans?
Moderator: Removed superfluous email headers and quoted contents.
Last edit: Vidar Hasfjord 2024-02-08
@keithcsimon wrote:
That's great! Please continue to update us on your progress with the OWLNext porting.
Indeed, I am enjoying my semi-retirement. There's still a lot of work to be done on Lima VVA and OWLNext/Owlet, which keeps me occupied whenever I feel like diving back into software development.