いつもお世話になります。表記のことについて質問させてください。
現在、テキストファイルを作成し、RCファイルに以下のように記述して
リソースとして実行ファイルに登録しています。
MyText TEXT "C:\Users\Owner\Desktop\1.txt"
この中には、当然ながら文字列が記録されているのですが、この文字列を
任意のものに変更したいのです。どのようにすればよいのでしょうか。
アイコンの書き換え方法や、読み出しの方法はいろいろと資料が出てきた
のですが、文字列の変更方法についてはよく分かりませんでした。
どうぞよろしくお願いいたします。
---------------------------------------------------------------
↓こんな感じで読んで、若干プログラムの動作を変えたいと思っています。
外部ファイル等にはあまり保存したくない情報を埋め込む予定です。
コンパイラが自由に使える環境とは限らないので、実行ファイルそのものを
書き換えできるとすごく助かります。
procedure TForm1.Button1Click(Sender: TObject);
var
RS:TResourceStream;
begin
RS := TResourceStream.Create(hInstance,'MyText','TEXT');
try
Memo1.Lines.LoadFromStream(RS);
finally
RS.Free;
end;
end;
正攻法は私が知るかぎり無いです。
トリッキーな方法で実現させた事があったので、もう一度書いて見ました。
要は、リソースを変更した自分自身を作成して、元の自分は削除してしまうというプログラムです。今回はテキストにしていますが、Streamでまとめてますので、改変は楽だと思います。
アイディアは面白いですが、これを配布するのは相当チャレンジャーだと思います。
リソースは当然サイズ固定ですので、想定されるデータの最大値を予め確保して、
書き込み位置はリソースデータの相同性から判別しています。
(サイズが小さいと失敗する恐れあり)
コンパイルの回数が少なければ、決め打ちの方が良いと思います。
当方XE2なのでusesは適宜変更してください。
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, UnitSpy;
type
TForm1 = class(TForm)
Memo1: TMemo;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form1: TForm1;
SpyHandle:HWND;
implementation
{$R *.dfm}
{$R mydata.res}
//mydata.res
//
//DATA BINARY "DATA.DAT"
//
procedure TForm1.Button1Click(Sender: TObject);
var
aMS:TMemoryStream;
begin
//リソース作成用
aMS:=TMemoryStream.Create;
SetStreamText(TStream(aMS),'初期設定');
aMS.Size:=ResSize;
aMS.SaveToFile('data.dat');
aMS.Free;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
var
aDataStream:TMemoryStream;
aMS:TMemoryStream;
begin
aDataStream:=TMemoryStream.Create;
GetDataResource(aDataStream);
aMS:=TMemoryStream.Create;
SetStreamText(TStream(aMS),Memo1.Text);
aMS.Size:=ResSize;
aMS.Position:=0;
WriteCode(Application.ExeName,
Application.ExeName + '_',
aDataStream, aMS);
Suicide(Application.ExeName, ExtractFileName(Application.ExeName) + '_');
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Memo1.Text := GetResText;
end;
end.
//--------------------------------------------------------
unit UnitSpy;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes;
const
ResSize = 1000;
function GetStreamText(var aStream:TStream):string;
procedure SetStreamText(var aStream:TStream; aText:string);
function FindResDataInMS(aMS1,aMS2:TMemoryStream):Integer;
procedure WriteCode(aPath,aNewPath:string; aOriginalData,aData:TMemoryStream);
function GetResText:string;
procedure GetDataResource(var aMS:TMemoryStream);
procedure Suicide(aAppPath,aCopyName:string);
implementation
function GetStreamText(var aStream:TStream):string;
var
i:Integer;
begin
aStream.Read(i,SizeOf(i));
SetLength(Result,i);
aStream.Read(Result[1],i*SizeOf(Char));
end;
procedure SetStreamText(var aStream:TStream; aText:string);
var
i:Integer;
begin
i:=Length(aText);
aStream.Write(i,SizeOf(i));
aStream.Write(aText[1],i*SizeOf(Char));
end;
procedure GetDataResource(var aMS:TMemoryStream);
var
aRS:TResourceStream;
begin
aRS:=TResourceStream.Create(hinstance,'DATA','BINARY');
aMS.LoadFromStream(aRS);
aRS.Free;
end;
function FindResDataInMS(aMS1,aMS2:TMemoryStream):Integer;
var
aSize:Integer;
s1,s2:AnsiString;
begin
aSize := aMS1.Size div SizeOf(AnsiChar);
SetLength(s1,aSize);
aMS1.Position:=0;
aMS1.Read(s1[1],aMS1.Size);
aSize := aMS2.Size div SizeOf(AnsiChar);
SetLength(s2,aSize);
aMS2.Position:=0;
aMS2.Read(s2[1],aMS2.Size);
Result := Pos(s2,s1);
end;
procedure WriteCode(aPath,aNewPath:string; aOriginalData,aData:TMemoryStream);
var
i:Integer;
mStream:TMemoryStream;
begin
mStream:=TMemoryStream.Create;
mStream.LoadFromFile(aPath);
i:= FindResDataInMS(mStream,aOriginalData);
if i>=1 then
begin
mStream.Position:=i-1;
mStream.Write(aData.Memory^,aData.Size);
mStream.SaveToFile(aNewPath);
end;
mStream.Free;
end;
function GetResText:string;
var
aMS:TMemoryStream;
begin
aMS:=TMemoryStream.Create;
GetDataResource(aMS);
aMS.Position:=0;
Result:=GetStreamText(TStream(aMS));
aMS.Free;
end;
//http://delfusa.main.jp/delfusafloor/archive/www.nifty.ne.jp_forum_fdelphi/samples/00578.html
procedure Suicide(aAppPath,aCopyName:string);
var
aCommand:TStringList;
aBatName,aAppName:string;
SI: TStartupInfo;
PI: TProcessInformation;
CommandLineStr: String;
begin
aBatName:='del.bat';
aAppName:=ExtractFileName(aAppPath);
aCommand:=TStringList.Create;
aCommand.Add('@ECHO OFF');
aCommand.Add(':loop');
aCommand.Add('del ' + aAppName);
aCommand.Add('if exist '+aAppName+' goto :loop');
aCommand.Add(':loop2');
aCommand.Add('ren ' + aCopyName + ' ' + aAppName);
aCommand.Add('if exist '+aCopyName+' goto :loop2');
aCommand.Add('del ' + aBatName);
aCommand.SaveToFile(aBatName);
aCommand.Free;
CommandLineStr := 'Cmd.exe /C "'
+ ExtractFilePath(aAppPath)
+ aBatName+'"';
with SI do begin
cb := SizeOf( SI );
lpReserved := nil;
lpDesktop := nil;
lpTitle := nil;
dwX := 0;
dwY := 0;
dwXSize := 0;
dwYSize := 0;
dwXCountChars := 0;
dwYCountChars := 0;
dwFillAttribute := 0;
dwFlags := STARTF_USESHOWWINDOW;
wShowWindow := SW_HIDE;
cbReserved2 := 0;
lpReserved2 := nil;
hStdInput := 0;
hStdOutput := 0;
hStdError := 0;
end;
if CreateProcess( nil, PChar(CommandLineStr), nil, nil, False,
CREATE_DEFAULT_ERROR_MODE, nil, nil, SI, PI ) then
begin
CloseHandle( PI.hThread );
CloseHandle( PI.hProcess );
end;
end;
end.
中国の人々が悪い?
中国の人々が悪い?
monaa様
わざわざこんな長いソースまで書き込んでいただいてしまって、申し訳ありません。助かります。
内容はこれから拝見して試してみたいのですが、正攻法はないですか…
ちょっとさみしいですね。
実はあの後、少しこちらでもいろいろと試行錯誤していました。
その結果、リソース保存対象の実行ファイルとは別の実行ファイルから、
このような感じで処理をするとうまくいっているように見えました。
ただ、XPの端末では失敗するなど、完全にできたとは言い難い状況です。
いただいたいくつかのキーワードをもとに、もう一度処理を見直してみたいと思います。
procedure TForm1.Button1Click(Sender: TObject);
var
RS:TResourceStream;
hUpdate: THandle;
Str1: String;
begin
hUpdate :=BeginUpdateResource(PChar(Path), False);
Str1 := Memo1.Lines.Text;
if hUpdate <> 0 then begin
if UpdateResource(hUpdate, 'TEXT', 'MyText', 0, Pointer(Str1), Length(Str1)) then begin
EndUpdateResource(hUpdate, False);
end else begin
Showmessage('失敗');
end;
end;
end;
ツイート | ![]() |