List all physical printers using WMI query in Inno Setup - inno-setup

I'm trying to get the list of physical printer's name, that are connected to Windows, based on an answer from Query available RAM in Inno Setup.
But just get: "Send To OneNote 16".
Here is my query:
Query := 'SELECT Name FROM Win32_Printer';
Printer := WbemQuery(WbemServices, Query);
if not VarIsNull(Printer) then
begin
Log(Format('Printers=%s', [Printer.Name]));
end;

You have to iterate the result set:
var
Query: string;
WbemLocator, WbemServices, WbemObjectSet: Variant;
Printer: Variant;
I: Integer;
begin
WbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
WbemServices := WbemLocator.ConnectServer('.', 'root\CIMV2');
Query := 'SELECT Name FROM Win32_Printer';
WbemObjectSet := WbemServices.ExecQuery(Query);
if not VarIsNull(WbemObjectSet) and (WbemObjectSet.Count > 0) then
begin
for I := 0 to WbemObjectSet.Count - 1 do
begin
Printer := WbemObjectSet.ItemIndex(I);
if not VarIsNull(Printer) then
begin
Log(Printer.Name);
end;
end;
end;
end;
The code requires Unicode version of Inno Setup (the only version as of Inno Setup 6) for a better Variant support.
Actually, you can see this code in the same question, where you took the WbemQuery from:
Is there a way to read the system's information in Inno Setup
Note how the Win32_NetworkAdapterConfiguration is iterated there.

Related

Display a message in separate window visible throughout an installation

I already used InfoBeforeFile directive, with an "Important notice" text file.
But I would prefer the user could continue to read the instructions throughout an installation (e.g. in a separate window).
Any clue?
Added the final result, thanks again to Martin Prikryl
Use CreateCustomForm function to create a separate window for your message.
[Files]
Source: "important.txt"; Flags: dontcopy;
[Code]
procedure InitializeWizard();
var
InfoForm: TSetupForm;
InfoMemo: TRichEditViewer;
begin
InfoForm := CreateCustomForm;
Log(IntToStr(WizardForm.Left));
Log(IntToStr(WizardForm.Width));
InfoForm.Left := WizardForm.Left + WizardForm.Width;
InfoForm.Width := ScaleX(400);
InfoForm.Caption := 'Important message';
InfoForm.Top := WizardForm.Top;
InfoForm.Height := WizardForm.Height;
InfoForm.Position := poDesigned;
InfoForm.Show();
InfoMemo := TRichEditViewer.Create(InfoForm);
InfoMemo.Parent := InfoForm;
InfoMemo.Left := ScaleX(40);
InfoMemo.Top := ScaleX(40);
InfoMemo.Width := InfoForm.ClientWidth - 2 * ScaleX(40);
InfoMemo.Height := InfoForm.ClientHeight - 2 * ScaleX(40);
InfoMemo.ScrollBars := ssVertical;
InfoMemo.ReadOnly := ssVertical;
InfoMemo.WantReturns := ssVertical;
InfoMemo.WantReturns := False;
ExtractTemporaryFile('important.txt');
InfoMemo.Lines.LoadFromFile(ExpandConstant('{tmp}\important.txt'));
end;
Though, wouldn't it be better to display the message on the side of the installer wizard?

Correct way to add items to a list box in Inno Setup?

I got a code from List all physical printers using WMI query in Inno Setup and I want to add the results to a list box. I have tried to do it before asking, but I just can't add all items. This is an my code:
var
Query, AllPrinters: string;
WbemLocator, WbemServices, WbemObjectSet: Variant;
Printer: Variant;
I: Integer;
begin
WbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
WbemServices := WbemLocator.ConnectServer('.', 'root\CIMV2');
Query := 'SELECT Name FROM Win32_Printer';
WbemObjectSet := WbemServices.ExecQuery(Query);
if not VarIsNull(WbemObjectSet) and (WbemObjectSet.Count > 0) then
begin
for I := 0 to WbemObjectSet.Count - 1 do
begin
Printer := WbemObjectSet.ItemIndex(I);
if not VarIsNull(Printer) then
begin
Log(Printer.Name);
AllPrinters := Printer.Name;
end;
end;
end;
end;
Then on a custom page do this:
ListBoxPrinters.Items.Add(AllPrinters);
You add the items (printers) to the list box the same way, the original code adds them to the log: in the loop!
for I := 0 to WbemObjectSet.Count - 1 do
begin
Printer := WbemObjectSet.ItemIndex(I);
if not VarIsNull(Printer) then
begin
ListBoxPrinters.Items.Add(Printer.Name);
end;
end;
Of course, you have to create the custom page with the ListBoxPrinters before iterating the printers.
If you cannot run the query after creating the page for whatever reason, you can store a printer list into TStringList.
var
Printers: TStringList;
Printers := TStringList.Create;
for I := 0 to WbemObjectSet.Count - 1 do
begin
Printer := WbemObjectSet.ItemIndex(I);
if not VarIsNull(Printer) then
begin
Printers.Add(Printer.Name);
end;
end;
And once you have the list box ready, you just copy the list over to the box:
ListBoxPrinters.Items.Assign(Printers);
You overwrite always with the next AllPrinters := Printer.Name; the previous value !
simple build the AllPrinters string like that
....
AllPrinters := '';
....
for I := 0 to WbemObjectSet.Count - 1 do
begin
Printer := WbemObjectSet.ItemIndex(I);
if not VarIsNull(Printer) then
begin
Log(Printer.Name);
AllPrinters := AllPrinters + Printer.Name + #13#10;
end;
end;
end;
and
ListBoxPrinters.Items.Text := AllPrinters;

Inno Setup - Cyrillic String shows up as question marks

I am running this code:
function CmdLineParamExists(const Value: string): Boolean;
var
I: Integer;
begin
Result := False;
for I := 1 to ParamCount do
begin
if CompareText(Copy(ParamStr(I), 1, Length(Value)), Value) = 0 then
begin
Result := True;
Exit;
end;
end;
end;
function GetAppName(Value: string): string;
begin
if CmdLineParamExists('/COMPONENTS=prog2') then
begin
Result := 'Программа 2'; //<----This shows up as ????????? 2
end
else
begin
Result := '{#SetupSetting("AppName")}';
end;
end;
procedure CurPageChanged(CurPageID: Integer);
var
S: string;
Begin
if CurPageID = wpSelectDir then
begin
S := SetupMessage(msgSelectDirLabel3);
StringChange(S, '[name]', GetAppName(''));
WizardForm.SelectDirLabel.Caption := S;
end;
end;
Now, I'm not sure what I'm doing wrong here. Every other string shows up correctly, except when I use the result of GetAppName. Should I convert anything to AnsiString at some point?
I'm assuming that you are using Ansi version of Inno Setup.
In the Ansi version, the culprit is probably the StringChange as it does not play nicely with non-Ansi character sets. Try using StringChangeEx.
Though you should be using Unicode version of Inno Setup anyway.
Only the most recent version of Inno Setup, 5.6, does support Unicode string literals. So make sure you have the latest version.
If you are stuck with an older version:
Encode the string like
#$041F#$0440#$043E#$0433#$0440#$0430#$043C#$043C#$0430 + ' 2'
Or, actually the most correct way is to add a new custom message to the language files (like Russian.isl):
[CustomMessages]
Program2=Программа 2
And load it like:
CustomMessage('Program2')

Inno Setup custom wizard pages ("installation checklist") change text at runtime

I made a custom wizard page, and I want it to show a sort of installation checklist at the end of the install, showing what installed successfully or not.
Something like
Crucial Step......................SUCCESS
Optional Step.....................FAILURE
So I have this code in my initializeWizard()
Page := CreateCustomPage(wpInstalling, 'Installation Checklist', 'Status of all installation components');
RichEditViewer := TRichEditViewer.Create(Page);
RichEditViewer.Width := Page.SurfaceWidth;
RichEditViewer.Height := Page.SurfaceHeight;
RichEditViewer.Parent := Page.Surface;
RichEditViewer.ScrollBars := ssVertical;
RichEditViewer.UseRichEdit := True;
RichEditViewer.RTFText := ''// I want this attribute to be set in CurStepChanged()
Is there a way to add or edit RichEditViewer.RTFText at a later point in time? Page is a global variable but trying to access any attributes gives me an error. I'd like to do edit the text after wpInstalling, so I can tell whether or not install steps were successful.
I'm not a huge fan of this method, but you Can set your RichEditViewer as a global, and then editing it at any point, in any function, is trivial.
var
RichEditViewer: TRichEditViewer;
procedure InitializeWizard();
var
Page: TWizardPage;
begin
Page := CreateCustomPage(wpInstalling, 'Installation Checklist', '');
RichEditViewer := TRichEditViewer.Create(Page);
RichEditViewer.Width := Page.SurfaceWidth;
RichEditViewer.Height := Page.SurfaceHeight;
RichEditViewer.Parent := Page.Surface;
RichEditViewer.ScrollBars := ssVertical;
RichEditViewer.UseRichEdit := True;
end;
procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep=ssPostInstall then RichEditViewer.RTFText := 'STUFF';
end;
Worthwhile to note, the page itself doesn't even need to be global.

Show text during installation process with inno-setup

I am searching for a possibility to show a user a note on how to proceed during install of a redistributable.
Background:
I have some Components that require 3rd party installations which are quit complex. If a user selects one of these components a message box with instructions are shown. After this box the resistributables are executet via exec/shellExec with 'ewWaitUntilTerminated'. Unfortunately the user cannot see the box during installation.
I tried to just open the notes in notepad and use 'ewNoWait', but than it will not close automatically after each installation of the redistributalbe. The user can chose more than one of these components and this help should only be visible during the specific installation. To kill the notepad with taskkill is not an option, it could kill opened notepad from the user.
Is there any elegant way to get such behaviour?
Create TOutputProgressWizardPage with function http://www.jrsoftware.org/ishelp/index.php?topic=isxfunc_createoutputprogresspage
function CreateOutputProgressPage(const ACaption, ADescription: String): TOutputProgressWizardPage;
[Code]
var
ProgressPage: TOutputProgressWizardPage;
procedure InitializeWizard;
begin
ProgressPage := CreateOutputProgressPage('Finalization of installation','');
end;
procedure CurPageChanged(CurPageID: Integer);
var
I: Integer;
begin
// Page is shown after installation when Finish page is shown
if CurPageID = wpFinish then begin
ProgressPage.SetText('Installing some 3rd party stuff...', '');
ProgressPage.SetProgress(0, 0);
ProgressPage.Show;
try
// Use exec/shellExec here to execute 3rd party app
// Also you can adjust progress barr position here:
for I := 0 to 10 do begin
ProgressPage.SetProgress(I, 10);
Sleep(100);
end;
finally
ProgressPage.Hide;
end;
end else
Result := True;
end;
I finally found a solution for my problem. On the basis of the answer of Slappy I used a std MsgPage and resize it for my need. Thx to TLama for his answer in a different topic for the resize code!
[Code]
var
RedistPage: TOutputMsgWizardPage;
DefaultTop,
DefaultLeft,
DefaultHeight,
DefaultBackTop,
DefaultNextTop,
DefaultCancelTop,
DefaultBevelTop,
DefaultBeveledLabelTop,
DefaultInnerHeight,
DefaultOuterHeight: Integer;
procedure InitializeWizard();
var
ReadMe: AnsiString;
begin
DefaultTop := WizardForm.Top;
DefaultLeft := WizardForm.Left;
DefaultHeight := WizardForm.Height;
DefaultBackTop := WizardForm.BackButton.Top;
DefaultNextTop := WizardForm.NextButton.Top;
DefaultCancelTop := WizardForm.CancelButton.Top;
DefaultBevelTop := WizardForm.Bevel.Top;
DefaultBeveledLabelTop := WizardForm.BeveledLabel.Top;
DefaultOuterHeight := WizardForm.OuterNotebook.Height;
DefaultInnerHeight := WizardForm.InnerNotebook.Height;
// save the contents of Readme.txt (non Unicode) in a string and build custom page
try
ExtractTemporaryFiles('{tmp}\readme.txt');
if LoadStringFromFile(ExpandConstant('{tmp}\readme.txt'), ReadMe) then
RedistPage := CreateOutputMsgPage(wpReady,
'Information', 'Please read the following important information about the installation before continuing.',ReadMe);
except
ShowExceptionMessage;
end;
function ShouldSkipPage(PageID: Integer): Boolean;
begin
Result := False; // initialize result to not skip any page (not necessary, but safer)
if PageID = RedistPage.ID then // if the page that is asked to be skipped is your custom page, then...
Result := not IsTaskSelected('dexela_API'); // if the task is not selected, skip the page
end;
procedure ChangePageSize(HeightOffset: Integer);
begin
WizardForm.Top := DefaultTop - (HeightOffset - DefaultHeight) div 2;
WizardForm.Height := WizardForm.Height + (HeightOffset - DefaultHeight);
WizardForm.InnerPage.Height := WizardForm.InnerPage.Height + (HeightOffset - DefaultHeight);
WizardForm.InnerNotebook.Height := WizardForm.InnerNotebook.Height + (HeightOffset - DefaultHeight);
WizardForm.OuterNotebook.Height := WizardForm.OuterNotebook.Height + (HeightOffset - DefaultHeight);
WizardForm.CancelButton.Top := DefaultCancelTop + (HeightOffset - DefaultHeight);
WizardForm.NextButton.Top := DefaultNextTop + (HeightOffset - DefaultHeight);
WizardForm.BackButton.Top := DefaultBackTop + (HeightOffset - DefaultHeight);
WizardForm.Bevel.Top := DefaultBevelTop + (HeightOffset - DefaultHeight);
end;
procedure CurPageChanged(CurPageID: Integer);
var
ComponentsPageTextHeight: Integer;
begin
if (CurPageID = RedistPage.ID) and (IsTaskSelected('dexela_API'))then begin
ChangePageSize(650);
//Sleep(2000); // time for the user to recognize the text, before it is hidden by installer
// Extract all Dexela files and launch them.
try
ExtractTemporaryFiles('{tmp}\Setup.msi');
except
ShowExceptionMessage;
end;
ShellExec('',ExpandConstant('{tmp}\Setup.msi'), '', '',SW_SHOW, ewWaitUntilTerminated, ResultCode);
end;
end;

Resources