-1

我让Delphi XE2 项目在 Windows 注册表中写入一些值。我正在尝试在 Delphi 环境中运行 RegEdit。我尝试了以下代码:

procedure TMainForm.BitBtn01Click(Sender: TObject);
  begin
    ShellExecute(handle,'','C:\WINDOWS\regedit.exe',
    '[HKEY_CLASSES_ROOT\CLSID\{00000000-0000-0000-0000-000000000001}\Subnode 01]
    @=hex(2):25,00,53,00,79,00,73,00,74,00,65,00,6d,00,52,00,6f,00,6f,\
      00,74,00,25,00,5c,00,53,00,79,00,73,00,74,00,65,00,6d,00,33,00,32,00,5c,00,\
      41,00,70,00,70,00,6c,00,69,00,63,00,61,00,74,00,69,00,6f,00,6e,00,20,00,57,\
      00,69,00,7a,00,61,00,72,00,64,00,20,00,30,00,31,00,2e,00,64,00,6c,00,6c,00,\
      00,00'
      ,nil,SW_SHOW);
  end;

但它没有编译。我的要求是将子节点 01 的可扩展字符串值写入“%SystemRoot%\System32\Application Wizard 01.dll”。我的项目的活动平台是 32 位,但也添加了 64 位,我的应用程序将以管理员身份在两个平台下运行。

我认为我的问题可以通过调用Wow64DisableWow64FsRedirection FunctionWow64EnableWow64FsRedirection Function来解决。但尚不清楚何时调用它。这是我的项目的另一个细节。

4

3 回答 3

5

Don't try to fail the redirection, just use this force to make your life easier.

If you put a DLL file to the global Windows store, you have to put it into the System32 folder. But this folder differs depending on the OS platform and the platform supported by your application.

x32 OS / x32 app -> %SystemRoot%\System32
x64 OS / x64 app -> %SystemRoot%\System32
x64 OS / x32 app -> %SystemRoot%\SysWow64

For your convenience Windows has an automated redirection also when writing to the registry from a x32 app on a x64 OS so you don't have to put an extra handling for this.

As designed you write with this code always the right path to your DLL file.

const
  c_RegKey = 'CLSID\{00000000-0000-0000-0000-000000000001}\Subnode 01';
  c_DllFile = '%systemroot%\system32\Understanding3264_lib.dll';

var
  LReg : TRegistry;
begin
  LReg := TRegistry.Create;
  try
    LReg.RootKey := HKEY_CLASSES_ROOT;

    if LReg.OpenKey( c_RegKey, True )
    then
      try

        // we write as REG_EXPAND_SZ to flag that this contain environment variables
        // that has to be expanded

        LReg.WriteExpandString( '', c_DllFile );

      finally
        LReg.CloseKey;
      end
    else
      raise Exception.CreateFmt( 'Not allowed to create the registry key HKCR\%s', [c_DllFile] );
  finally
    LReg.Free;
  end;
end;

One codebase for all three cases without any compiler switches or OS platform checking.

But you have to take care on installation, to put the files in the right place.

Here is an example script for Inno Setup which handles both platforms. On x32 OS it will only install the x32 app, on x64 OS it will install both (x32/x64) apps.

; Extended sample from
; -- 64BitTwoArch.iss --
; Demonstrates how to install a program built for two different
; architectures (x86 and x64) using a single installer.

; SEE THE DOCUMENTATION FOR DETAILS ON CREATING .ISS SCRIPT FILES!

[Setup]
AppName=Understanding3264
AppVersion=1.0
AppId={{BD2CF2C0-B8A4-40C9-8161-917544CB2E5C}
DefaultDirName={pf}\Understanding3264
DefaultGroupName=Understanding3264
UninstallDisplayIcon={app}\Understanding3264.exe
Compression=lzma2
SolidCompression=yes
OutputDir=Setup
OutputBaseFilename=Understanding3264_Setup
; "ArchitecturesInstallIn64BitMode=x64" requests that the install be
; done in "64-bit mode" on x64, meaning it should use the native
; 64-bit Program Files directory and the 64-bit view of the registry.
; On all other architectures it will install in "32-bit mode".
ArchitecturesInstallIn64BitMode=x64
; Note: We don't set ProcessorsAllowed because we want this
; installation to run on all architectures (including Itanium,
; since it's capable of running 32-bit code too).

[Files]

; 32bit Platform only 32bit Application

Source: ".\Win32\Release\Understanding3264.exe"; DestDir: "{app}"; Check: not Is64BitInstallMode
Source: ".\Win32\Release\Understanding3264_lib.dll"; DestDir: "{sys}"; Check: not Is64BitInstallMode

; 64bit Platforms install 64bit and 32bit Application

Source: ".\Win64\Release\Understanding3264.exe"; DestDir: "{app}"; Check: Is64BitInstallMode
Source: ".\Win64\Release\Understanding3264_lib.dll"; DestDir: "{sys}"; Check: Is64BitInstallMode
Source: ".\Win32\Release\Understanding3264.exe"; DestDir: "{app}\x32"; Check: Is64BitInstallMode
Source: ".\Win32\Release\Understanding3264_lib.dll"; DestDir: "{syswow64}"; Check: Is64BitInstallMode

[Icons]
Name: "{group}\Understanding3264"; Filename: "{app}\Understanding3264.exe"
; link to x32 app when on x64 OS
Name: "{group}\Understanding3264 (32bit)"; Filename: "{app}\x32\Understanding3264.exe"; Check: Is64BitInstallMode
Name: "{group}\{cm:UninstallProgram, Understanding3264}"; Filename: "{uninstallexe}"

[Registry]
; clean the registry on uninstall
Root: "HKCR"; Subkey: "CLSID\{{00000000-0000-0000-0000-000000000001}"; Flags: dontcreatekey uninsdeletekey
; if x64 OS we also have to take care on the registry key created by the x32 application
Root: "HKCR32"; Subkey: "CLSID\{{00000000-0000-0000-0000-000000000001}"; Flags: dontcreatekey uninsdeletekey; Check: Is64BitInstallMode

and this is the sample application (one codebase for both platforms). There is one compiler switch, to set the form caption. That's all.

unit Main_ViewU;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

const
  c_RegKey = 'CLSID\{00000000-0000-0000-0000-000000000001}\Subnode 01';

  // Because Windows does a magic redirection, we can use the same string
  // for both platforms x32/x64
  // x32 app on x32 OS -> %systemroot%\system32\Understanding3264_lib.dll
  // x64 app on x64 OS -> %systemroot%\system32\Understanding3264_lib.dll
  // x32 app on x64 OS -> %systemroot%\SysWow64\Understanding3264_lib.dll

  c_DllFile = '%systemroot%\system32\Understanding3264_lib.dll';

type
  TGetInfoFunc = function : WideString; stdcall;

type
  TMain_View = class( TForm )
    GetInfo_Button : TButton;
    RegisterLib_Button : TButton;
    DllFileName_Label : TLabel;
    procedure FormCreate( Sender : TObject );
    procedure GetInfo_ButtonClick( Sender : TObject );
    procedure RegisterLib_ButtonClick( Sender : TObject );
  private

  public

  end;

var
  Main_View : TMain_View;

implementation

{$R *.dfm}

uses
  Registry;

function ExpandEnvironmentStringsStr( const AStr : string ) : string;
begin
  SetLength( Result, ExpandEnvironmentStrings( PChar( AStr ), nil, 0 ) );
  ExpandEnvironmentStrings( PChar( AStr ), PChar( Result ), Length( Result ) );
end;

procedure TMain_View.GetInfo_ButtonClick( Sender : TObject );
var
  LReg :         TRegistry;
  LRegDataInfo : TRegDataInfo;
  LDllFileName : string;
  LLib :         HMODULE;
  LFunc :        TGetInfoFunc;
  LStr :         string;
begin
  LReg := TRegistry.Create;
  try
    LReg.RootKey := HKEY_CLASSES_ROOT;

    if LReg.OpenKeyReadOnly( c_RegKey )
    then
      if LReg.GetDataInfo( '', LRegDataInfo )
      then
        begin
          case LRegDataInfo.RegData of
            rdString : // just read the string
              LDllFileName := LReg.ReadString( '' );
            rdExpandString : // string needs to be expanded
              LDllFileName := ExpandEnvironmentStringsStr( LReg.ReadString( '' ) );
          end;
        end;

  finally
    LReg.Free;
  end;

  // just for information
  DllFileName_Label.Caption := LDllFileName;

  // no info from registry
  if LDllFileName = ''
  then
    raise Exception.Create( 'Not registered' );

  // load the library
  LLib := LoadLibrary( PChar( LDllFileName ) );
  if LLib <> 0
  then
    try
      @LFunc := GetProcAddress( LLib, 'GetInfo' );
      LStr   := LFunc;
    finally
      FreeLibrary( LLib );
    end
  else
    raise Exception.CreateFmt( 'Dll-File "%s" not found!', [LDllFileName] );

  // show the information
  ShowMessage( LStr );
end;

procedure TMain_View.RegisterLib_ButtonClick( Sender : TObject );
var
  LReg : TRegistry;
begin
  LReg := TRegistry.Create;
  try
    LReg.RootKey := HKEY_CLASSES_ROOT;

    if LReg.OpenKey( c_RegKey, True )
    then
      try

        // we write as REG_EXPAND_SZ to flag that this contain environment variables
        // that has to be expanded

        LReg.WriteExpandString( '', c_DllFile );

      finally
        LReg.CloseKey;
      end
    else
      raise Exception.CreateFmt( 'Not allowed to create the registry key HKCR\%s', [c_DllFile] );
  finally
    LReg.Free;
  end;
end;

procedure TMain_View.FormCreate( Sender : TObject );
begin
  Caption := Application.Title{$IFDEF Win64} + ' (x64)'{$ELSE} + ' (x32)'{$ENDIF};
end;

end.
于 2013-05-06T14:14:53.790 回答
4

试试这样:

Uses
  ShellApi;

procedure TForm1.Button1Click(Sender: TObject);
  begin
    ShellExecute(handle,'','C:\WINDOWS\regedit.exe',
    '[HKEY_CLASSES_ROOT\CLSID\{00000000-0000-0000-0000-000000000001}\Subnode 01]'+
    '@=hex(2):25,00,53,00,79,00,73,00,74,00,65,00,6d,00,52,00,6f,00,6f,'+
    '00,74,00,25,00,5c,00,53,00,79,00,73,00,74,00,65,00,6d,00,33,00,32,00,5c,00,'+
    '41,00,70,00,70,00,6c,00,69,00,63,00,61,00,74,00,69,00,6f,00,6e,00,20,00,57,'+
    '00,69,00,7a,00,61,00,72,00,64,00,20,00,30,00,31,00,2e,00,64,00,6c,00,6c,00,'+
    '00,00', nil, SW_SHOW);
  end;
于 2013-05-06T10:09:19.873 回答
3

您没有使用有效的字符串。在字符串中进行换行时,您需要将其关闭并用 + 号连接它。

例如:

AFunction(..., 
'text1' +
'text2' +
'text3', ...);

或将整个字符串参数写在一行中。

于 2013-05-06T10:11:58.707 回答