我正在尝试将文件从特定路径复制到另一个路径。
我定位的路径是CSIDL_COMMON_APPDATA
,这是程序数据,所以我尝试了:
CopyFile(PChar(AppFolder +'\needed.dll'), PChar(anotherfolder+'\needed.dll'), False);
但它不会将任何内容复制到目标路径。
所以我应该测试EXE应用程序中的代码并正常复制文件。可能是什么问题呢?为什么我无法从DLL复制文件?
这是我的Appfolder
路径:
function GetSpecialFolder(const CSIDL : integer) : String;
var
RecPath : PWideChar;
begin
RecPath := StrAlloc(MAX_PATH);
try
FillChar(RecPath^,MAX_PATH,0);
if SHGetSpecialFolderPath(0,RecPath,CSIDL,false) then begin
Result := RecPath;
end else Result := '';
finally
StrDispose(RecPath);
end;
end;
function AnotherFolder: string;
begin
if IsWindowsVistaOrGreater then
begin
Result := GetSpecialFolder(CSIDL_COMMON_APPDATA)+'\applocation';
end;
end;
function AppFolder: string;
begin
if IsWindowsVistaOrGreater then
begin
Result := GetSpecialFolder(CSIDL_INTERNET_CACHE)+'\Low\applocation';
end else
Result := GetSpecialFolder(CSIDL_COMMON_APPDATA)+'\application';
//Result := ExtractFilePath(Application.ExeName);
end;
添加实际代码
// dll form
function GetSpecialFolder(const CSIDL: integer): String;
var
RecPath: PWideChar;
begin
RecPath := StrAlloc(MAX_PATH);
try
FillChar(RecPath^, MAX_PATH, 0);
if SHGetSpecialFolderPath(0, RecPath, CSIDL, false) then
begin
Result := RecPath;
end
else
Result := '';
finally
StrDispose(RecPath);
end;
end;
function AnotherFolder: string;
begin
// Vista check removed
Result := GetSpecialFolder(CSIDL_COMMON_APPDATA) + '\applocation';
end;
function AppFolder: string;
begin
if IsWindowsVistaOrGreater then
begin
Result := GetSpecialFolder(CSIDL_INTERNET_CACHE) + '\Low\applocation';
end
else
Result := GetSpecialFolder(CSIDL_COMMON_APPDATA) + '\application';
// Result := ExtractFilePath(Application.ExeName);
end;
procedure Tform1.FormShow(Sender: TObject);
begin
if IsWindowsVistaOrGreater then
begin
CopyFile(PChar(AppFolder + '\needed.dll'), PChar(AnotherFolder + '\needed.dll'), false);
memo1.Lines.Add('Value : ' + IntTostr(GetLastError()));
end;
end;
我的dll只有一个表单,当它显示它时会显示从一个位置到另一个位置的副本文件。
清单文件
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
type="win32"
name="DelphiApplication"
version="1.0.0.0"
processorArchitecture="*"/>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
publicKeyToken="6595b64144ccf1df"
language="*"
processorArchitecture="*"/>
</dependentAssembly>
</dependency>
</assembly>
项目dll源
{$R apploadform.res' apploadform.rc'}
答案 0 :(得分:2)
您没有检查错误。 Win32 API函数CopyFile
返回Boolean
,表示成功或失败。在你的情况下,我预测它会返回False
。然后由文档指导(你仔细阅读了吗?)来调用GetLastError
来找出调用失败的原因。我预测这将产生5
的值ERROR_ACCESS_DENIED
。这样做的原因是CSIDL_COMMON_APPDATA
可以防止标准用户的写入。您需要提升您的流程才能在那里写作。
当然,我在这里的猜测可能是错的。在这种情况下,您仍然可以通过遵循此建议获得答案。如果函数调用失败,错误代码将为您提供原因。
在我看来,这里要学习的重要一课是在调用Win32 API函数时进行错误检查的重要性。您必须密切关注文档,并遵循它规定的错误检查程序。
另一个教训是,在调试时你应该简化。也许您的代码会生成无效路径。也许GetSpecialFolder
被打破了。也许您无法正确添加目录分隔符。调试的第1步是检查传递给CopyFile
的路径是否正确。是你做的吗?一旦你对此感到满意,那么你可以深入挖掘。当然,如果代码的那部分工作,那么我们不需要在这里看到它。为了我们的利益,您可以替换该代码并将常量传递给CopyFile
。
另一方面,传递给CopyFile
的路径可能不是您期望的路径。你应该做一些调试来检查这些路径。您知道传递给CopyFile
的路径吗?如果没有,你真的应该检查它们是否符合你的期望。
答案 1 :(得分:1)
尝试更像这样的东西:
uses
..., SysUtils, Windows, ShlObj;
function GetSpecialFolder(const iFolder: Integer; OwnerWnd: HWND = 0): String;
var
RecPath: array[0..MAX_PATH] of Char;
begin
if SHGetSpecialFolderPath(OwnerWnd, RecPath, iFolder, False) then
Result := IncludeTrailingPathDelimiter(RecPath)
else
Result := '';
end;
function AnotherFolder(OwnerWnd: HWND = 0): string;
begin
Result := GetSpecialFolder(CSIDL_COMMON_APPDATA, OwnerWnd) + 'applocation' + PathDelim;
end;
function AppFolder(OwnerWnd: HWND = 0): string;
begin
Result := GetSpecialFolder(CSIDL_COMMON_APPDATA, OwnerWnd) + 'application' + PathDelim;
end;
procedure TForm1.FormShow(Sender: TObject);
var
Source, Target: String;
ErrCode: DWORD;
begin
Source := AppFolder(Handle) + 'needed.dll';
Target := AnotherFolder(Handle) + 'needed.dll';
Memo1.Lines.Add('Source: ' + Source);
Memo1.Lines.Add('Target: ' + Target);
if CopyFile(PChar(Source), PChar(Target), false) then
begin
Memo1.Lines.Add('Copied OK');
end else
begin
ErrCode := GetLastError;
Memo1.Lines.Add('Unable to copy! Error ' + IntTostr(ErrCode) + '. ' + SysErrorMessage(ErrCode));
end;
end;