Suppose I've got a large ActiveX library written in Delphi, let's call it Lib1.dll. It contains multiple interfaces. The task is to rename the library to Lib2.dll in such a way, that another application can call both methods from Lib1 and Lib2 at the same time.
I thought to do it in next way:
Rename Delphi project to Lib2 (that will rename the library).
Replace *Lib1_TLB.pas* file with *Lib2_TLB.pas* with the same content, but with new GUIDs of interfaces and coclasses.
Paste new GUIDs to Lib2.ridl.
Generate new Lib2.tlb file from that ridl and that should be ok.
But it isn't. I'm getting Delphi error "Couldn't find Lib1.ridl file". Okay, rename both ridl and tlb.pas back to Lib1, compile&build ok, but registering ActiveX server crashes the IDE.
Please suggest me a way to rename the lib or how to make my current progress work.
I assume you are using a recent version of Delphi using .ridl files for COM interfaces so keep in mind that it is the central unit for dealing with COM. You may start with copying and renaming the ridl file from Lib1.ridl to Lib2.ridl. Then inside Lib2.ridl, not _TLB.pas (which is recreated automatically) regenerate the library's GUID and those of coclasses. Interfaces may remain unchanged. After that you should be able to generate tlb and refresh _TLB.pas and finally build and register the new library.
Related
I have all the files needed to open the unit and code but I can't make any changes or compile because the Project.dproj and Project.dpr files are missing. However, I have the .exe file. Is there any way by which the aforementioned files can be extracted from the .exe file?
If you have all of the source files, meaning the .pas and .dfm files, then the first thing I'd do is add them all into a new project and try to compile it. It'll either work, meaning you've got everything you need, or it will generate errors.
There would be three kinds of errors:
The first is the most likely -- the forms might use components that you don't have installed. This will be obivous if you try to open the forms in the IDE. If they open without fanfare, GREAT! If you get a warning box saying "Cannot locate component: remove references to it?" or something like that, then you're probably hosed.
The second is version-specific errors -- stuff that's old and crufty and no longer supported by the language.
Third, the program may use run-time libraries that you don't have.
The compiler adds RTTI metadata, including unit names, when it builds, and if you know about how the RTTI tables are laid out it's possible to extract this. The unit list is the principal component of the DPR file, but it takes some serious work to access it and I'm not aware of any tools out there that read the RTTI tables that have been kept up to date beyond the Delphi 7 era.
As for the .dproj file, you're out of luck. That doesn't actually contain any code that gets "compiled in" to the EXE; it's a set of build instructions for how to produce the EXE. But if the Delphi IDE doesn't have one, it can generate a default .dproj from the .dpr, if you can produce that.
I'm curious, though. How did you obtain the .pas files but not the .dpr?
In C++Builder XE5.
My understanding is that the binary file MyProject.res (which is created by the compiler in the same directory as the .cbproj file) contains compiled versions of the program icon and the project version details (although mine also seems to contain an XML manifest).
But this info is also contained in the .cbproj file and the .ico files; and if I delete the .res file then it seems to get recreated exactly was it was next time I open the project.
So is it safe to mark *.res as not being in source control? (I use git). And/Or is it possible to have it generated in the same directory as the object files instead, so it's not mixed in with the source?
(This certainly wasn't safe in C++Builder 5 - if you deleted the .res file then it complained it couldn't find it, and you lost your icons).
Update: Does this also apply to the .tlb file? This seems to be compiled based on the .ridl file, and if I delete it then it is automatically regenerated.
C++ Builder 6.0 and later will recreate RES files if deleted. I treat them as other temporary/build files (like OBJ files) and do not put them in version control software. I do have nightly backups that include all of these files though, which I think is still good practice.
I am not sure about TLB files. I would temporarily delete (aka-rename) one and see if it gets recreated to the same state. If so, should be same as RES files.
This does not hold true for 3rd party libraries though, if all you have is compiled resources. In that case, I still do not place in my version control though, since I am not going to be modifying them. I just have my backups.
For what it's worth, the TFS source control defaults are to exclude *.res but include *.tlb.
So you should expect *.res files to be created by their associated builds. If the build isn't going to be present, then the *.res file should be included.
I suspect that you're right about *.tlb files being built as well, but perhaps TFS doesn't exclude these on default because the extension isn't entirely unique to OLE type library files alone.
I wrote a test project which exposes a COM factory and object. Having tested and found our implementation to be working - i now want to move the code + typelibrary into our main project.
I copied the RIDL + TLB file into the main-project folder. I renamed both files accordingly (to the main project name). I also deleted the project resource file just in case Delphi places the TLB data here. And naturally i deleted the old TLB and RIDL files (I also deleted all DCU files, just in case). Last, I added the RIDL file to the main project and compiled.
The RIDL file is picked up by Delphi during compilation, it generates the TLB file as expected, but somehow it doesnt inject the TLB data into the exefile. So when i start the application i simply get an error message "Unable to load typelibrary". In my code i automatically create the COM factory on startup and update the windows registry. On shutdown the reverse happens.
Having fiddled with the typelibrary editor for hours, trying to register the typelibrary/exe from both Delphi and shell/regsvr32, delphi for some magical reason picked up the new file and everything worked as expected.
Problem is, I have no idea "why" it didnt work to begin with, nor do i know why it worked after hours of trying different combinations. So I am unable to reproduce the success. When updating our codebase I had to do the same on another computer/revision -- but this time it refused to work.
How can I force Delphi to inject the typelibrary?
Is there some "trick" (except the obvious like refreshing the RIDL, which generates the unit correctly but doesnt do anything about the TLB resource problem).
As I understand it the steps are as follows:
Add the .ridl file to the project. This will result in the build process compiling it to a .tlb file.
Link the .tlb resource with a $R conditional directive like this: {$R MyProject.tlb}
I have a delphi project that somehow has become corrupted. I upgraded to Advantage 11.1 components (using XE) and now I'm getting the following error message when opening the project:
acctTbl: Error 5018: The handle given was not recognized by
Advantage. Verify specified handle is open/active. The given handle
is not recognized as a valid Advantage Client Engine
Because the error occurs, the data module DFM is not built, so I can't "adjust" any settings.
acctTbl is the first table in the DFM, so the error might occur for the ones following, but I can't tell.
We are not using the server, just the "Local Server".
I have tried to go back to version 10 of the components, but still the error continues.
I have also tried removing all of the projects object code and only opening the PAS and DFM files (by reverting from SVN).
Any help is greatly appreciated.
You can open the .dfm in a text editor (like Notepad), and change the AdsConnection.Connected property to false, and change any AdsTable or ADSQuery component's Active flags to false as well. (I'd suggest closing the IDE first, to make sure it doesn't cache a reference.) This will at least let you open the project and make whatever changes are needed to compile with the new version of ADS.
If the file has been updated through many older versions of Delphi prior to XE, there's a chance you still have a binary format .dfm file (meaning you'll see all kinds of strange symbols in Notepad when you open the .dfm file). If that's the case, Delphi includes a conversion utility (convert.exe, found in your $(DELPHI)\Bin folder), and you can use the following steps to convert it to text format and then make the changes (there's no need to convert it back after - the default is to create text .dfm files when new forms are created, and Delphi uses them very well as text).
Make a backup copy of your datamodule's .DFM somewhere safe first!
After making the backup copy, open a command window in your project folder, and run
Convert.exe -1 YourDataModule.dfm
The command says to convert in place (-i), which means the existing binary .dfm is overwritten by the new text .dfm (and the reason I stressed making a backup copy first). If you don't want to overwrite, you can omit the -i switch, and it will create a YourDataModule.txt file in the folder instead; you can then manually rename YourDataModule.dfm to a different name, and then rename YourDataModule.txt to YourDataModule.dfm.
I am trying to start making my own libraries avaialble as packages prior to compiling my Apps with these packages hence modularising my code. For years I've 'sort of' understood packages, breathing a sigh of relief when I load a component package and click on 'Install' and it does. I understand that the process of installing a component (or components) is via the creation of a BPL which is then registered with the IDE.
Where I begin to get lost is how to make files available so that I can compile with EITHER a package OR pre-compiled dcu's (like the third party vendors do) and without pointing my project at the source code all the time. I can create a package with the following settings:
where I've specified that all my output will go into 'c:\scratch\wow'. After a build I find TEST.BPL, TEST.DCP and lots of DUC's. Now, when I point another project at this folder to use the DCU's, I get a missing DFM error (one of the units is a form). Should I be manually copying needed DFM's into this output folder? The DPK knows about this form, so why do I not get the DFM copied for me? I presume that using TEST.BPL, that file contains everything, but I wish to work in the two modes. Of course I can get around this by including the source folder in my project search path to find the DFM but third party libraries seem to already have the DFM's in their output folder. Did they install them there using the installer?
Thanks
instead
As others say you could use post-build events to copy your DFM files into place. Other people use a one-time external batch file that copies the DFMs to the DCU folder.
Personally I see very little benefit to making packages for things which are not developed also as reusable components. I also see very little benefit in partitioning an existing application into packages, when you don't reasonably need to use the same subsection or package more than once, or at designtime.
Things I would put into packages:
Delphi visual and non-visual components.
Things which absolutely must be plugged in at runtime, or left out. For example, supposing I sell MetaWare Light and MetaWare Pro, and instead of using compiler IFDEFs to build a differnt binary, I preferred for some reason to simply not ship the ADVANCEDFEATURE.BPL with my systems.
Things to beware of with packages:
I have run into a lot of compiler bugs when combining packages with generics. I have also run into IDE crashes and lockups, in Delphi 2009, 2010, XE and XE2. (I believe XE3 is better)
You should learn a bit about BorlandMM.dll and shared memory management in the BPL world before you move to it. There are some subtleties.
Packages limits the ability of the linker to decide what to remove. In fact, it pretty much destroys it. Packages contain everything that is linked into them, and nothing publically accessible can be removed.
Once you've created a binary package and shipped it to even one customer, you have a pretty difficult to modify contract (this BPL contains a particular signature or application binary interface) you have to be careful in the future to never change them, or mix and match them. Beware of DLL hell, even among your own customers, and be prepared to use versioning on your packages. Just as delphi packages have a version suffix, I recommend you use version suffixes in your own packages right off the bat, and bump them whenever binary compatibility has changed.
Delphi handles build dependencies between packages about as well as could be hoped, which is less well than a single monolithic application. In applications that I have that make heavy use of packages, I find project groups that contain a bunch of packages that depend on each other are very difficult to manage and build quickly. In fact, I have experienced that both compiles and builds are slower and more frustrating than they would be in a singular 750Kline megaproject.
I really wonder if you're not that into the package area of Delphi (you breath a sigh of relief whenever a delphi component actually builds and installs without issue?) if you really want to move into the Packages World totally. By all means, you should experiment. But I wouldn't bet the farm on it yet. Learn some more first.
Yes, you should copy the .dfm to the directory with the compiled units (.dcus), if that is the only directory you want in your search path. The BPL will of course contain the .dfms, and you need a .dcp to be able to link a BPL with your app.
Third party tools must have put the .dfms together with the .dcus in the directory using their installer, indeed.
Instead of copying *.DFM manually you can use Post-Build Event (Project/Options/Build Event), ex:
copy “$(PROJECTDIR)\Unit1.DFM” “c:\Scratch\wow\Unit1.DFM”
I found a way to do this without moving .dfm files to the directory of .dcu files, so you can have a directory for .dcu files only one for .dcp files only and another for .bpl files only.
All you need to do is to create another directory on your good structure, as I do. The directory is called RES and in it should be placed all the resource files (.res files, not .dcr files) that are used by applications compiled using your packages (components). In the Delphi Library Path, you must include in addition to the DCU directory (you should already have) a directory named RES.
On your component (design time) do everything you want with the form (design it, put other components, etc). In the source code of the unit you replace {$R *.dfm} with {$R UnitName.dfm}. In doing so, save all and close the DPK. Now move the .dfm file (do not copy, move!) to the RES folder (the .dfm file is a resource file to the Delphi. The {$R} directive is proof!) and after that open the DPK again to understand what has changed.
First realize that you may not open the form (F12) from his unit, though no error was issued by Delphi about "DFM missing".
Now, do a Build on your package and then install it. Realized again? No errors displayed! This happened because you have indicated the location of .dfm file in the Delphi library search path (RES directory).
Done! You can use your component and dfm will be found when your component is included in an application.
Many of you can now say that this way I will not longer be able to visually edit a form in the component design time. Yes this is true, but if you think about it, why would I want to change so often a form into a component that, in practice, should only be used and slightly edited? Draw your own conclusions ;)