Jump to content
ChrisChuah

Any delphi components for VNC or RemoteDesktop?

Recommended Posts

Hi

Is there a ActiveX or native component for VNC Client or Remote Desktop client so that the application can connect to the VNC server running on Ubuntu 22 and above.

The VNC ActiveX component that i have been using since Delphi 6 is not able to properly show the Ubuntu desktop version 22. But it is able to display properly for Ubuntu 20.

 

Please advise

 

regards

chris

Share this post


Link to post
18 minutes ago, Rollo62 said:

I think you mean this one: https://github.com/CloudDelphi/RTC-Portal-VCL

But that is neither VNC nor RDP, which is what the OP asked for.

 

For RDP there is an ActiveX but I don't know what it does. I've never used it.
https://learn.microsoft.com/en-us/windows/win32/termserv/remote-desktop-activex-control

  • Like 1

Share this post


Link to post

AFAIU mRemoteNG uses some kind of component or a lib for VNC so probably there is one. Try to check that lib. But you'll likely have to write Delphi wrapper by yourself

Share this post


Link to post
3 hours ago, ChrisChuah said:

Different layers. I haven't used either but AFAIK RTC Portal is a layer on top of RTC SDK.

Note though that it's a completely proprietary protocol. You need something that implements the RFB protocol (which is what VNC uses).

Share this post


Link to post

so meaning there is no component that i can use readily to plug into a Delphi form so that i can connect to a VNC server isnt it?

still have to do more work on it. oh mine..

then will need more time to research on these few github sources

 

Share this post


Link to post
On 10/31/2023 at 1:52 PM, Anders Melander said:

For RDP there is an ActiveX but I don't know what it does. I've never used it.
https://learn.microsoft.com/en-us/windows/win32/termserv/remote-desktop-activex-control

It indeed exists, and works as advertised. I grabbed installation instructions from somewhere a long time ago:

 

- Component -> Import Component -> Import ActiveX Control -> Select Terminal Services (mstscax.dll)
- Palette page: MsTSC, unit dir name: Delphi Lib folder, Search path: empty. Check Generate component wrappers
- Install to New package
- Enter the same name (MsTSCLib_TLB.dproj) under Delphi Lib folder
- Try to build package just to fail
- Change Property type of ConnectWithEndpoint to "OleVariant", build package again
- Right-click on MsTSCLib_TLB.bpl in Project manager and select "Install"

 

After this different versions of the control will appear on the palette and everything can be set (RD gateway, compression, audio redirection, key capture, etc.) via properties what mstsc.exe allows.

Kinda handy stuff.

Share this post


Link to post

Hi 

Last time, since Delphi 6, i managed to download an VNCX.dll from internet and i was able to embed it into my Delphi 6 application.

Now, i tried to import this same component into Delphi 11, Delphi 11 managed to convert into the TLB files and was able to compile it and add to the Palette.

When i create a new Windows VCL app and add that VNC ActiveX component into the form, Delphi 11 will crash.

Is there a way to find out why Delphi 11 crashed?

 

regards

chris

 

Share this post


Link to post

hi

Also the activeX comes in 32 bit and 64 bit version

when i do a regsvr32 vnc.dll and regsvr32 vnc64.dll, Delphi only shows the 32 bit activeX when importing.

how can delphi able to use the 64bit dll?

please advise

 

 

Share this post


Link to post
2 hours ago, ChrisChuah said:

how can delphi able to use the 64bit dll?

Is the Delphi app 64-bit?

Share this post


Link to post

Delphi can compile app into 64bit isnt it?

If so, can my Delphi 64bit app run the 32bit dll or does it require the 64bit dll?

 

Share this post


Link to post
5 hours ago, ChrisChuah said:

Delphi can compile app into 64bit isnt it?

If so, can my Delphi 64bit app run the 32bit dll or does it require the 64bit dll?

 

64 bit app can run only 64 bit dll, and 32 bit app can run only 32 bit dll. But you can "connect" to 32 or 64 bit Com Object if it is out-of-process, from any process (both 32 and 64 bit).

Edited by DelphiUdIT

Share this post


Link to post

Thank you.

I managed to connect to the 64 bit dll file although the Delphi IDE registered the 32 bit dll as activeX component.

until now, i am still learning how to go about doing things in delphi

 

regards

chris

 

Share this post


Link to post
On 03/11/2023 at 14:34, aehimself said:

Ele realmente existe e funciona como anunciado. Peguei instruções de instalação em algum lugar há muito tempo:

 

- Componente -> Importar Componente -> Importar Controle ActiveX -> Selecionar Serviços de Terminal (mstscax.dll)
- Página da paleta: MsTSC, nome do diretório da unidade: pasta Delphi Lib, caminho de pesquisa: vazio. Marque a opção Gerar wrappers de componentes
- Instalar em um novo pacote
- Digite o mesmo nome (MsTSCLib_TLB.dproj) na pasta Delphi Lib
- Tente compilar o pacote, mas não consiga
- Altere o tipo de propriedade de ConnectWithEndpoint para "OleVariant", compile o pacote novamente
- Clique com o botão direito do mouse em MsTSCLib_TLB.bpl no Gerenciador de Projetos e selecione "Instalar"

 

Depois disso, diferentes versões do controle aparecerão na paleta e tudo poderá ser definido (gateway RD, compactação, redirecionamento de áudio, captura de teclas, etc.) por meio de propriedades permitidas pelo mstsc.exe.

Coisa meio útil.

I've been trying to implement this method for about two weeks, using MsTSCLib_TLB.pas.
My problem may be my expectations of what could be done, as I would like an application like Remote Desktop Manager (RDM). I'm managing to make the connection and everything, but I'm stuck on these two validation tabs, maybe it's something in Windows, the big issue is that I've tried using several things and different ways, but I can't make something fluid and automatic, just by clicking and connecting.

Print 1.png

Print 2.png

Share this post


Link to post

The first window warns about "invalidity" of certificate and approval of access for a specific function (drive mapping maybe?). You will not be able to bypass this (you can ignore the certificate so the warning only comes back once the cert is renewed).

The second one you can bypass by specifying the username and password.

This is how my tabbed remote access application sets up MsTscAx controls for RDP connections:

  If Self.Credential <> nil Then
  Begin
    If Not Self.Credential.DomainName.IsEmpty Then
      _rdp.Domain := Self.Credential.DomainName;

    If Not Self.Credential.UserName.IsEmpty Then
      _rdp.UserName := Self.Credential.UserName;

    If Not Self.Credential.Password.IsEmpty Then
      _rdp.AdvancedSettings7.ClearTextPassword := Self.Credential.Password;
  End;

I suggest you check all the .AdvancedSettingsxxx options. There are plenty of tasty settings there to fulfill your needs.

Share this post


Link to post
18 hours ago, aehimself said:

The first window warns about "invalidity" of certificate and approval of access for a specific function (drive mapping maybe?). You will not be able to bypass this (you can ignore the certificate so the warning only comes back once the cert is renewed).

The second one you can bypass by specifying the username and password.

This is how my tabbed remote access application sets up MsTscAx controls for RDP connections:


  If Self.Credential <> nil Then
  Begin
    If Not Self.Credential.DomainName.IsEmpty Then
      _rdp.Domain := Self.Credential.DomainName;

    If Not Self.Credential.UserName.IsEmpty Then
      _rdp.UserName := Self.Credential.UserName;

    If Not Self.Credential.Password.IsEmpty Then
      _rdp.AdvancedSettings7.ClearTextPassword := Self.Credential.Password;
  End;

I suggest you check all the .AdvancedSettingsxxx options. There are plenty of tasty settings there to fulfill your needs.

Can you help me? (Don't mind the writing and indentation of the code, it's really bad, this language is new to me)
 

unit tbConnectRDP;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ComCtrls, Vcl.ExtCtrls, MSTSCLib_TLB, ActiveX, ComObj,
  Vcl.OleServer, Vcl.OleCtrls, Generics.Collections;

type
  TConnectRDP = class(TForm)
    treeListServer: TTreeView;
    listServerSplitter: TSplitter;
    pageControlViewServer: TPageControl;
    procedure ConectarRDP( const IP, Usuario, Senha: string );
    procedure treeListServerDblClick(Sender: TObject);
    procedure addServersListTree;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    FRDPConnections: TObjectList<TMsRdpClient10>;
    procedure RDPDisconnected(Sender: TObject; discReason: Integer);
    procedure pageControlViewServerDrawTab(Control: TCustomTabControl; TabIndex: Integer; const Rect: TRect; Active: Boolean);
    procedure pageControlViewServerMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  public
    { Public declarations }
  end;

var
  ConnectRDP: TConnectRDP;

implementation

{$R *.dfm}

uses
  tbMenu;

   procedure TConnectRDP.FormCreate(Sender: TObject);
   begin
      CoInitialize(nil);
      FRDPConnections := TObjectList<TMsRdpClient10>.Create(True); // True para liberar objetos ao destruir
      addServersListTree;
      pageControlViewServer.OwnerDraw := True;
      pageControlViewServer.OnDrawTab := pageControlViewServerDrawTab;
      pageControlViewServer.OnMouseDown := pageControlViewServerMouseDown;
   end;

   procedure TConnectRDP.FormDestroy(Sender: TObject);
   begin
      FRDPConnections.Free;
      CoUninitialize;
   end;

   procedure TConnectRDP.addServersListTree;
   var
     Grupo: TTreeNode;
   begin
     // Limpa a TreeView antes de adicionar
     treeListServer.Items.Clear;

     // Adiciona um grupo chamado "Produção"
     Grupo := treeListServer.Items.Add(nil, 'Produção');
     treeListServer.Items.AddChild(Grupo, '10.1.1.96');
     treeListServer.Items.AddChild(Grupo, '10.1.1.200');
     treeListServer.Items.AddChild(Grupo, '10.1.1.233');

     // Adiciona outro grupo chamado "Testes"
     Grupo := treeListServer.Items.Add(nil, 'Testes');
     treeListServer.Items.AddChild(Grupo, '192.168.100.10');

     // Expande os grupos para facilitar visualização
   //  treeListServer.FullExpand;
   end;


   procedure TConnectRDP.treeListServerDblClick(Sender: TObject);
   var
     ServerIP, Username, Password: string;
   begin
     if not Assigned(treeListServer.Selected) then Exit;
     if treeListServer.Selected.Parent = nil then Exit;  // evita grupo

     ServerIP := treeListServer.Selected.Text;
     Username := 'Administrador';
     Password := '!tsncs4606';

     ConectarRDP(ServerIP, Username, Password);
   end;

{   procedure TConnectRDP.ConectarRDP(const IP, Usuario, Senha: string);
   var
     Node: TTreeNode;
     NovaAba: TTabSheet;
     RDPClientLocal: TMsRdpClient10;
   begin
     Node := treeListServer.Selected;
     if (Node = nil) or (Node.Parent = nil) then Exit;

     NovaAba := TTabSheet.Create(pageControlViewServer);
     NovaAba.PageControl := pageControlViewServer;
     NovaAba.Caption := Node.Text;

     RDPClientLocal := TMsRdpClient10.Create(NovaAba);
     RDPClientLocal.Parent := NovaAba;
     RDPClientLocal.Align := alClient;
     RDPClientLocal.Visible := True;

     RDPClientLocal.OnDisconnected := RDPDisconnected;

     RDPClientLocal.UserName := Usuario;
     RDPClientLocal.Domain := '';
     RDPClientLocal.AdvancedSettings9.ClearTextPassword := Senha;
     RDPClientLocal.AdvancedSettings9.AuthenticationLevel := 0;
     RDPClientLocal.AdvancedSettings9.EnableCredSspSupport := True;
     RDPClientLocal.AdvancedSettings9.RedirectClipboard := False;

     RDPClientLocal.Server := IP;

//     FRDPConnections.Add(RDPClientLocal);

     try
       RDPClientLocal.Connect;
     except
       on E: Exception do
         ShowMessage('Erro ao conectar: ' + E.Message);
     end;
   end;     }

procedure TConnectRDP.RDPDisconnected(Sender: TObject; discReason: Integer);
begin
  ShowMessage('Desconectado. Motivo: ' + IntToStr(discReason));
end;

procedure TConnectRDP.ConectarRDP(const IP, Usuario, Senha: string);
var
  Node: TTreeNode;
  NovaAba: TTabSheet;
  RDPClientLocal: TMsRdpClient10;
  NonScriptable: IMsRdpClientNonScriptable5;
begin
  Node := treeListServer.Selected;
  if (Node = nil) or (Node.Parent = nil) then Exit;

  NovaAba := TTabSheet.Create(pageControlViewServer);
  NovaAba.PageControl := pageControlViewServer;
  NovaAba.Caption := Node.Text;

  RDPClientLocal := TMsRdpClient10.Create(NovaAba);
  RDPClientLocal.Parent := NovaAba;
  RDPClientLocal.Align := alClient;
  RDPClientLocal.Visible := True;

  RDPClientLocal.OnDisconnected := RDPDisconnected;

  // Configuração de automação total
  RDPClientLocal.UserName := Usuario;
  RDPClientLocal.Domain := '';
  RDPClientLocal.AdvancedSettings9.ClearTextPassword := Senha;
  RDPClientLocal.AdvancedSettings9.AuthenticationLevel := 0; // Ignora certificado
  RDPClientLocal.AdvancedSettings9.EnableCredSspSupport := True;

  // Configurações avançadas de prompt e credenciais via NonScriptable
  if Supports( RDPClientLocal, IMsRdpClientNonScriptable5, NonScriptable) then
  begin
    NonScriptable.Set_AllowPromptingForCredentials(False);
    NonScriptable.Set_PromptForCredentials(False);
    NonScriptable.Set_PromptForCredsOnClient(False);
    NonScriptable.Set_AllowCredentialSaving(True);
  end;

  // Redirecionamento (opcional)
  RDPClientLocal.AdvancedSettings9.RedirectDrives := False;
  RDPClientLocal.AdvancedSettings9.RedirectPrinters := False;
  RDPClientLocal.AdvancedSettings9.RedirectClipboard := false;

  RDPClientLocal.Server := IP;

  try
    RDPClientLocal.Connect;
  except
    on E: Exception do
      ShowMessage('Erro ao conectar: ' + E.Message);
  end;
end;

procedure TConnectRDP.pageControlViewServerDrawTab(Control: TCustomTabControl; TabIndex: Integer; const Rect: TRect; Active: Boolean);
var
  TabCaption: string;
  CloseRect: TRect;
begin
  TabCaption := pageControlViewServer.Pages[TabIndex].Caption;
  // Desenha o texto da aba
  Control.Canvas.TextRect( Rect, Rect.Left + 10, Rect.Top + 4, TabCaption );

  // Desenha o "X" no canto direito da aba
  CloseRect := Rect;
  CloseRect.Left := CloseRect.Right  - 25;
  CloseRect.Right := CloseRect.Right - 25;
  CloseRect.Top := CloseRect.Top + 4;
  CloseRect.Bottom := CloseRect.Bottom - 4;
  Control.Canvas.TextRect(CloseRect, CloseRect.Left, CloseRect.Top, 'X');
end;

procedure TConnectRDP.pageControlViewServerMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
  i: Integer;
  TabRect: TRect;
  CloseRect: TRect;
begin
  for i := 0 to pageControlViewServer.PageCount - 1 do
  begin
    TabRect := pageControlViewServer.TabRect(i);
    CloseRect := TabRect;
    CloseRect.Left := CloseRect.Right - 18;
    CloseRect.Right := CloseRect.Right - 4;
    if PtInRect(CloseRect, Point(X, Y)) then
    begin
      pageControlViewServer.Pages.Free;
      Break;
    end;
  end;
end;

end.

Share this post


Link to post

When experimenting with a new component I suggest a "barebone" example first. One control on the form, setting up and connecting in FormCreate.

I'm not going to recreate your form layout and filter out the essentials I'm sorry... I already showed how I'm doing it and it works fine.

 

Also keep in mind that by importing the MsTscAx control you are effectively using the current version available in your Windows setup: it can / might / surely will differ between versions, editions and even patch levels.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×