Using Registry Values in ICON Section - icons

I am trying to use a registry value for the location of an EXE file in the ICONS section, the value is not located in the normal \microsoft\windows\exe\ registry. I have the following code that is not retuning the value, the ICON is created with the word "computer" for the target.
function GetACADexe (Param: string): string;
var VerKey: String;
var ExeKey: String;
begin
if RegQueryStringValue(HKCU, 'Software\Classes\AutoCAD.Drawing', 'CurVer', VerKey) and
RegQueryStringValue(HKCU, 'Software\Classes\' + VerKey + '\Protocol\StdFileEditing', 'Server', ExeKey) then
Result := ExpandConstant ('{ExeKey}')
end;

Here is the resultant working answer;
function GetHKCU() : Integer;
begin
if IsWin64 then
begin
Result := HKCU64;
end
else
begin
Result := HKEY_CURRENT_USER;
end;
end;
function GetACADexe(Value: String): string;
var
VerKey: string;
ExeKey: string;
begin
// result should be initialized for case when ACAD is not installed
Result := '';
if RegQueryStringValue(GetHKCU(), 'Software\Classes\AutoCAD.Drawing\CurVer', '', VerKey) and
RegQueryStringValue(GetHKCU(), 'Software\Classes\' + VerKey + '\Protocol\StdFileEditing\Server', '', ExeKey)
then
Result := ExeKey;
end;
Along with checking for 32 or 64 bit systems, I also ran into the issue that the registry values where the "(Default)" values, that's why the empty '' for the key name. Works great now.... Thanks TLAMA.

Related

HTTP POST returns truncated response if executed in loop

The code below works fine if executed as a single command. I use it to download PDFs that are typically a few megabytes in size.
However, when I execute it multiple times in a loop, all the downloaded files are exactly the same size (truncated # ~50KB). Is there an issue with my code or is this the server not being able to deliver as expected?
type
TKeyValuePair = record
Key: String;
Value: String;
end;
TKeyValueSet = Array of TKeyValuePair;
// ...
function TDM.MultipartPost(const URL, LocalFile: String; const MultipartData: TKeyValueSet): Boolean;
var
i: Integer;
httpclient: THTTPClient;
formdata: TMultipartFormData;
fstream: TFileStream;
begin
httpclient := THTTPClient.Create;
formdata := TMultipartFormData.Create();
fstream := nil;
try
fstream := TFileStream.Create(LocalFile, fmCreate);
except
// removed
end;
try
for i := Low(MultipartData) to High(MultipartData) do
formdata.AddField(MultipartData[i].Key, MultipartData[i].Value);
try
httpclient.Post(url, formdata, fstream);
except
// removed
end;
finally
FlushFileBuffers(fstream.Handle);
fstream.Free;
formdata.Free;
httpclient.Free;
//
Result := FileExists(LocalFile) and (GetFileSize(LocalFile) > 0);
end;
end;
Mea culpa - my apologies to all that read/replied to my post. I just built a minimal, but complete application to demonstrate the issue and, voila, it worked just fine.
1 hour or so of not seeing the forest for all the trees later:
I accidentally used an incorrect URL to post to :(

Delphi: Setting timestamp of file wrong by one hour for some files

I want to correct the last-access time of some files.
Doing that programmatically fails - by one hour - for some files.
Mysterious, as I do correct the date according to the timezone.
Here is an example, tested for Delphi2010 (that's where I would need code for) and Delphi10.3
function GetTempDir : string;
var path : array[0..MAX_PATH] of char;
PathStr : string;
begin
GetTempPath(MAX_PATH, path);
PathStr:=path;
result:=IncludeTrailingPathDelimiter(PathStr);
end;
function UTCDateTimeFromLocalDateTime(const LocalDateTime: TDateTime): TDateTime;
var
LocalSystemTime: TSystemTime;
UTCSystemTime: TSystemTime;
LocalFileTime: TFileTime;
UTCFileTime: TFileTime;
begin
DateTimeToSystemTime(LocalDateTime, UTCSystemTime);
SystemTimeToFileTime(UTCSystemTime, UTCFileTime);
if LocalFileTimeToFileTime(UTCFileTime, LocalFileTime)
and FileTimeToSystemTime(LocalFileTime, LocalSystemTime) then begin
Result := SystemTimeToDateTime(LocalSystemTime);
end else begin
Result := LocalDateTime;
end;
end;
function SetFileTimesHelper(const FileName: string; DateTime: TDateTime): Boolean;
var
Handle: THandle;
FileTime: TFileTime;
SystemTime: TSystemTime;
begin
Result := False;
Handle := CreateFile(PChar(FileName), GENERIC_WRITE, FILE_SHARE_READ, nil,
OPEN_EXISTING, 0, 0);
if Handle <> INVALID_HANDLE_VALUE then
try
DateTime:=UTCDateTimeFromLocalDateTime(DateTime);
DateTimeToSystemTime(DateTime, SystemTime);
FileTime.dwLowDateTime := 0;
FileTime.dwHighDateTime := 0;
if SystemTimeToFileTime(SystemTime, FileTime) then
begin
Result := SetFileTime(Handle, nil, nil, #FileTime);
end;
finally
CloseHandle(Handle);
end;
end;
procedure TForm1.CreateDateFile(Dat : TDateTime);
var FileName : string;
begin
FileName:=GetTempDir+FormatDateTime('yyyymmdd hhnnss', Dat)+'.txt';
Memo1.Lines.Add(FileName);
with TStringList.Create do
begin
text:='1';
SaveToFile(FileName);
Free;
end;
SetFileTimesHelper(FileName, Dat);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
CreateDateFile(StrToDateTime('23.02.2013 11:11:11'));
CreateDateFile(StrToDateTime('06.05.2014 22:22:22')); // file dated 23:22:22
end;
The first file is correctly dated, the 2nd is displayed in the windows explorer with 23:22:22.
What do I miss?
Thanks brian for the comment.
Digging that way I found a solution:
GetTimeZoneInformation(tz);
SystemTimeToTzSpecificLocalTime(#tz, UTCSystemTime, LtSystemTime);
I didn't find the inverse function of SystemTimeToTzSpecificLocalTime, but I used this function and then see the resulting offset. Then I invert the offset and the time is properly corrected.

Pin folder to the start menu with Inno Setup [duplicate]

I'm using the excellent Inno Setup installer and I notice that some Applications (often from Microsoft) get installed with their launch icon already highly visible ('pinned?') in the start menu (in Windows 7). Am I totally reliant on the most-recently-used algorithm for my icon to be 'large' in the start menu, or is there a way of promoting my application from the installer please?
It is possible to pin programs, but not officially. Based on a code posted in this thread (which uses the same way as described in the article linked by #Mark Redman) I wrote the following:
[Code]
#ifdef UNICODE
#define AW "W"
#else
#define AW "A"
#endif
const
// these constants are not defined in Windows
SHELL32_STRING_ID_PIN_TO_TASKBAR = 5386;
SHELL32_STRING_ID_PIN_TO_STARTMENU = 5381;
SHELL32_STRING_ID_UNPIN_FROM_TASKBAR = 5387;
SHELL32_STRING_ID_UNPIN_FROM_STARTMENU = 5382;
type
HINSTANCE = THandle;
HMODULE = HINSTANCE;
TPinDest = (
pdTaskbar,
pdStartMenu
);
function LoadLibrary(lpFileName: string): HMODULE;
external 'LoadLibrary{#AW}#kernel32.dll stdcall';
function FreeLibrary(hModule: HMODULE): BOOL;
external 'FreeLibrary#kernel32.dll stdcall';
function LoadString(hInstance: HINSTANCE; uID: UINT;
lpBuffer: string; nBufferMax: Integer): Integer;
external 'LoadString{#AW}#user32.dll stdcall';
function TryGetVerbName(ID: UINT; out VerbName: string): Boolean;
var
Buffer: string;
BufLen: Integer;
Handle: HMODULE;
begin
Result := False;
Handle := LoadLibrary(ExpandConstant('{sys}\Shell32.dll'));
if Handle <> 0 then
try
SetLength(Buffer, 255);
BufLen := LoadString(Handle, ID, Buffer, Length(Buffer));
if BufLen <> 0 then
begin
Result := True;
VerbName := Copy(Buffer, 1, BufLen);
end;
finally
FreeLibrary(Handle);
end;
end;
function ExecVerb(const FileName, VerbName: string): Boolean;
var
I: Integer;
Shell: Variant;
Folder: Variant;
FolderItem: Variant;
begin
Result := False;
Shell := CreateOleObject('Shell.Application');
Folder := Shell.NameSpace(ExtractFilePath(FileName));
FolderItem := Folder.ParseName(ExtractFileName(FileName));
for I := 1 to FolderItem.Verbs.Count do
begin
if FolderItem.Verbs.Item(I).Name = VerbName then
begin
FolderItem.Verbs.Item(I).DoIt;
Result := True;
Exit;
end;
end;
end;
function PinAppTo(const FileName: string; PinDest: TPinDest): Boolean;
var
ResStrID: UINT;
VerbName: string;
begin
case PinDest of
pdTaskbar: ResStrID := SHELL32_STRING_ID_PIN_TO_TASKBAR;
pdStartMenu: ResStrID := SHELL32_STRING_ID_PIN_TO_STARTMENU;
end;
Result := TryGetVerbName(ResStrID, VerbName) and ExecVerb(FileName, VerbName);
end;
function UnpinAppFrom(const FileName: string; PinDest: TPinDest): Boolean;
var
ResStrID: UINT;
VerbName: string;
begin
case PinDest of
pdTaskbar: ResStrID := SHELL32_STRING_ID_UNPIN_FROM_TASKBAR;
pdStartMenu: ResStrID := SHELL32_STRING_ID_UNPIN_FROM_STARTMENU;
end;
Result := TryGetVerbName(ResStrID, VerbName) and ExecVerb(FileName, VerbName);
end;
The above code first reads the caption of the menu item for pinning or unpinning applications from the string table of the Shell32.dll library. Then connects to the Windows Shell, and for the target app. path creates the Folder object, then obtains the FolderItem object and on this object iterates all the available verbs and checks if their name matches to the one read from the Shell32.dll library string table. If so, it invokes the verb item action by calling the DoIt method and exits the iteration.
Here is a possible usage of the above code, for pinning:
if PinAppTo(ExpandConstant('{sys}\calc.exe'), pdTaskbar) then
MsgBox('Calc has been pinned to the taskbar.', mbInformation, MB_OK);
if PinAppTo(ExpandConstant('{sys}\calc.exe'), pdStartMenu) then
MsgBox('Calc has been pinned to the start menu.', mbInformation, MB_OK);
And for unpinning:
if UnpinAppFrom(ExpandConstant('{sys}\calc.exe'), pdTaskbar) then
MsgBox('Calc is not pinned to the taskbar anymore.', mbInformation, MB_OK);
if UnpinAppFrom(ExpandConstant('{sys}\calc.exe'), pdStartMenu) then
MsgBox('Calc is not pinned to the start menu anymore.', mbInformation, MB_OK);
Please note that even though this code works on Windows 7 (and taskbar pinning also on Windows 8.1 where I've tested it), it is really hacky way, since there is no official way to programatically pin programs to taskbar, nor start menu. That's what the users should do by their own choice.
There's a reason there's no programmatic way to pin things to the taskbar/start menu. In my experience, I have seen the start menu highlight newly-created shortcuts, and that's designed to handle exactly this situation. When you see a newly-installed program show up on the start menu, it's probably because of that algorithm and not because the installer placed it there.
That said, if a new shortcut does not appear highlighted, it may be because the installer extracts a pre-existing shortcut and preserves an old timestamp on it, rather than using the API function to create a shortcut in the start menu.
Have a look at: http://blogs.technet.com/deploymentguys/archive/2009/04/08/pin-items-to-the-start-menu-or-windows-7-taskbar-via-script.aspx

Could not convert variant of type (Unknown) into type (Dispatch)

I´m trying to port the following javascript code to inno-setup pascal script:
var adminManager = new ActiveXObject('Microsoft.ApplicationHost.AdminManager');
var appPoolsSection = adminManager.GetAdminSection('system.applicationHost/applicationPools', 'MACHINE/WEBROOT/APPHOST');
var appPoolsCollection = applicationPoolsSection.Collection;
for (var i = 0; i < appPoolsCollection.Count; i++)
{
var appPool = appPoolsCollection.Item(i);
// doing someting with the application pool
}
This code has been translated to this:
var AdminManager, AppPoolsSection, AppPoolsCollection, AppPool: Variant;
i: Integer;
begin
AdminManager := CreateOleObject('Microsoft.ApplicationHost.AdminManager');
AppPoolsSection := AdminManager.GetAdminSection('system.applicationHost/applicationPools', 'MACHINE/WEBROOT/APPHOST');
AppPoolsCollection := AppPoolsSection.Collection;
for i := 0 to AppPoolsCollection.Count-1 do begin
AppPool := AppPoolsCollection.Item(i);
// doing someting with the application pool
end;
end;
But it is raising the following error on line AppPoolsCollection := AppPoolsSection.Collection:
Exception: Could not convert variant of type (Unknown) into type (Dispatch).
There are any thing that I can do to inform to pascal scritp that the AppPoolsSection object is an IDispach and not only an IUnknown?
I found a solution that works and is simpler than "import" the interfaces definition.
All the COM components used in this code implements IDispatch (it is required to use on VBScript or JScript), then I imported the VariantChangeType function to cast the IUnknown reference to an IDispatch reference (as it appears not to be supported on pascal script).
Follow the final code:
function VariantChangeType(out Dest: Variant; Source: Variant; Flags, vt: Word): HRESULT; external 'VariantChangeType#oleaut32.dll stdcall';
function VarToDisp(Source: Variant): Variant;
begin
Result := Unassigned;
OleCheck(VariantChangeType(Result, Source, 0, varDispatch));
end;
procedure EnumerateAppPools(AppPools: TStrings);
var AdminManager, Section, Collection, Item, Properties: Variant;
i: Integer;
begin
AdminManager := CreateOleObject('Microsoft.ApplicationHost.AdminManager');
Section := VarToDisp(AdminManager.GetAdminSection('system.applicationHost/applicationPools', 'MACHINE/WEBROOT/APPHOST'));
Collection := VarToDisp(Section.Collection);
for i := 0 to Collection.Count-1 do begin
Item := VarToDisp(Collection.Item(i));
Properties := VarToDisp(Item.Properties);
if (VarToDisp(Properties.Item('managedPipelineMode')).Value = 1) and
(VarToDisp(Properties.Item('managedRuntimeVersion')).Value = 'v4.0') then
AppPools.Add(VarToDisp(Properties.Item('name')).Value);
end;
end;

Inno Setup: Ord Function or eqivalent?

I'm using inno setup to "crypt" a password:
function XORcrypt(Value,Key: string): string;
var
p,k,pl,kl: integer;
begin
{very basic encryption, using bitwise XOR}
result:=Value;
pl:=Length(Value);
kl:=Length(Key);
if (pl>0) and (kl>0) then
begin
p:=1; k:=1;
while (p<=pl) do
begin
Result[p]:=Char(Ord(Value[p]) XOR Ord(Key[k]));
if k=kl then k:=1 else k:=k+1;
p:=p+1
end; {while}
end; {if}
end; {XORcrypt}
inno seems not to know the pascal function Ord which returns the ASCII value of a requested character (67 for 'C')
Any solutions?
The problem is not Ord() it's Char() you need to use Chr() instead.
function XORcrypt(Value,Key: String): String;
var
p,k,pl,kl: integer;
begin
{very basic encryption, using bitwise XOR}
result:=Value;
pl:=Length(Value);
kl:=Length(Key);
if (pl>0) and (kl>0) then
begin
p:=1; k:=1;
while (p<=pl) do
begin
Result[p]:=Chr(Ord(Value[p]) XOR Ord(Key[k]));
if k=kl then k:=1 else k:=k+1;
p:=p+1
end; {while}
end; {if}
end; {XORcrypt}

Resources