Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

File is in use message when starting to compile a project

Status
Not open for further replies.

Tom Borgmann

Programmer
Feb 9, 2017
103
DE
Today I finally lost my patience with this message thats hunting me for decades because I often forget to do a CLEAR ALL in the commandwindow right before starting a compile.

About 10-15 years ago, when I wrote our projecthook class I had tried to get rid of this message by doing a CLEAR ALL within the BeforeBuild hook. But this brought up the message that my projecthook class were in use and couldn't be cleared.
So at that time I simply removed the CLEAR ALL and accepted that I'd have to do it in the commandwindow.

Today, after the 10 millionth time of forgetting the CLEAR ALL thing I finally had enough of it.

Searching the web brought up likewise problems, even here in tektips, but the answers didn't really help. So I took the projekthook out of our sourcecode archive, where it had slept for years and experimented a bit.

Now I'm using a small loop for all project files, check their suffix==[vcx] and do an explicit CLEAR CLASSLIB on the vcx file.
Problem solved and wondering why I didn't do that all those years ago *facepalm*

So, this is all that's needed in the BeforeBuild hook:

Code:
liFlag = _VFP.ActiveProject.Files.Count
liCont = 1

DO WHILE liCont = 1
	TRY
		IF LOWER( JUSTEXT( _VFP.ActiveProject.Files( liFlag ).Name ) ) == [vcx]
			lcClasslib = _VFP.ActiveProject.Files( liFlag ).Name
			CLEAR CLASSLIB &lcClasslib
		ENDIF 
	CATCH
		liCont = 0
	ENDTRY
	liFlag = liFlag - 1
ENDDO

It is part of a bigger loop where unused bitmaps are removed from the project and therefore the loop works from bottom to top. However I cut that part out.

-Tom
 
Thanks for that, Tom. An interesting post.

My approach is more heavy-handed: I quit and restart VFP before doing a build. Not a particularly elegant approach, but simple in concept. Then again, I rarely do an explicit compile (other than as part of a build), and I only do a build when I need to generate a new executable.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Hi Mike,

well, closing VFP each time I'm doing a compile would last too long. Since the beginning of March I'm working in homeoffice and as I have 25MBit download and only 2.5MBit upload and our Sourcelevel archive has to be accessed via our datacenter, reopening a project can last up to 30 seconds and as I usually have more than 4 projects open at a time closing VFP again and again would make me a nervous wreck :)))

BTW, when talking about compiles I mean building a new app or exe ;)


-Tom
 
I take your point, Tom. I have the advantage that my development environment is entirely local - except for checking in and out of source control. For me, stopping and restarting takes about three seconds - and i don't need to do it very often.

when talking about compiles I mean building a new app or exe

I should have realised that. Although I also do a compile when I start getting "source code out of date" messages in the debugger.

Mike


__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Since the only time I ever open the project is to do builds, I just do CLOSE ALL, CLEAR ALL before that.

Tamar
 
I think under certain circumstances iterating all classlibs might clear them in an unfortunate order, and since you stop in the first exception you might not get all cleaned up.
But you know better. It might also differ on a project by project basis.

I have the habit of restarting VFP before compiling. That could be the advice you find from me searching the forum and aren't satisfied with. And it's also a habit you first need to get into.

I just see CLEAR ALL works from the command window, even when a project hook is used. It seems to skip the hook class and lib and I wonder, if that can't be used.

Challenge accepted and with a little trickery you can let the hook return to command window, suspend, cancel and restart the build with a flag set to not take this detour infinitely:

Code:
LPARAMETERS cOutputName, nBuildAction, lRebuildAll, lShowErrors, lBuildNewGuids

If Vartype(goBuild)='U'
   Show Window 'Command'
   Doevents
   Keyboard '{CTRL+F2}{CTRL+A}{DEL}CANCEL{ENTER}CLEAR ALL{ENTER}goBuild=.T.{ENTER}' PLAIN CLEAR
   Keyboard 'BUILD EXE ("'+Forceext(_vfp.ActiveProject.Name,'EXE')+'") FROM ("'+_vfp.activeproject.name+'"){ENTER}'
   Suspend
EndIf

Release goBuild

I had to use two KEYBOARD as that easily exceeds 128 characters you can send with a single KEYBOARD command.
I think you understand it, but in short when no variable goBuild is defined it suspends and cancels the build process, then does CLEAR ALL, declare a goBuild variable and restarts the build. I guess you could use the parameters of the before build to generate the correct BUILD command to repeat exactly what originally triggered the BeforeBuild, but for demo purposes I think a working B'UILD EXE is good enough.

Bye, Olaf.

Olaf Doschke Software Engineering
 
Just to clarify - this is just a problem if one edit classlibs, right?
Because I never needed to do a CLEAR ALL before building an EXE...
 
The usual case isn't editing a class. But when you ran the application in its source form, which is very recommendable for debugging and single-stepping through code.

Bye, Olaf.



Olaf Doschke Software Engineering
 
@Olaf
I like this idea with the keyboard macro. Nice :)

BTW the catch only fires in case somethings wrong with the bitmap files. As said, its just a part of a bigger loop and I didn't want to strip everything. The code might have become non-understandable.

In its own loop I wouldn't even place it in a TRY statement as the only thing that could go wrong is a clear to a non existing classlib and that's by any chance ... rare and a missing classlib would raise bigger problems anyway.


-Tom
 
The idea is a bit clumsy. It took a while to get the idea to first empty the command window (temporarily) with CTRL+A and DEL. I had halfbaked commands resulting from typing into previous lines at first.

I'll still rather restart VFP, cd into the project home and compile. It's the most reliable way for same environment during the build process.

I don't know how an image might cause trouble being loaded into memory, sounds more like you'd remove some images before compiling and that's nothing CLEAR ALL wold do. But I see how running code adds files to the PJX, it's quite good at that automatic project completion as VFP generally assumes you don't want to reference external images.

You could also prevent that by not referring to the images directly.

Bye, Olaf.



Olaf Doschke Software Engineering
 
I just treid that.

It's easy enough to fool the "detective" work VFP does to get all files used in an application into the PJX: Just define a function or method returning the image fullpath name and let the Picture property "call" that by setting it to =getimage(1), for example.

Unlike directly setting the picture property this doesn't let VFP add it to project files, though once it runs VFP knows what image file it set image.Picture to. I think this also is by intention, what happens danymically is, well, subject to change, so there is no reason to believe the fcuntion call would always return the same file path.

Not sure if that is what you want to avoid, but I think you're also aware this whole topic would ask for a more wholesome approach with meta data about images anyway. But even a small solution with just a simple dbf having imagekey, imagepath fields could allow you to specify UI images that should differ by language setting.

Bye, Olaf.

Olaf Doschke Software Engineering
 
I have my own project manager replacement and only use the PJX for the build. Originally, I had tried to use the BUILD command but found the same issue you found with Files in use. I tried to use CLEAR CLASSLIB but still found problems prior to the BUILD command (similar approach as above). Now I use the Build method of the project object. Seems it can force the release of objects held in memory and now I do not have the Files in Use problem (unless they are truly open for edit).
 
Interesting. I can not confirm that, though. Or differently said: I think I know the reason you think so.

After I prepared the situation of "file is in use" by having an instance of a class and building with the "Recompile All" option checked, that error occurs. Which, by the way, suggests that not using the recompile all option you reduce the problem to files VFP regards necessary to compile in the build process.

And indeed the Project.Build() method has the lRebuildAll parameter, which when omitted does only compile the bunch of files considered modified. When you combine that with having the IDE option set to compile before saving files, you also won't run into compiling files. Their open status doesn't matter, then, the can be built into an exe anyway.

But if you explicitly pass in .t. you get the same file in use error.

Bye, Olaf.

Olaf Doschke Software Engineering
 
I always use the Compile All setting for all my builds. I do not experience this issue anymore...
 
That's of course the best situation.
Maybe you have a secret to tell, or is it just the way it is for you?

I see, for example, that you can have an instance of a class defined in a PRG and still compile/build. Though when you edit the defining PRG VFP asks you, whether you want to remove the class from memory. So a strategy to avoid all visual classes may also work about build. Not really feasible for me. You can't just rework a given project you work for, for example. You can forget solutions that only work on the academic situation you're in full control and decide about all project details...

But this possibility to build including a loaded PRG class (or its FXP) also shows how it's more a choice and caution of VFP to be picky about this situation than it's a core technical problem. The motto simply is, when you have exclusive access to the source file that's guaranteeing nothing may cause inconsistencies of compiling the content you currently read from the file(s).

There also are ways of clean programming and defenses against losing conrol, like but I rarely maintain just my own code. And to be honest, I have not made use of Christof's base idea as I don't have these release problems, zombie objects, dangling object references, with my programming. I have been there, had that, but you learn, of course.

Plus, it's simply the easiest to have defined state of both VFP and the project when building after a restart.

Nevertheless, it's fun to see how you can outsmart VFP to still force it to clear all, for example. Or see what really is blocking a build.
One thing to know is having the debugger opened before build, as that adds detailed information about build steps in the debugout window. In this case of "file in use" the error already clearly tells you which file can't be (re)compiled, but in other cases that'll tell you. The last message might be about the last succeeding part and then you can infer what next file is problematic.

Bye, Olaf.

Olaf Doschke Software Engineering
 
On your use of the Debug Window open... I instead use SET DEBUGOUT TO CompileLog.txt Now when the compile is being performed it is outputting to the text file. After build I reset via SET DEBUG OUT. Now I use the text file as a compile log. This build process is handled in my custom project manager with a build form.

2020-08-07_10-35-59_xzth7p.jpg
 
Well, I did actually get the file in use error when using project.build() with recompile all and not failing without recompile all. But preparing a situation you know fails of course is not necessarily a real-world case.

Comments also of Tamar point out using a project as late as possible, so there might be a bit related to the project manager? I can't relate that to experiences of such "file in use" problems, as open files usually are open because, well, they are used/instanced classes. I also remember some strange cases like mentioning a cursor alias. IIRC there was something corrupt in the pjx strucutre.

There is the tendency of the project manager to keep a DBC open, but that's a separate issue and, well, rarely a problem. I tend to keep dbc in a separate project as I want to debug with shared use, too. Though it's also advisable to have them in the PJX so calls to stored procs are found and thus understood by the compiler.

At least I don't see you're losing any essential capability not using the project manager itself, the project class has the projecthook, projecthookclass and projecthookclasslib, so that's also not part of just the interface we know as the project manager, you can make any kind of setting, if you fail to find it by shortly using the project manager anyway, things like settings about olepublic classes will be peristed in the pjx anyway, so that's also no hurdle.

I might give it a try to do without the project manager itself in developing and debugging and then use some build meachnisms, but I doubt I'll ever have the time to build up a hole project manager replacement. Is your's publicly available? Or is it a too private code base?

Bye, Olaf.



Olaf Doschke Software Engineering
 
Thanks, Greg,

releaswenotes.rtf was missing and some gkklistview.bmo reference, which likely meant gkplistview.bmp
And then I had to uncomment an API declaration of DestroyIcon to get it working.

In the end I got to compile the app and start it to load the same pjx and prepare the same instance in use situation, and then you get display the same build error displayed with your error display form:
builderror_otp69z.jpg


It would be a wonder you could do better. I think this is very inherent. Once some instance of a class is loaded, VFP refuses to compile.

Aside of that: You always call with recompile all set, I do like the option to turn that off, especially once I initially managed a full build I like to have the ability of fast builds only compiling changes.
Anyway, I think I'll need to dig a bit in this, it's quite a comprehensive project.

Thanks a bunch.

Bye, Olaf.

Olaf Doschke Software Engineering
 
I found the loop you go through. Indeed you implemented the same idea, iterate project files, especially PRGs and VCXs and try to CLEAR CLASS and/or CLEAR CLASSLIB. But when there are actual instances that also finally has to give up.

This precheck could actually use AINSTANCES to at least find instances created by CREATEOBJECT or NEWOJECT and remove and release them. But as the help on AINSTANCE says, this is limited to such instances. And in the end the one command that would release them all is CLEAR ALL.

I just observe another specialty, you extract a class name from PRG source code by finding the name between DEFINE CLASS and AS, you only look for one per PRG. It's your choice, of course, but that also can differ in projects you get to maintain and don't get to refactor in a way every class is in a separate PRG.

You don't need to program the most general case, in the normal situation everything is unused and no instance in memory. No reason to overcomplicate things. Especially no reason when the simpler solution could be CLEAR ALL. It just doesn't work as you can't specify your own current hook or project manager as exception.

So CLEAR ALL only works well from the command window and everywhere else you need to be more detailed. It just works so fine from the command windows, it doesn't complain to not be able to clear the current project hook, while it does error when executed from within...

OK, and that'S going back to where we started. You can iterate through project files and CLEAR CLASS/CLEAR CLASSLIB, okay. Classlibs won't unload before not all classes inside them unloaded, that could be handled, too. But then you won't necessarily get hands on all instances of objects to release. Especially when I think of frameworks having some things loaded you'd not want to clear that. That's also where CLEAR ALL is a too simple solution.

Bye, Olaf.

Olaf Doschke Software Engineering
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top