Access Denied when copying DLL files for particular client - delphi

We have a small utility which updates our software on client computers by simply copying/replacing certain files. The files consist of both EXE's and DLL's. All works fine, except for one client of ours. They have an Active Directory domain (as many of our clients do) but on every single computer, the DLL files fail to copy with error code 5 (access denied). Even when the application is run as administrator - while logged into the computer as administrator. Happens on all of their XP, Vista, and 7 machines. EXE files are copied/replaced fine, but not DLL files. If the DLL does not exist, it copies fine. But if it needs to replace, it fails.
These files are copied using the API call:
function CopyFile(lpExistingFileName, lpNewFileName: PWideChar; bFailIfExists: BOOL): BOOL; stdcall;
The source is a temp folder automatically created by a self-extracting package, and the destination is wherever our software is installed (identified by a registry key of ours). The destination is most commonly a directory in the C: root, but also happens in the Program Files (x86) and anywhere else on their computers. Their IT person insists that they have no special settings configured in their domain to block this. This is our only client with this problem, and happens on all 20+ of their computers. However, when I manually copy the files through Windows, the files copy/replace just fine. I checked the attributes of these files, and they are not hidden or read-only.
What else do I need to do to ensure proper access? Since running as administrator doesn't do the trick?

Trace your update utility with procMon. You should see ACCESS_DENIED errors. Analyse them. Keep an eye on Impersonation. Also ask them if they any Software IPS, "Angry" Antivirus, or if they have configured Software Restirction/AppLocker. The last ones may not be really connected with your issue, but give them a try.
Unlikely to be a problem, but if your Utility is 32 bit and don't have manifest, it may be silently redirected by the OS (Vista and later).
UPDATE:
If the program is too old (i.e. does not comply MS recommendations for software/data locations) MS ACT (Microsoft Application Compatibility Toolkit (ACT)) can be your friend.

Related

BDE, Windows 7 and UAC

I have a very old application written in delphi 5 running in some customers which uses the BDE. Now some users with Windows Vista and 7, had experimented some problems with the multiuser access. i' think which these problems are related to the location of the net.and .lck files. so the question is which is the proper way to confgure the BDE under Windows Vista and 7 to avoid permissions and UAC conflicts?
In addition to the above answer, you'll want to make sure that the .net and .lck files are located in a user-specific directory under Windows 7, specifically:
C:\Users\{User Name}\AppData\Local\{Your Company Name}\{Your Application Name}
Those are the only folders that the current user will always have complete control over.
You can get this folder by using this code:
CSIDL_LOCAL_APPDATA = $001C;
function GetAppDataDirectory: AnsiString;
var
TempBuffer: array[0..MAX_PATH] of AnsiChar;
ResultLength: Integer;
begin
FillChar(TempBuffer,((MAX_PATH+1)*SizeOf(AnsiChar)),0);
ShlObj.SHGetSpecialFolderPathA(0,#TempBuffer,CSIDL_LOCAL_APPDATA,False);
ResultLength:=StrLen(pAnsiChar(#TempBuffer));
SetLength(Result,ResultLength);
Move(TempBuffer[0],pAnsiChar(Result)^,(ResultLength*SizeOf(AnsiChar)));
end;
and then appending {Your Company Name} and {Your Application Name} to the value returned. You'll need to include the ShlObj unit.
One such thing I remember is to configure the Session to put that kind of files on folders where a normal user have write-privileges.
From what I remember, the properties
Session.PrivateDir
Session.NetFileDir
Are the relevant ones.
The correct location will depend on concurrent access, the database you're connecting to, data location –in case of paradox or dbf's– and if you use cached updates or not.
I maintain an application written originally in D4, now compiled with D2007 when rarely needed and it works well on vista+ using this with it's particular configuration and needs (no paradox/dbf's).
If you don't want to work around the security bugs in a default install of the BDE (as other answers mention - granting permissions that the BDE installer forgot to), you can just run your application as an administrator.
You have a few options:
Tell the user to right-click and select Run As Administrator every time.
Go to the program's Compatibility tab, and check Run this program as an administrator (which has the same effect as 1)
Go to the program's Compatibility tab, and Run this program in compatibility mode for Windows XP (which has the same effect as 2)
Create a manifest MyApp.exe.manifest and include the requestedExecutionLevel of requireAdministrator (which has the same effect as 3)
In other words: Your application, as it stands right now, requires administrative access to run - so just run it as an administrator.
On the other hand you can make a few simple changes and your application will no longer need to run as an administrator; you've made the world a better place for all humanity!

How do I move Delphi XE packages and settings to another user?

We have set up a new (template) development machine with among other things Delphi XE including a large number of third-party and internal packages, and intend to make a number of clones of this computer for the developers in our team. Note that we are not trying to bypass licensing, we (re-) activate/register Windows, Office, Delphi XE etc. after cloning. My problem is that when I am logged on (as myself) to the clone that will be my own machine, Delphi shows none of the packages we installed (i.e. on the the template machine, using a local Administrator account). Is there anyway I can find and copy/move the Delphi settings from the local administrator to my own user account, so that packages and other settings are the same as we set them up on the template machine before cloning?
I'd try to export the relevant registry keys - something like HKEY_CURRENT_USER\Software\Borland\BDS\5.0\Known Packages for D2007 (probably ..\Embarcadero\.. for XE). You can (carefully!) edit the *.reg file and re-import it.

How to keep Delphi App IDE target folder in track with installer default between 32 and 64-bit

It's easiest when developing in the IDE to work with a Application target folder in the default location into which it will be installed e.g:
"c:\Program Files\MyAppFolder"
As a result, I have "c:\Program Files\MyAppFolder" coded into the Delphi project's 'Output directory' and I can prepare for development by running my installer (Innosetup) which populates that folder with supporting data files etc.
Now I'm moving between Windows7 64 and Windows 7 32 and my installer wants to put it's (32-bit) app into "c:\Program Files (x86)", so I need to point my IDE output at:
"c:\Program Files (86)\MyAppFolder"
This would be a change required in each project. Is there a predefined variable that I can use or some other method that would allow me to move between platforms with a 32-bit app?
It's easiest when developing in the IDE to work with a Application target folder in the default location into which it will be installed e.g
Your application is supposed to work wherever the user installs it, and you obviously know that since you call the location "the default location". Since the app should work wherever you install it, it shouldn't matter where you're developing it.
Your Program Files choice is bad for a number of reasons:
If you make the mistake of hard-coding a path in your application, you'll only learn about it when a client installs the application somewhere else.
Doing your development in the Program Files folder requires you to work with UAC disabled: your client's are going to have UAC enabled, so you're not actually working in an environment that looks like the environment where the app is going to be used.
You can't test application's installer: since you already have files in the "default location".
Program Files goes through two folder redirectors: The 64 bit virtualization that makes 32 bit application read from Program Files x86 when they say Program Files and the UAC virtualization that redirects write access to Program Files folders to folders in one's UserData directory.
It's my honest opinion that it's better to develop into an other directory, outside the Program Files minefield. For my own development I'm taking this to the next level: The same applications is developed in different folders on different computers. Example: I've got my app checked out in C:\Appname, my colleague has it in D:\SomeFolder\AppName
You can use environment variables when specifying paths in Delphi.
Set output directory to $(ProgramFiles)\MyAppFolder.
$(ProgramFiles) in Win64 points to Program Files x(86) for 32-bit applications. Delphi is 32-bit so that will work for you.
This wouldn't work for me because I have UAC enabled. I'd just stick it somewhere outside the program files folders.

are delphi 2010 programs capable of tackling vista/win7 UAC by default

if you compile a program in D2010 a manifest .res file is automatically generated. is it included in your program by default? or you have to include it yourself?if yes what level of privilage is given to you? my program modifies a registery key would it be able to do so with out any modifications to .res file?if no what modifications i need to do?
a side question: is there a component/expert(prefably free) that can generate/include .res file in my delphi 7 and delphi 2007 projects automatically just like delphi 2010?
edit: forgot to mention i do not have win7 or vista nor have i ever used them
edit2:i have included a manifest file just in case following this tutorial but the tutorial only talks about windows vista and not 7 would the .xml(manifest) file in this tutorial make my app capable of dealing with win7 UAC too
edit3 if i include my own manifest file and delphi is including it by default as well that will make 2 manifest files(1 with admin previlages and 2nd without) would this cause any problems/unpredictable behaviour
The manifest generated by delphi gives your process the lowest privileges (that is the default by the way).
You have to modify the manifest file in order for it to ASK for permission to be run under administrative rights (Called elevation).
Your application with the standard privileges should read/write to HKEY_CURRENT_USER without elevation.
Accessing %programfiles% and HKEY_LOCAL_MACHINE requires elevation. (Not so sure about the other registry hives)
This is a PDF that will help you A LOT with what you're up to.
http://pascalfonteneau.developpez.com/articles/delphi/vista/uac/VistaUACandDelphi.pdf

External exception C0000006

I've wrote some program in Delphi and when I am running it from a disk on key. At some point I'm required to unplug the disk on key while the application is running. If I do this on a computer with at least 1gb of ram everything is okay. When I do this on a machine with 512mb I get an external exception C0000006. If I'm not mistaken, this is because the OS is trying to read the next line of code but cannot find the resource for it (meaning, the application wasn't loaded to the ram) which is absurd because it's a 500kb application.
How can I solve this? or at least handle this exception in a more elegant way? (Since I can't catch it since it's an external exception).
Oh, and my Delphi application is a console application under windows xp.
What you need to do is tell windows to load your whole program into memory, rather than allowing it to demand load pages when it needs to. I have done this successfully for applications running off a CD. I don't have the code with me right now, but I recall that I found hints on how to do it in source for the fantastic open source install program Inno Setup.
Edit: Actually, after doing a little research, you can use a Delphi compiler directive to tell windows to load the full executable. This works if you have Delphi > 2006. This will have the effect that you will never get the external exception.
Put this line in your applications project file:
{$SetPEFlags IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP}
This tells windows that the executable is going to be used from removable media, so load the the executable into memory (or the swap file). Then you don't need to worry about things like copying the file to the machine first, etc.
Edit 2: I currently have access to Delphi 7 and I can confirm, as noted by others, that this also works with Delphi 7 (and likely Delphi 6) with the following code:
const
IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP = $0400;
{$SetPEFlags IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP}
For Delphi < 6, you can go down the path of forcing the executable to be paged in. There is an example of how to do it in C++ here (unless you find a way to modify the PE header flags after link time, which looks to be complicated)
N#
That's EXCEPTION_IN_PAGE_ERROR. It means that the OS loader failed to page in some data required for the application to run, probably due to an I/O error or other error. Since you're removing the disk, that would make sense.
Perhaps the working set (the set of often-used memory pages) for the application was allowed to grow large enough on 1GB machines such that recourse to the disk to reload pages wasn't necessary, but that wasn't the case on 512MB machines?
I would suggest trying to copy the executable to a temporary location and starting it from there, possibly with delayed deletion; or use some other mechanism to guarantee on-disk backing for all memory pages touched by the application in normal use, and prevent this error in cases of memory pressure, where the OS will trim the working set of running processes.
Like #Barry, I would recommend checking the drive type of the volume that your executable is running from; if it is a removeable drive (and missing a "already in temp" command line parameter) copy the executable (and any of its dependencies) to the user's %TEMP% folder and then re-launch it from there with an extra command line parameter to indicate "already in temp".
Create each temporary file using File.Create(targetPath, bufferSize, FileOptions.DeleteOnClose) (or one of the FileStream constructors that takes a FileOptions parameter), but make sure to hang onto the returned File instance until after the second copy is launched (e.g. in a List<File>).
Copy the contents of each file.
Launch the executable from the temp folder.
Call Close() on each of the File instances saved above.
Exit the original executable.
This way the files get closed regardless of which process finishes first, and the source volume can be removed earlier.
The solution
uses Windows;
{$SetPEFlags IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP or IMAGE_FILE_NET_RUN_FROM_SWAP}
is available for Delphi since version 6.
There's a Delphi working version of RunImageLocally from MSJ which forces the executable/dll to be paged in. This can prevent C0000006 errors when running from network or removable media...
Check it out at https://github.com/jrsoftware/issrc/blob/master/Projects/SetupLdr.dpr
This exception C0000006 also often occurs if your software is run from a network drive. To prevent that problem you can combine the flag
{$SetPEFlags IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP}
with the following flag:
IMAGE_FILE_NET_RUN_FROM_SWAP = $0800;
{$SetPEFlags $0C00}

Resources