Highlight word in TListView Delphi 7 - delphi-7

I'm trying to highlight a word from TListView but I can't make it work. My first attempt is to highlight the first letter of each row but won't work. TListView won't display anything. Here is my code:
procedure TfrmMain.lvMainDrawItem(Sender: TCustomListView; Item: TListItem; Rect: TRect; State: TOwnerDrawState);
var
r : TRect;
c : TCanvas;
begin
r := Item.DisplayRect(drBounds);
c := Sender.Canvas;
c.Brush.Color := clWindow;
c.Font.Color := clWindowText;
c.TextRect(r, 1, 1, 'a');
end;
I based my code here but it is written in XE10.4. I'm using delphi 7. How can I highlight word/first letter of each row in TListView?

You are drawing outside of the item's bounding rectangle, that is why you don't see anything. The X,Y coordinates you specify to TextRect() are relative to the top/left corner of the ListView's client area, but are clipped by the specified TRect.
Try this instead:
c.TextRect(r, r.Left+1, r.Top+1, 'a');

Here is my working code:
set and populate list view
procedure TForm1.Button1Click(Sender: TObject);
begin
ListView1.Clear;
ListView1.ViewStyle := vsReport;
ListView1.RowSelect := True;
ListView1.Items.Add.Caption := 'banana';
ListView1.Items.Add.Caption := 'apple and banana';
ListView1.Items.Add.Caption := 'orange apple and banana';
ListView1.Items.Add.Caption := 'banana and orange';
ListView1.Items.Add.Caption := 'banana orange and apple';
ListView1.Items.Add.Caption := 'appleXandXbanana';
ListView1.Items.Add.Caption := 'orangeXappleXand banana';
ListView1.Items.Add.Caption := 'bananaXandXorange';
ListView1.Items.Add.Caption := 'bananaXorangeXandXapple';
end;
painting
procedure TForm1.ListView1DrawItem(Sender: TCustomListView;Item: TListItem; Rect: TRect; State: TOwnerDrawState);
var
r : TRect;
c : TCanvas;
sText : string;
sTemp : string;
nPos : Integer;
nLen : Integer;
lv : TListView;
begin
if item = nil then
begin
Exit;
end;
r := Item.DisplayRect(drBounds);
c := Sender.Canvas;
lv := TListView(Sender);
// fKeyword := 'apple';
sText := Item.Caption;
nLen := Length(fKeyword);
nPos := AnsiPos(fKeyword, sText);
// first part : before match
sTemp := Copy(sText, 1, nPos - 1);
if sTemp <> '' then
begin
c.Brush.Color := clWindow;
c.Font.Color := clWindowText;
c.TextRect(r, r.Left, r.Top, sTemp);
Inc(r.Left, c.TextWidth(sTemp));
end;
// second part: match
sTemp := Copy(sText, nPos, nLen);
if (nPos > 0) and (sTemp <> '') then
begin
c.Brush.Color := clRed;
c.Font.Color := clBlue;
c.TextRect(r, r.Left + 1, r.Top, sTemp);
Inc(r.Left, c.TextWidth(sTemp));
end;
// third part : after match
if nPos = 0 then
begin
sTemp := sText;
end
else
begin
sTemp := Copy(sText, nPos + nLen, Length(sText) - nPos - nLen + 1);
end;
c.Brush.Color := clWindow;
c.Font.Color := clWindowText;
c.TextRect(r, r.Left + 1, r.Top, sTemp);
Inc(r.Left, c.TextWidth(sTemp));
if odFocused in State then
begin
lv.Canvas.Brush.Style := bsSolid;
lv.Canvas.Brush.Color := clBlack;
lv.Canvas.Font.Color := clWhite;
DrawFocusRect(lv.Canvas.Handle, Rect);
end;
end;

Related

Programatically queries Channel Number using WinAPI-WlanQueryInterface- Delphi

While querying the WlanQueryInterface to get the channel number see that the return value is a large integer like 1820789 etc.. any help?
uses nduWlanTypes, nduWlanAPI;
Function GetWifiChannelTest: String;
var
hClient: THandle;
dwVersion: DWORD;
ResultInt: DWORD;
pInterface: Pndu_WLAN_INTERFACE_INFO_LIST;
i: Integer;
pInterfaceGuid: TGUID;
pdwDataSize: DWORD;
ppData: Tndu_WLAN_INTF_OPCODE;
pI: Pinteger;
p: pvoid;
begin
ResultInt := WlanOpenHandle(1, nil, #dwVersion, #hClient);
try
if ResultInt <> ERROR_SUCCESS then
begin
ShowMessage('Error Open CLient' + IntToStr(ResultInt));
Exit;
end;
ResultInt := WlanEnumInterfaces(hClient, nil, #pInterface);
if ResultInt <> ERROR_SUCCESS then
begin
ShowMessage('Error Enum Interfaces ' + IntToStr(ResultInt));
Exit;
end;
for i := 0 to pInterface^.dwNumberOfItems - 1 do
begin
pInterfaceGuid := pInterface^.InterfaceInfo[pInterface^.dwIndex]
.InterfaceGuid;
ResultInt := WlanQueryInterface(hClient, #pInterfaceGuid,
wlan_intf_opcode_channel_number, nil, #pdwDataSize, #ppData, nil);
try
if (ResultInt = ERROR_SUCCESS) and (pdwDataSize = SizeOf(ppData)) then
begin
p := #ppData;
pI := pvoid(p);
Result := IntToStr(pI^);
// the result is 1820789 ,but i need channel number like 10, or 11 etc...
end;
except
end;
end;
finally
WlanCloseHandle(hClient, nil);
end;
end;
You are not enumerating interfaces correctly. You should not be using dwIndex as the index into the InterfaceInfo[] array. Use your loop counter i instead.
Also, you are not calling WlanQueryInterface() correctly. wlan_intf_opcode_channel_number outputs a ULONG value, not a WLAN_INTF_OPCODE value.
Also, you are leaking the WLAN_INTERFACE_INFO_LIST that WlanEnumInterfaces() allocates.
Try something more like this instead:
uses
nduWlanTypes, nduWlanAPI;
Function GetWifiChannelTest: String;
var
hClient: THandle;
dwVersion: DWORD;
ResultInt: DWORD;
pIntfList: PWLAN_INTERFACE_INFO_LIST;
i: DWORD;
IntfGuid: TGUID;
dwDataSize: DWORD;
ChannelNumber: ULONG;
begin
Result := '';
ResultInt := WlanOpenHandle(1, nil, #dwVersion, #hClient);
if ResultInt <> ERROR_SUCCESS then
begin
ShowMessage('Error Open Client: ' + IntToStr(ResultInt));
Exit;
end;
try
ResultInt := WlanEnumInterfaces(hClient, nil, #pIntfList);
if ResultInt <> ERROR_SUCCESS then
begin
ShowMessage('Error Enumerating Interfaces: ' + IntToStr(ResultInt));
Exit;
end;
try
for i := 0 to pIntfList^.dwNumberOfItems - 1 do
begin
IntfGuid := pIntfList^.InterfaceInfo[i].InterfaceGuid;
ResultInt := WlanQueryInterface(hClient, #IntfGuid, wlan_intf_opcode_channel_number, nil, #dwDataSize, #ChannelNumber, nil);
if ResultInt = ERROR_SUCCESS then
begin
Result := IntToStr(ChannelNumber);
Exit;
end;
end;
finally
WlanFreeMemory(pIntfList);
end;
finally
WlanCloseHandle(hClient, nil);
end;
end;
UPDATE: after further review, it seems that wlan_intf_opcode_channel_number might be outputting a pointer to a ULONG, so you would need to give it a pointer to a pointer to a ULONG, and then you can dereference the outputted pointer to get the actual ULONG. Try this:
uses
nduWlanTypes, nduWlanAPI;
Function GetWifiChannelTest: String;
var
hClient: THandle;
dwVersion: DWORD;
ResultInt: DWORD;
pIntfList: PWLAN_INTERFACE_INFO_LIST;
i: DWORD;
IntfGuid: TGUID;
dwDataSize: DWORD;
pChannelNumber: PULONG; // <--
begin
Result := '';
ResultInt := WlanOpenHandle(1, nil, #dwVersion, #hClient);
if ResultInt <> ERROR_SUCCESS then
begin
ShowMessage('Error Open Client: ' + IntToStr(ResultInt));
Exit;
end;
try
ResultInt := WlanEnumInterfaces(hClient, nil, #pIntfList);
if ResultInt <> ERROR_SUCCESS then
begin
ShowMessage('Error Enumerating Interfaces: ' + IntToStr(ResultInt));
Exit;
end;
try
for i := 0 to pIntfList^.dwNumberOfItems - 1 do
begin
IntfGuid := pIntfList^.InterfaceInfo[i].InterfaceGuid;
ResultInt := WlanQueryInterface(hClient, #IntfGuid, wlan_intf_opcode_channel_number, nil, #dwDataSize, #pChannelNumber, nil);
if ResultInt = ERROR_SUCCESS then
begin
Result := IntToStr(pChannelNumber^); // <--
Exit;
end;
end;
finally
WlanFreeMemory(pIntfList);
end;
finally
WlanCloseHandle(hClient, nil);
end;
end;

Inno Setup: Custom page to select Update or Remove/Uninstall

I need to create a custom uninstall page that let the user choose if he wants to update the software or uninstall it (if the software is already installed).
I have already done my custom page and is like this:
How can I get the values of those radio buttons when the user click the Next Button?
And, how can I update or uninstall the program?
UPDATE:
procedure InitializeWizard();
var
InstallPath: String;
BackgroundBitmapImage: TBitmapImage;
BmpFileName : String;
Temp : String;
AppId : String;
Color : String;
begin
AppId:=ExpandConstant('{#AppId}');
if(AppIsInstalled(AppId, InstallPath)) Then
begin
UpdateRemovePageID := RepairRemove_CreatePage(wpWelcome);
end;
BmpFileName:= ExpandConstant('{src}\Background.bmp');
if FileExists(BmpFileName) then begin
BackgroundBitmapImage := TBitmapImage.Create(MainForm);
BackgroundBitmapImage.Align := alClient;
BackgroundBitmapImage.Autosize := True;
BackgroundBitmapImage.Center := True;
BackgroundBitmapImage.Bitmap.LoadFromFile(BmpFileName);
end;
BackgroundBitmapImage.BackColor := StringToColor('8cceff');
BackgroundBitmapImage.Parent := MainForm;
WizardForm.Caption := MainForm.Caption;
if(FileExists(ExpandConstant('{src}\WizImage.bmp'))) then begin
WizardForm.WizardBitmapImage.Bitmap.LoadFromFile(ExpandConstant('{src}') + '\WizImage.bmp');
end
if(FileExists(ExpandConstant('{src}\WizSmallImage.bmp'))) then begin
WizardForm.WizardSmallBitmapImage.Bitmap.LoadFromFile(ExpandConstant('{src}') + '\WizSmallImage.bmp');
end
end;
function RepairRemove_CreatePage(PreviousPageId: Integer): Integer;
var
Page: TWizardPage;
UpdateBmpFileName : String;
RemoveBmpFileName : String;
begin
Page := CreateCustomPage(PreviousPageId, ExpandConstant('{cm:RepairRemove_Caption}'), ExpandConstant('{cm:RepairRemove_Description}'));
BitmapImageUpdate := TBitmapImage.Create(Page);
UpdateBmpFileName := ExpandConstant('{tmp}\Update.bmp');
if not FileExists(UpdateBmpFileName) then begin
ExtractTemporaryFile(ExtractFileName(UpdateBmpFileName));
end;
BitmapImageUpdate.Bitmap.LoadFromFile(UpdateBmpFileName);
with BitmapImageUpdate do
begin
Parent := Page.Surface;
Left := ScaleX(64);
Top := ScaleY(64);
Width := ScaleX(32);
Height := ScaleY(32);
end;
Label1 := TLabel.Create(Page);
with Label1 do
begin
Parent := Page.Surface;
Caption := ExpandConstant('{cm:RepairRemove_Label1_Caption0}');
Left := ScaleX(120);
Top := ScaleY(72);
Width := ScaleX(243);
Height := ScaleY(13);
end;
BitmapImageRemove := TBitmapImage.Create(Page);
RemoveBmpFileName := ExpandConstant('{tmp}\TrashCan.bmp');
if not FileExists(RemoveBmpFileName) then begin
ExtractTemporaryFile(ExtractFileName(RemoveBmpFileName));
end;
BitmapImageRemove.Bitmap.LoadFromFile(RemoveBmpFileName);
with BitmapImageRemove do
begin
Parent := Page.Surface;
Left := ScaleX(64);
Top := ScaleY(120);
Width := ScaleX(32);
Height := ScaleY(32);
end;
Label2 := TLabel.Create(Page);
with Label2 do
begin
Parent := Page.Surface;
Caption := ExpandConstant('{cm:RepairRemove_Label2_Caption0}');
Left := ScaleX(120);
Top := ScaleY(128);
Width := ScaleX(243);
Height := ScaleY(13);
end;
UpdateButton := TRadioButton.Create(Page);
with UpdateButton do
begin
Parent := Page.Surface;
Caption := ExpandConstant('');
Left := ScaleX(32);
Top := ScaleY(72);
Width := ScaleX(17);
Height := ScaleY(17);
TabOrder := 0;
end;
RemoveButton := TRadioButton.Create(Page);
with RemoveButton do
begin
Parent := Page.Surface;
Caption := ExpandConstant('');
Left := ScaleX(32);
Top := ScaleY(128);
Width := ScaleX(17);
Height := ScaleY(17);
Checked := True;
TabOrder := 1;
TabStop := True;
end;
with Page do
begin
OnActivate := #RepairRemove_Activate;
OnShouldSkipPage := #RepairRemove_ShouldSkipPage;
OnBackButtonClick := #RepairRemove_BackButtonClick;
OnNextButtonClick := #RepairRemove_NextButtonClick;
OnCancelButtonClick := #RepairRemove_CancelButtonClick;
end;
Result := Page.ID;
end;
function RepairRemove_NextButtonClick(Page: TWizardPage): Boolean;
begin
Result := True;
//What I have to do here to correctly handle the user choice?
end;
how can I update or uninstall the program?
Update - That's what the installer does by default.
Uninstall - See How to detect old installation and offer removal?
You will also want to abort the installer after uninstallation:
Exit from Inno Setup Installation from [code].
function RepairRemove_NextButtonClick(Page: TWizardPage): Boolean;
begin
if RemoveButton.Checked then
begin
{ Uninstall here }
{ And abort installer }
ExitProcess(1);
end;
Result := True;
end;

Can I obtain information about the windows explorer tree (left pane)?

Is it possible to obtain information about the Windows Explorer tree (what nodes are currently expanded, when a node is expanded etc.)?
Starting from Vista there is official way to communicate with tree in Explorer window. This way uses INameSpaceTreeControl interface.
If you want to get INameSpaceTreeControl from external app you must:
1) Get IDispatch of shell window:
var
ShellWindows: IShellWindows;
i: Integer;
Dispatch: IDispatch;
SL: TStrings;
begin
OleCheck(CoCreateInstance(CLASS_ShellWindows, nil, CLSCTX_INPROC_SERVER or CLSCTX_LOCAL_SERVER, IShellWindows, ShellWindows));
try
for i := ShellWindows.Count - 1 downto 0 do
begin
Dispatch := ShellWindows.Item(i);
try
SL := CreateNodeList(Dispatch);
try
Memo1.Lines.Assign(SL);
finally
SL.Free;
end;
Exit;
finally
Dispatch := nil;
end;
end;
finally
ShellWindows := nil;
end;
end;
2) Query IServiceProvider from IDispatch.
3) Query INameSpaceTreeControl from IServiceProvider.
4) After this you can enum elements of tree. I used the following algorithm:
function GetItemName(AShellItem: IShellItem): UnicodeString;
var
Name: PWideChar;
begin
OleCheck(AShellItem.GetDisplayName(SIGDN_NORMALDISPLAY, Name));
try
Result := Name;
finally
CoTaskMemFree(Name);
end;
end;
function GetLevelSpaces(ALevel: Integer): UnicodeString;
var
i: Integer;
begin
Result := '';
for i := 0 to ALevel - 1 do
Result := Result + ' ';
end;
function CalcLavel(AShellItem: IShellItem): Integer;
var Parent: IShellItem;
begin
Result := 0;
if Succeeded(AShellItem.GetParent(Parent)) then
try
Inc(Result);
Result := Result + CalcLavel(Parent);
finally
Parent := nil;
end;
end;
function GetExpanded(ATree: INameSpaceTreeControl; AItem: IShellItem): WideChar;
var
State: DWORD;
begin
OleCheck(ATree.GetItemState(AItem, NSTCIS_EXPANDED, State));
if State and NSTCIS_EXPANDED <> 0 then Result := '+'
else Result := '-';
end;
function CreateNodeList(ADispatch: IDispatch): TStrings;
var
ServiceProvider: IServiceProvider;
Tree: INameSpaceTreeControl;
L: Integer;
ShellItem, ShellItem2: IShellItem;
begin
OleCheck(ADispatch.QueryInterface(IServiceProvider, ServiceProvider));
try
OleCheck(ServiceProvider.QueryService(SID_SNavigationPane, INameSpaceTreeControl, Tree));
try
Result := TStringList.Create;
try
if Succeeded(Tree.GetNextItem(nil, NSTCGNI_CHILD, ShellItem)) then
repeat
try
L := CalcLavel(ShellItem);
Result.Add(GetLevelSpaces(L - 1) + GetExpanded(Tree, ShellItem) + ' ' + GetItemName(ShellItem));
finally
ShellItem2 := ShellItem;
ShellItem := nil;
end;
until Failed(Tree.GetNextItem(ShellItem2, NSTCGNI_NEXTVISIBLE, ShellItem));
finally
ShellItem2 := nil;
end;
finally
Tree := nil;
end;
finally
ServiceProvider := nil;
end;
end;
Result:
If you want to subscribe to tree actions use INameSpaceTreeControl.TreeAdvise.

inno setup custom page with checkbox and dropdown list

Is it possible to have a custom page with a drop down list, check boxes, and a button possibly changing the check boxes based on what is chosen from the drop down list. The button will just be used to display a readme text file. I am really not familiar with python scripting but have managed to create a drop down list.
You might take a script like this as an inspiration:
[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName={pf}\My Program
OutputDir=userdocs:Inno Setup Examples Output
[Files]
Source: "Readme.txt"; Flags: dontcopy
[Code]
var
Button: TNewButton;
ComboBox: TNewComboBox;
CheckBox1: TNewCheckBox;
CheckBox2: TNewCheckBox;
CustomPage: TWizardPage;
procedure ComboBoxChange(Sender: TObject);
begin
case ComboBox.ItemIndex of
0:
begin
CheckBox1.Checked := True;
CheckBox2.Checked := False;
end;
1:
begin
CheckBox1.Checked := False;
CheckBox2.Checked := True;
end;
2:
begin
CheckBox1.Checked := True;
CheckBox2.Checked := True;
end;
3:
begin
CheckBox1.Checked := False;
CheckBox2.Checked := False;
end;
end;
end;
procedure ButtonClick(Sender: TObject);
var
ErrorCode: Integer;
begin
ExtractTemporaryFile('Readme.txt');
if not ShellExec('', ExpandConstant('{tmp}\Readme.txt'), '', '',
SW_SHOW, ewNoWait, ErrorCode)
then
MsgBox(SysErrorMessage(ErrorCode), mbError, MB_OK);
end;
procedure InitializeWizard;
var
DescLabel: TLabel;
begin
CustomPage := CreateCustomPage(wpSelectDir, 'Caption', 'Description');
DescLabel := TLabel.Create(WizardForm);
DescLabel.Parent := CustomPage.Surface;
DescLabel.Left := 0;
DescLabel.Top := 0;
DescLabel.Caption := 'Select an item...';
ComboBox := TNewComboBox.Create(WizardForm);
ComboBox.Parent := CustomPage.Surface;
ComboBox.Left := 0;
ComboBox.Top := DescLabel.Top + DescLabel.Height + 6;
ComboBox.Width := 220;
ComboBox.Style := csDropDownList;
ComboBox.Items.Add('Check CheckBox1');
ComboBox.Items.Add('Check CheckBox2');
ComboBox.Items.Add('Check CheckBox1 and CheckBox2');
ComboBox.Items.Add('Uncheck CheckBox1 and CheckBox2');
ComboBox.OnChange := #ComboBoxChange;
CheckBox1 := TNewCheckBox.Create(WizardForm);
CheckBox1.Parent := CustomPage.Surface;
CheckBox1.Left := 0;
CheckBox1.Top := ComboBox.Top + ComboBox.Height + 6;
CheckBox1.Caption := 'CheckBox1';
CheckBox2 := TNewCheckBox.Create(WizardForm);
CheckBox2.Parent := CustomPage.Surface;
CheckBox2.Left := 0;
CheckBox2.Top := CheckBox1.Top + CheckBox1.Height + 6;
CheckBox2.Caption := 'CheckBox2';
Button := TNewButton.Create(WizardForm);
Button.Parent := CustomPage.Surface;
Button.Left := 0;
Button.Top := CheckBox2.Top + CheckBox2.Height + 6;
Button.Caption := 'Readme';
Button.OnClick := #ButtonClick;
end;

Is It Possible To Change The Font Colour of a TTabSheet Tab Caption

Just a follow up question to this one here => link
Is it possible to change the text colour of a TabSheet caption to another colour (eg. White) and change the font style to 'bold'?
Maybe this might give you such inspiration. Again, please note this will work only on Windows and with themes disabled in your application.
uses
ComCtrls, Windows, LCLType;
type
TPageControl = class(ComCtrls.TPageControl)
private
procedure CNDrawItem(var Message: TWMDrawItem); message WM_DRAWITEM;
protected
procedure CreateParams(var Params: TCreateParams); override;
end;
implementation
procedure TPageControl.CreateParams(var Params: TCreateParams);
begin
inherited CreateParams(Params);
with Params do
begin
if not (csDesigning in ComponentState) then
Style := Style or TCS_OWNERDRAWFIXED;
end;
end;
procedure TPageControl.CNDrawItem(var Message: TWMDrawItem);
var
FontHandle: HFONT;
FontColor: COLORREF;
FontObject: TLogFont;
BrushColor: COLORREF;
BrushHandle: HBRUSH;
begin
with Message.DrawItemStruct^ do
begin
GetObject(Font.Handle, SizeOf(FontObject), #FontObject);
case itemID of
0:
begin
BrushColor := RGB(235, 24, 33);
FontColor := clWhite;
FontObject.lfWeight := FW_NORMAL;
FontObject.lfItalic := 0;
end;
1:
begin
BrushColor := RGB(247, 200, 34);
FontColor := clGreen;
FontObject.lfWeight := FW_NORMAL;
FontObject.lfItalic := 1;
end;
2:
begin
BrushColor := RGB(178, 229, 26);
FontColor := clGreen;
FontObject.lfWeight := FW_BOLD;
FontObject.lfItalic := 1;
end
else
BrushColor := ColorToRGB(clBtnFace);
end;
BrushHandle := CreateSolidBrush(BrushColor);
FillRect(hDC, rcItem, BrushHandle);
FontHandle := CreateFontIndirect(FontObject);
try
SelectObject(hDC, FontHandle);
SetTextColor(hDC, FontColor);
SetBkMode(hDC, TRANSPARENT);
DrawTextEx(hDC, PChar(Page[itemID].Caption), -1, rcItem, DT_CENTER or
DT_VCENTER or DT_SINGLELINE, nil);
finally
DeleteObject(FontHandle);
end;
end;
Message.Result := 1;
end;
Here is how it looks like:
Replace hDc with _hDc
and drawtextex with drawtext and

Resources