如何将文件复制到dll中的另一个路径?
how to copy file to another path in dll?
我正在尝试将文件从特定路径复制到另一个路径。
我定位的路径是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'}
您没有检查错误。 Win32 API 函数 CopyFile
return 是一个 Boolean
表示成功或失败。在你的情况下,我预测它会 return False
。然后根据文档(您仔细阅读了吗?)指示您调用 GetLastError
以查明调用失败的原因。我预测这将产生 5
的值,即 ERROR_ACCESS_DENIED
。这样做的原因是 CSIDL_COMMON_APPDATA
是安全的,不会被标准用户写入。您需要 运行 提升您的进程才能在那里写入。
当然,我在这里的猜测可能是错误的。在这种情况下,您仍会按照此建议找到答案。如果函数调用失败,错误代码会告诉您原因。
在我看来,这里要学习的重要一课是在调用 Win32 API 函数时进行错误检查的重要性。您必须密切关注文档,并遵循它规定的错误检查程序。
另一个教训是调试时应该简化。也许您的代码会产生无效路径。也许 GetSpecialFolder
坏了。也许您没有正确添加目录分隔符。调试的第 1 步是检查您传递给 CopyFile
的路径是否正确。是你做的吗?一旦你对此感到满意,你就可以深入挖掘。当然,如果那部分代码有效,那么我们就不需要在这里看到它。为了我们的利益,您可以替换该代码并将常量传递给 CopyFile
。
另一方面,您传递给 CopyFile
的路径可能不是您期望的那样。您应该进行一些调试以检查这些路径。你知道你传递给 CopyFile
的路径是什么吗?如果不是,您真的应该检查一下它们是否符合您的预期。
尝试更像这样的东西:
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;
我正在尝试将文件从特定路径复制到另一个路径。
我定位的路径是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'}
您没有检查错误。 Win32 API 函数 CopyFile
return 是一个 Boolean
表示成功或失败。在你的情况下,我预测它会 return False
。然后根据文档(您仔细阅读了吗?)指示您调用 GetLastError
以查明调用失败的原因。我预测这将产生 5
的值,即 ERROR_ACCESS_DENIED
。这样做的原因是 CSIDL_COMMON_APPDATA
是安全的,不会被标准用户写入。您需要 运行 提升您的进程才能在那里写入。
当然,我在这里的猜测可能是错误的。在这种情况下,您仍会按照此建议找到答案。如果函数调用失败,错误代码会告诉您原因。
在我看来,这里要学习的重要一课是在调用 Win32 API 函数时进行错误检查的重要性。您必须密切关注文档,并遵循它规定的错误检查程序。
另一个教训是调试时应该简化。也许您的代码会产生无效路径。也许 GetSpecialFolder
坏了。也许您没有正确添加目录分隔符。调试的第 1 步是检查您传递给 CopyFile
的路径是否正确。是你做的吗?一旦你对此感到满意,你就可以深入挖掘。当然,如果那部分代码有效,那么我们就不需要在这里看到它。为了我们的利益,您可以替换该代码并将常量传递给 CopyFile
。
另一方面,您传递给 CopyFile
的路径可能不是您期望的那样。您应该进行一些调试以检查这些路径。你知道你传递给 CopyFile
的路径是什么吗?如果不是,您真的应该检查一下它们是否符合您的预期。
尝试更像这样的东西:
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;