Link to home
Start Free TrialLog in
Avatar of Matthew Cioffi
Matthew CioffiFlag for United States of America

asked on

Updating old C++ program

Is it possible to recompile a program using increasingly newer compilers to "update" it?

We have a very old program that was compiled using Borland C++ around 1998, Borland C++ v3.1 to be specific.  I know it is ancient, but the program has become central to the business.  I'm not a programmer/developer but I'm trying to piece a little of this together.  Is it possible to use a newer compiler, maybe one or versions newer and recompile?  If we did that would that have any useful effect on the program?  
Here is what I want to do in the VERY SHORT TERM.
"upgrade" the program to work on a 64 BIT OS.  Right now it will only run on 32 bit XP or Windows 7.  32 bit Windows 10 will not work.  I would prefer to get it to work on Windows 10 64 so we can get away from the Windows 7 at 32 bit or Windows 7 at 64 bit with an XP mode on it.  
If possible I would also like to change how it sends to printers.  I'm not sure where in the program it does that, but it will only print to HP printers that are using LPT1.  I would like to allow it to print to the default printer.

Any suggestions for a NON PROGRAMMER to pursue?

Thanks.
Avatar of Kent Olsen
Kent Olsen
Flag of United States of America image

Hi Matthew,

Yes, you can compile that old C++ program with a newer compiler.  But it will likely require some code changes and, depending on what the application does, could be minor or very extensive.  The only way to know is to try and recompile the source code with the new compiler and see what happens.

Does the program have a GUI interface?  If so, I suspect that there's a lot of work to make your application run in 64-bit mode.  

Borland's (Embarcadero's) 64 bit C++ IDE is over $1,000 for a single license.  If your application does not have a GUI interface it might be simpler and cheaper to install CYGWIN (and the C++ compiler) and compile it from the CYGWIN command line.


Good Luck!
Kent
Hi,

@Kent Olsen: Borland C++ v3.1 was targeting just DOS applications, with a text-based pseudo UI.

 @Matthew Cioffi: If your application is using this text-based pseudo UI, you don't have any possibility to recompile it because it's using what Borland was calling TurboVision: a set of object-oriented libraries dedicated to this purpose. If it's not based on this UI, still it's a problem because of the non-standard libraries used by Borland specific products.
If the application is not really necessary to be implemented in C++, I would suggest having it implemented in C# or Java that will allow faster development (especially the UI part).
Regarding the printing from the old app, again it's not possible (not in an easy way) to change the implementation because LPT1 was handled as a text device, with a low-level drive, it text mode and this is not possible to be done in Windows (default printer)
Avatar of Matthew Cioffi

ASKER

This is not looking good than.  

I would say it is probably the text-based pseudo UI.  But I do not know for sure.  Is there some way to check that to be sure?

Any other suggestions?
@Eduard Ghergu:  I had completely forgotten that the old DOS UI interface was ported to the C++ IDE.  I was thinking that it had been retired along with the C IDE.  Good catch, and thanks!

@Matthew:  There are several functions that are unique to the DOS interface.  textattr and gotoxy come to mind.  Check your source code and see if either of these are used.  (I think they're both all lower case, but it's been a very long time since I last saw them.)


Kent
I decided to poke around with this a little and see what I could see so to speak.

I have installed and setup a copy of Borland C++ 4 and tried to open and compile the project.  I get these messages.
I suspect it may be expecting too much to go back and forth with all the errors that may pop up.  But I'm very curious to see if anyone has any thoughts.  I would love to try getting it compiled in at least one newer compiler just to see if I can do it.  It is sort of academic for me at this point.
OldProgCompileError.jpg
You could use conditional code to compile some lines when using the 3.1 compiler and other lines when using 4.0.  If you're not comfortable with that, it may be easier to just save a copy of the source for the 3.1 compiler (which you'll probably never use again) and change the source until you have a program compatible with 4.0.
can you post some code? check where the 'main' function is implemented and post it. if there is a UI (or perhaps GUI. i remember that i used borland c++ on os/2 and win32s with graphical resource files) you should have some cpp files named xxxdlg.cpp or yyyview.cpp or zzzui.cpp.

if the programs runs 'on 32 bit XP or Windows 7', it also should/could run on windows 10. i think it is only a lack of libraries. did you try to run it on a 64-bit windows 7 ? if it runs there, try to find (old) depends.exe. if not available, you can download it from various places. depends.exe shows which libraries were used by your program. you have to check the application folder of your program and the windows\syswow64 folder of the windows 7 which files are needed by your program and where you can get them. you would copy those files to the application folder (that is the folder where the .exe file of your program resides) and then try to run it on windows 10. do it in a cmd shell (dos box) such that you would see error messages i. e. a missing start library. if that fails you may try to install last used borland ide at the windows 10. the goal is not to use the compiler but to install the basic environment to run the program.

if all fails, think of running the program in a vm which probably is the easiest way,

Sara
Can you post the #include statements?  That'll identify most of the proprietary libraries/functions that could be a problem.
I opened PROJ12.IDE in Borland C++ 4.0.  I tried to run the Bring all targets up-to-date by compiling and linking, as necessary.  It created and opened a file DB_RPT.C.  This is at the top of the file.

Does this help?

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <dos.h>
#include "db_defs.h"
#include "vmisc.h"
#include "vfile.h"
extern struct date today;
extern SYSREC sysvar;
extern PRNCODES prnCodes;
extern CHAR *month[13];
extern FILE *defPrinter;
extern MOUSE_CLICK *points;
Hi,
From the screen capture, it looks like that rpt is implemented in plain C
Text-based pseudo UI will look like this: https://winworldpc.com/product/borland-c/30
As I remember, Borland C++ 4.x was the first one that was targeting Win 3.1. So, if it runs on Windows 7, most likely it's executed in compatibility mode. It simply cannot be executed as a 32 or 64 bit because it was created for 16-bit.
I just have seen what you have pasted. That part is specific to the code that it's used to print the report, it's not really relevant for the app. Can you identify the file with the main function and paste it's content?
I'm not sure exactly where to look, how about this?
/**
*   DB.C        - Main Program Module for KK Distrib
*
*
*   Description -
*
*
*
*
*
*
*   Revision History:
*
*   Version     Date        Author      Comments
*   -------     --------    ------      --------------------------------
*   3.00a       09-07-93     SAJ        Revision 3
*
**/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <dos.h>
#include <ctype.h>
#include <conio.h>
#include <math.h>
#include <io.h>

#ifdef DEBUG
#include <malloc.h>
#endif

#include "db_defs.h"
#include "vmouse.h"
#include "vmisc.h"
#include "vfile.h"
#include "db_defs.h"
#include "vmouse.h"
#include "vmisc.h"
#include "vfile.h"

These are application-specific. Do you have a picture of how the app looks like when it's executed?
conio.h

That's Borland's Console I/O interface, and will probably be the biggest challenge in converting this application.

That and the printer driver.  Those old programs wrote to a port, not a device, so configuring a printer will be a bit of code, too.
I could live with the printer issue if we got it working in newer OS.  That could be a phase 2 heavy lift down the road.
KKDistribMainWindow.jpg
conio.h was provided by many DOS targeting compilers, in this case by Borland. Yes, it's one of the difficult areas to take care about.
As for the other comment about 32 bit Win 7 and 32 bit win 10.  I was unable to get that to work.  I did not do too much digging, but I will look for the depends.exe and see if I can tell what failed.

What happens when the program is kicked off is that a shortcut to a shared directory runs that program with user details.

For example:  Change to the Y drive where the program and data live.  run the DB.EXE with the user name CC and the password ccweb.
y:
db.exe cc ccweb
cd\
Hi!

As it looks in the screen capture, the UI is easy to be reimplemented. The existing app functions can be called from the new UI.
That seems like good news.
How can I troubleshoot the error I got with the TextEditor line?  I have been looking at the files but I cannot find how to resolve it.
Hi!

What error do you mean?
What happens when the program is kicked off is that a shortcut to a shared directory runs that program with user details.

don't know why you complicate the task by running the executable from a remote share. you may run into issues which are unrelated to your compiler problem.

you should copy the whole application folder from win 7 to win 10. it would be best if the path to the folder is the same. then start

         windows\syswow64\cmd.exe

which is the 32-bit command interpreter (blame MS for running 64-bit programs from system32 and 32-bit programs from syswow64). it shouldn't make much difference, but it is better to eliminate each possible complication. then navigate to your program folder and start the program. tell what happened in detail.

the error I got with the TextEditor line?
post line 933 (and some lines before and after) from dbrpt.c

you can take the error message literally and so the arguments for the function have changed with the newer compiler. you have to check the header files which arguments are required and add the missing ones.

Sara
line 1184 conversion may lose significant digits

this happens if you assign a 32-bit variable to a 16 bit, i. e. a double to a float or a long int to a short int.

it also may happen if a 64-bit integer (like size_t) was assigned to an 32-bit integer (like int).

for example the statement

int siz = strlen("abcdefg");

returns size_t type which changed from 32 bit to 64 bit with compilers in this century.

Sara
Hi Matthew,

There may be an easier way.  :)

Download and install DosBox.  It's a DOS command line (like) interface that runs many old 16 bit applications.  It's pretty straight forward, and you should be able to easily configure DosBox to run from an icon on the desktop that automatically fires up your application.

That will be easier than converting the program.  And if you do decide to convert it, the current version will be functional on your 64 bit systems until your programming is complete.


Kent
Thank you all for your suggestions and comments.  Also I apologize for not responding yesterday, I was away from my desk on other things all day.  

I'm going to take another look at DOS Box, I had played around with it in the past, but did not have much success.

Sara, below is a snippet of the code before and after the line that is erroring, TextEditor(textfname, cd.fax, cd.accounting_email);

            len = strlen(name);
                for(i = 0; i < len; i++)
                {
                    if(name[i] == ' ')
                    {
                        name[i] = '\0';
                        break;
                    }
                }

                fprintf(fp, "        Dear %s:\n\r\n\r", name);
                fprintf(fp, "            We have bid your company on the following jobs in the last\n\r");
                fprintf(fp, "        few weeks/month.  Could you please advise if any of these were\n\r");
                fprintf(fp, "        awarded to your firm on the status.\n\r\n\r\n\r");

                fprintf(fp, "        Job Code Job Name                  Client Contact       Bid Date\n\r");
                fprintf(fp, "        ________________________________________________________________\n\r");

                for (i=0; i<k; i++) 
                {
                    s_read(JB, &jb, i);
                    vec = s_getno(ES, 0, jb.code);
                    s_read(ES, &es, vec);
                    fprintf(fp, "        %-8s %-25.25s %-20.20s %-8s\n\r",jb.code,jb.name,es.estname,jb.due);
                }
                
                fprintf(fp, "\n\r\n\r            Your help is greatly appreciated in updating our files.\n\r\n\r");
                fprintf(fp, "        Thank you.\n\r\n\r\n\r");

                vec = s_getno(SP, 0, curuser.spcode);
                if (vec == -1)
                    break;
                    
                memset(&sp, 0, sizeof(SPREC));
                s_read(SP, &sp, vec);
                s_close(SP);

                fprintf(fp, "        %s\n\r", sp.name);
                fprintf(fp, "        %s\n\r\n\r", sp.title);
        } while (0);

    FileClose(handle);
    
    s_close(JB);
    s_delfile(JB);       /* Delete temp JB file. */

    strcpy(db[JB].fname, ftemp);
    strcpy(db[JB].extension, etemp);
    strcpy(db[JB].path, ptemp);

    if (k != 0)
    {
        filecls(fp);
        TextEditor(textfname, cd.fax, cd.accounting_email);
        FileDelete(textfname);
    }

    return(0);
}


/*****************************************************************************
                Product Search Report
*****************************************************************************/
INT ProductSearchReport(VOID)
{
    POREC po;
    VDREC vd;
    PDREC pd;
    PLREC pl;
    ESREC es;
    CHAR sdate[10], edate[10], status[2], ftemp[9], etemp[4], ptemp[40];
    CHAR fname[60], todaysdate[9];
    INT i, j, k, l, key, pos, test, handle, np, lines, bg, ed, numPL;
    BOOLEAN endFlg, endthis;
    CHAR jbcode[9];

    /* Inits */
    endFlg = endthis = FALSE;
    vd.code[0] = '\0';
    pd.code[0] = '\0';
    status[0] = '\0';
    key = KEY_DOWN;
    k = pos = np = lines = 0;
    jbcode[0] = '\0';

Open in new window

Hi,

This code is plain C, there is nothing C++ specific at first sight. There is a makefile available? If not, you can grab a copy of Borland C++ 5.x form here: https://winworldpc.com/download/35c2be17-78c3-8cc3-8e11-c3a6c2bb2a52 and use ..\BC5\BIN\IDETOMAK.EXE utility to generate one from the .ide file. You can build the project using different toolsets such as:

Microsoft: Install the build tools: https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2019, and use the nmake utility

GNU: Install the MingW: https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win32/Personal%20Builds/mingw-builds/installer/mingw-w64-install.exe/download, and use mingw32-make

I'm looking forward to see how it's going.
Eduard, so far everything I have tried has bombed with the error about the TextEditor and too few parameters.  I'm trying to figure out how to set the proper number of parameters.  I have found 2 .c files that seem like the most likely place for this to be coming from.  I have included them here if anyone can tell me how many parameters it is expecting and if possible what they are.
1_Editor.c
1_editor1.c
This is the declaration in the C file:

  VOID TextEditor(const CHAR *fnb, const CHAR *ph, const CHAR *email, const CHAR *jbcode)

A comment next to it said that the 4th parameter was added to support the job code.  If the error that your getting is on the call to TextEditor, you have a mismatch in the call and the declaration.  Either the source files don't match or there's other development that occurred that wasn't complete.

Check the local header files (those with names that are in double quotes) to see if any of them declare TextEditor() and its parameters.
Hi,

Yes, it's the jbcode that it's missing. Can you pass NULL as an argument value for now and see it it's working?
Can you pass NULL as an argument value for now

better use variable 'jbcode' which very likely is the right one.

TextEditor(textfname, cd.fax, cd.accounting_email, jbcode);

Open in new window



Sara
Thank you.
I tried a number of things and es.jbcode seems to have worked, it got rid of the ERROR regarding the parameters.  Using NULL also worked.  Now I have a series of warnings that error out when it hits 255.
newKKIssues.PNG
I'm interested in continuing to fiddle with this, but if you folks feel it is getting to complicated I will close this out and try something else.  
I do appreciate the help and willingness to help me on this.
you normally can take the text of a warning or error literally.

Initialization is only partially bracketed

an initialization that needs brackets is for example the initialization of an array of struct objects:

xxx.h 

struct YYY
{
     double x;
     double y;
};

struct XXX
{
     int i;
     YYY pt;
      char * szp;
};

Open in new window


in c the same structures might be defined using typedef's
// xxx.h 

typedef struct _yyy
{
     double x;
     double y;
} YYY;

typedef struct _xxx
{
     int i;
     YYY pt;
      char * szp;
} XXX;     

Open in new window


with that you might have an array of XXX and want initialize it:

#define NUM_XXX 3
...

double f()
{
      XXX   xxxs[NUM_XXX] = 
      {      
            {   10, { 1.0, 2.0 }, "ABC" },
            {   20, { 3.0, 4.0 }, "DEF" },
            {   30, { 5.0, -1.0 }, NULL },
       };
       return xxxs[0].pt.x * xxxs[1].pt.y * xxxs[2].i;        
}

Open in new window

     

all the brackets used in the sample are needed. if one is missing, e. g. the middle ones for the pt structure, you would get a warning (or error).

suspicious pointer conversion

if the code was compiled with c compiler, conversions between pointers of different type might compile without errors. ansi-c compilers might be more strict and give a warning if for example you initialize a double pointer with a pointer to int.

struct ZZZ
{
       int i;
       double pd;
};

const int n = 100;
ZZZ z = { 1,  &n };  

Open in new window


Sara
The "Suspicious pointer conversion" error can probably be ignored for now.  It's a common thing and often is no more than a variable declared as a CHAR and that variable is passed to a function where the parameter is declared as UNSIGNED CHAR.  (Or vice-versa.)

I'd be interested to see an example of the code that produces "Initialization is only partially bracketed".

Kent
the errors are both in the same line. it is a good chance that adding the brackets could solve the pointer issue as well.

Sara
Hi Sara,

The file that is generating the errors is called "DB_DEFS.C".  Based on the name It probably contains all of the variables/objects that the program uses to interact with their database.  Since it apparently compiled cleanly at one time, this may be as simple as a macro or definition that propagates through the file, or finding a compiler option that will accept the code as is.



Hi Mathew.

Can you post part of that file?  From line 1 through the second error would be ideal.

Kent
Hi,
Or, maybe, it’s a missing semicolon...
Hello,
I have been swamped, but coming around again to this.  If you are still interested in taking a look, here is the file mentioned above.
DB_DEFS.C
the db_defs.c contains only data no functions. we need header file db_defs.h to find out whether it compiles.

you also should post - at least - the .c file which contains function main. check whether it includes more private header files like db_defs.h.

Sara
Hello,

Sorry I had to step back from this for a bit.  We have some other changes we are working on.  I will try to get you the .h file in the next day or 2.  I do appreciate the help.
This question needs an answer!
Become an EE member today
7 DAY FREE TRIAL
Members can start a 7-Day Free trial then enjoy unlimited access to the platform.
View membership options
or
Learn why we charge membership fees
We get it - no one likes a content blocker. Take one extra minute and find out why we block content.