如何将文件复制到DLL中的另一个路径?

时间:2016-05-11 16:12:43

标签: delphi delphi-xe7

我正在尝试将文件从特定路径复制到另一个路径。

我定位的路径是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'}

2 个答案:

答案 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;