Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Trucos (https://www.clubdelphi.com/foros/forumdisplay.php?f=52)
-   -   Cómo abrir una URL con Microsoft Edge en Windows 10 (https://www.clubdelphi.com/foros/showthread.php?t=88805)

dec 03-08-2015 19:58:13

Cómo abrir una URL con Microsoft Edge en Windows 10
 
Hola a todos,

En Microsoft Windows 10 viene incorporado, además de Internet Explorer 11, otro navegador, Microsoft Edge. Buscando información sobre cómo abrir una determinada URL con este navegador, encontraremos que podemos usar la función "ShellExecute" (de toda la vida) proporcionando como argumento "FileName" una cadena similar a esta:

Código:

microsoft-edge:http://www.clubdelphi.com
Ya está. Ese es el truco. ¡¿Ese es el truco?!

Bueno, en realidad esto da para un poco más. Ponte en el caso de tener que detectar si Microsoft Edge está instalado o no en el sistema. Como ves arriba, no invocamos ningún ejecutable, y, de hecho, en mi sistema aparecen tres "MicrosoftEdge.exe" en lugares diferentes. Así que, ¿cómo saber que Microsoft Edge está disponible?

La forma de hacerlo (o al menos lo que yo he hecho) ha sido averiguando la versión de Windows en que corre mi programa. Ahora mismo, al menos, Microsoft Edge está disponible sólo en Windows 10, de modo que lo que tenemos que averiguar es si nuestro programa corre o no en Windows 10.

Y ahora sí, ese es el truco. ¡¿Ese es el truco?!

Bueno (bueno estaba y se murió, ¡pues no estaría tan bueno!), en realidad esto da para un poco más todavía. Resulta que hay cierto lío montado con el asunto de averiguar la versión de Windows desde nuestros programas. Microsoft ha llevado a cabo ciertos cambios (que tampoco conozco a fondo) en la forma en que se manejan las versiones de Windows.

De este modo, un programa escrito en Delphi XE2 (al menos) en Windows 10 nos dará datos erróneos si tratamos de usar el registro "SysUtils.TOSVersion", por ejemplo, o bien otras funciones del API de Windows para obtener la versión del sistema. Con nuestros propios ojos podremos ver que ejecutándose nuestro programa en Windows 10 este nos informa de que corre en Windows 8.

Buscando por internet encontré una unidad que implementa ciertas funciones de un nuevo API de Windows disponibles a partir de Windows 10, y que, sin atribuirme autoría alguna (creo que es una copia de cierto código C que también he podido ver, pero, desconozco la autoría) aquí están porque igual pueden serle a alguien tan útiles como a mí mismo:

Código Delphi [-]
unit AppBuilder.Shared.WindowsVersion;

interface

uses
  // Delphi
  Winapi.Windows,
  System.SysUtils;

const
  VER_SERVICEPACKMAJOR = $0000010;
  VER_MAJORVERSION = $0000002;
  VER_MINORVERSION = $0000001;
  VER_NT_WORKSTATION = 1;
  VER_PRODUCT_TYPE = $80;

  VER_EQUAL = 1;
  VER_GREATER = 2;
  VER_GREATER_EQUAL = 3;
  VER_LESS = 4;
  VER_LESS_EQUAL = 5;
  VER_AND = 6;
  VER_OR = 7;
  WIN32_WINNT_NT4 = $0400;
  WIN32_WINNT_WIN2K = $0500;
  WIN32_WINNT_WINXP = $0501;
  WIN32_WINNT_WS03 = $0502;
  WIN32_WINNT_VISTA = $0600;
  WIN32_WINNT_WS08 = $0600;
  WIN32_WINNT_LONGHORN = $0600;
  WIN32_WINNT_WIN7 = $0601;
  WIN32_WINNT_WIN8 = $0602;
  WIN32_WINNT_WINBLUE = $0603;
  WIN32_WINNT_WIN10 = $0A00;

  kernel32 = 'kernel32.dll';

type
  OSVERSIONINFOEX = record
    dwOSVersionInfoSize: DWord;
    dwMajorVersion: DWord;
    dwMinorVersion: DWord;
    dwBuildNumber: DWord;
    dwPlatformID: DWord;
    szCSDVersion: array [1 .. 128] of char;
    wServicePackMajor: Word;
    wServicePackMinor: Word;
    wSuiteMask: Word;
    wProductType: Byte;
    wReserved: Byte;
  end;

function IsWindowsXPOrGreater: Bool; stdcall;
function IsWindowsXPSP1OrGreater: Bool; stdcall;
function IsWindowsXPSP2OrGreater: Bool; stdcall;
function IsWindowsXPSP3OrGreater: Bool; stdcall;
function IsWindowsVistaOrGreater: Bool; stdcall;
function IsWindowsVistaSP1OrGreater: Bool; stdcall;
function IsWindowsVistaSP2OrGreater: Bool; stdcall;
function IsWindows7OrGreater: Bool; stdcall;
function IsWindows7SP1OrGreater: Bool; stdcall;
function IsWindows8OrGreater: Bool; stdcall;
function IsWindows8Point1OrGreater: Bool; stdcall;
function IsWindows10OrGreater: Bool; stdcall;
function IsWindowsServer: Bool; stdcall;

function IsWindowsVersionOrGreater(wMajorVersion, wMinorVersion,
  wServicePackMajor: Word): Bool; stdcall;

implementation

function VerifyVersionInfo(var LPOSVERSIONINFOEX: OSVERSIONINFOEX;
  dwTypeMask: DWord; dwlConditionMask: int64): Bool; stdcall;
  external kernel32 name 'VerifyVersionInfoA';

function VerSetConditionMask(dwlConditionMask: int64; dwTypeBitMask: DWord;
  dwConditionMask: Byte): int64; stdcall; external kernel32;

function IsWindowsVersionOrGreater;
var
  osvi: OSVERSIONINFOEX;
  condmask: int64;
begin
  FillChar(osvi, sizeof(osvi), 0);
  osvi.dwOSVersionInfoSize := sizeof(osvi);
  FillChar(condmask, 8, 0);
  condmask := VerSetConditionMask(condmask, VER_MAJORVERSION,
    VER_GREATER_EQUAL);
  condmask := VerSetConditionMask(condmask, VER_MINORVERSION,
    VER_GREATER_EQUAL);
  condmask := VerSetConditionMask(condmask, VER_SERVICEPACKMAJOR,
    VER_GREATER_EQUAL);
  osvi.dwMajorVersion := wMajorVersion;
  osvi.dwMinorVersion := wMinorVersion;
  osvi.wServicePackMajor := wServicePackMajor;
  Result := VerifyVersionInfo(osvi, VER_MAJORVERSION or VER_MINORVERSION or
    VER_SERVICEPACKMAJOR, condmask) <> false;
end;

function IsWindowsXPOrGreater;
begin
  Result := IsWindowsVersionOrGreater(HiByte(WIN32_WINNT_WINXP),
    LOBYTE(WIN32_WINNT_WINXP), 0);
end;

function IsWindowsXPSP1OrGreater;
begin
  Result := IsWindowsVersionOrGreater(HiByte(WIN32_WINNT_WINXP),
    LOBYTE(WIN32_WINNT_WINXP), 1);
end;

function IsWindowsXPSP2OrGreater;
begin
  Result := IsWindowsVersionOrGreater(HiByte(WIN32_WINNT_WINXP),
    LOBYTE(WIN32_WINNT_WINXP), 2);
end;

function IsWindowsXPSP3OrGreater;
begin
  Result := IsWindowsVersionOrGreater(HiByte(WIN32_WINNT_WINXP),
    LOBYTE(WIN32_WINNT_WINXP), 3);
end;

function IsWindowsVistaOrGreater;
begin
  Result := IsWindowsVersionOrGreater(HiByte(WIN32_WINNT_VISTA),
    LOBYTE(WIN32_WINNT_VISTA), 0);
end;

function IsWindowsVistaSP1OrGreater;
begin
  Result := IsWindowsVersionOrGreater(HiByte(WIN32_WINNT_VISTA),
    LOBYTE(WIN32_WINNT_VISTA), 1);
end;

function IsWindowsVistaSP2OrGreater;
begin
  Result := IsWindowsVersionOrGreater(HiByte(WIN32_WINNT_VISTA),
    LOBYTE(WIN32_WINNT_VISTA), 2);
end;

function IsWindows7OrGreater;
begin
  Result := IsWindowsVersionOrGreater(HiByte(WIN32_WINNT_WIN7),
    LOBYTE(WIN32_WINNT_WIN7), 0);
end;

function IsWindows7SP1OrGreater;
begin
  Result := IsWindowsVersionOrGreater(HiByte(WIN32_WINNT_WIN7),
    LOBYTE(WIN32_WINNT_WIN7), 0);
end;

function IsWindows8OrGreater;
begin
  Result := IsWindowsVersionOrGreater(HiByte(WIN32_WINNT_WIN8),
    LOBYTE(WIN32_WINNT_WIN8), 0);
end;

function IsWindows8Point1OrGreater;
begin
  Result := IsWindowsVersionOrGreater(HiByte(WIN32_WINNT_WINBLUE),
    LOBYTE(WIN32_WINNT_WINBLUE), 0);
end;

function IsWindows10OrGreater;
begin
  Result := IsWindowsVersionOrGreater(HiByte(WIN32_WINNT_WIN10),
    LOBYTE(WIN32_WINNT_WIN10), 0);
end;

function IsWindowsServer;
var
  osvi: OSVERSIONINFOEX;
  condmask: int64;
begin
  FillChar(osvi, sizeof(osvi), 0);
  osvi.dwOSVersionInfoSize := sizeof(osvi);
  FillChar(condmask, 8, 0);
  condmask := VerSetConditionMask(condmask, VER_PRODUCT_TYPE, VER_EQUAL);
  osvi.wProductType := VER_NT_WORKSTATION;
  Result := not VerifyVersionInfo(osvi, VER_PRODUCT_TYPE, condmask) <> false;
end;

end.

Así que en principio con estas funciones podemos averiguar si nuestro programa correo finalmente en Windows 10, de modo que podamos abrir una URL con el navegador Microsoft Edge, por ejemplo. Sin embargo, ni siquiera estas funciones ofrecerán los resultados esperados... ¡este truco no va a terminar nunca!

En efecto, tenemos que utilizar un manifiesto para nuestro programa diferente del que incluye Delphi XE2, al menos, porque, de lo contrario, las funciones anteriores (u otras) ofrecerán resultados equivocados, por lo menos, confundirán Windows 10 con Windows 8. Básicamente, podemos partir del manifiesto que usa Delphi por defecto:

Código:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
 <dependency>
  <dependentAssembly>
    <assemblyIdentity
      type="win32"
      name="Microsoft.Windows.Common-Controls"
      version="6.0.0.0"
      publicKeyToken="6595b64144ccf1df"
      language="*"
      processorArchitecture="*"/>
  </dependentAssembly>
 </dependency>
 <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
  <security>
    <requestedPrivileges>
      <requestedExecutionLevel
        level="asInvoker"
        uiAccess="false"/>
      </requestedPrivileges>
  </security>
 </trustInfo>
</assembly>

A este manifiesto hemos de añadir una opción de compatibilidad al menos: para indicar que nuestro programa requiere de las nuevas características de Windows 10:

Código:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
 <dependency>
  <dependentAssembly>
    <assemblyIdentity
      type="win32"
      name="Microsoft.Windows.Common-Controls"
      version="6.0.0.0"
      publicKeyToken="6595b64144ccf1df"
      language="*"
      processorArchitecture="*"/>
  </dependentAssembly>
 </dependency>
 <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
  <security>
    <requestedPrivileges>
      <requestedExecutionLevel
        level="asInvoker"
        uiAccess="false"/>
      </requestedPrivileges>
  </security>
 </trustInfo>
 <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
  <application>
  <!--This Id value indicates the application supports Windows 7 functionality-->
  <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
  <!--This Id value indicates the application supports Windows 8 functionality-->
  <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
  <!--This Id value indicates the application supports Windows 8.1 functionality-->
  <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
  <!-- This Id value indicates the application supports Windows 10 functionality -->
  <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
  </application>
 </compatibility>
</assembly>

El manifiesto anterior es el que yo he empezado a usar en mis programas y, una vez lo añadamos a los mismos:



... ahora sí, podremos usar las funciones anteriores para averiguar si nuestro programa corre en Windows 10.

¡Fin del truco!

En conclusión:

Por lo que parece, a partir de Windows 10 (que yo sepa) los programas que no incluyan en su manifiesto la compatibilidad con dicha versión de Windows, tampoco podrán delegar en la versión del sistema operativo, o sea, el programa no tendrá modo de saber si corre en Windows 10, al menos usando los recursos y funciones habituales.

nlsgarcia 03-08-2015 22:15:34

David,

Cita:

Empezado por dec
...lo que tenemos que averiguar es si nuestro programa corre o no en Windows 10...

:rolleyes:

Revisa este código:
Código Delphi [-]
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ActiveX, ComObj;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

// Obtiene la versión de Windows vía WMI
function GetWindowsVersion : String;
const
  wbemFlagForwardOnly = $00000020;

var
  FSWbemLocator : OLEVariant;
  FWMIService : OLEVariant;
  FWbemObjectSet : OLEVariant;
  FWbemObject : OLEVariant;
  oEnum : IEnumvariant;
  iValue : LongWord;
  SQLWMI : String;

begin

  // Obtiene Acceso a WMI
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');

  // Obtiene Acceso al NameSpace root\CIMV2 localmente que contiene la Clase Win32_Process
  FWMIService := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');

  // Contruye la Consulta SQL WMI (WQL) a la Clase Win32_Process
  SQLWMI := 'SELECT * FROM Win32_OperatingSystem';

  // Ejecuta la Consulta
  FWbemObjectSet := FWMIService.ExecQuery(SQLWMI,'WQL',wbemFlagForwardOnly);

  // Interface a los objetos COM de la consulta por medio de enumeración
  oEnum := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant;

  // Accesa las propiedades de los objetos de la enumeración
  if oEnum.Next(1, FWbemObject, iValue) = 0 then
  begin
     Result := Format('%s %s',[FWbemObject.Caption, FWbemObject.Version]);
     FWbemObject:=Unassigned;
  end

end;

procedure TForm1.Button1Click(Sender: TObject);
begin
   MessageDlg(GetWindowsVersion,mtInformation,[mbOK],0);
end;

end.
El código anterior en Delphi 7 sobre Windows 7 Professional x32, Permite por medio de Windows Management Instrumentation (WMI) obtener la versión de Windows, como se muestra en la siguiente imagen:



Espero sea útil :)

Nelson.

dec 03-08-2015 22:50:28

Hola,

Gracias por el aporte. Había leído que a través de WMI era también posible hacerlo, pero, no sé porqué he preferido la otra opción, ¿quizá porque me parece más rápida de algunas pruebas que hice hace tiempo con WMI? Ojo que esto no quita que sea otra posible solución y que además lo mío es más bien una impresión que puede estar equivocada. :)

P.D. No había probado con WMI, pero, acabo de hacerlo y parece que funciona sin necesidad de cambiar el manifiesto que por defecto incorpora Delphi XE2.

nlsgarcia 20-08-2015 06:12:21

Club Delphi,

Cita:

Empezado por dec
...lo que tenemos que averiguar es si nuestro programa corre o no en Windows 10...

:rolleyes:


Tomado de: Getting the System Version

Revisa este código:
Código Delphi [-]
unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, System.StrUtils;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

// Obtiene la versión de Windows vía APIs
function GetWindowsKernelVersion : String;
const
   FileName : String = 'C:\Windows\System32\Kernel32.dll';

type
   PLanguageCodepage = ^TLanguageCodepage;
   TLanguageCodepage = record
      Language : Word;
      CodePage : Word;
   end;

var
   None, Size: LongWord;
   Buffer, Ptr : Pointer;
   Lang, AuxStr, Version : String;
   WinList : TStringList;
   P : Integer;

   function IsWindowsServer : Boolean;
   var
      OSVersion : OSVersionInfoEX;
      ConditionMask : Int64;
   begin
      FillChar(OSVersion, SizeOf(OSVersion), 0);
      OSVersion.dwOSVersionInfoSize := SizeOf(OSVersion);
      OSVersion.wProductType := VER_NT_WORKSTATION;
      ConditionMask := VerSetConditionMask(ConditionMask, VER_PRODUCT_TYPE, VER_EQUAL);
      Result := not VerifyVersionInfo(OSVersion, VER_PRODUCT_TYPE, ConditionMask);
   end;

begin

   Size := GetFileVersionInfoSize(PChar(FileName), None);

   if Size = 0 then
      Exit;

   WinList := TStringList.Create;

   WinList.Add('10.0=Windows 10');
   WinList.Add('Svr 10.0=Windows Server');
   WinList.Add('6.3=Windows 8.1');
   WinList.Add('Svr 6.3=Windows Server 2012 R2');
   WinList.Add('6.2=Windows 8');
   WinList.Add('Svr 6.2=Windows Server 2012');
   WinList.Add('6.1=Windows 7');
   WinList.Add('Svr 6.1=Windows Server 2008 R2');
   WinList.Add('6.0=Windows Vista');
   WinList.Add('Svr 6.0=Windows Server 2008');
   WinList.Add('5.2=Windows XP x64');
   WinList.Add('Svr 5.2=Windows Server 2003');
   WinList.Add('5.1=Windows XP');
   WinList.Add('5.0=Windows 2000');
   WinList.Add('4.0=Windows NT');

   Result := '0.0.0.0';

   GetMem(Buffer, Size);

   try
      GetFileVersionInfo(PChar(FileName), 0, Size, Buffer);

      VerQueryValue(Buffer, '\VarFileInfo\Translation\', Ptr, Size);

      Lang := Format('%.4x%.4x', [PLanguageCodepage(Ptr)^.Language, PLanguageCodepage(Ptr)^.CodePage]);

      if VerQueryValue(Buffer, PChar('\StringFileInfo\' + Lang + '\FileVersion'), Ptr, Size) then
      begin
         AuxStr := PChar(Ptr);
         P := PosEx('.',AuxStr,Pos('.',AuxStr)+1);
         Version := Copy(AuxStr,1,P-1);
         if IsWindowsServer then
            Result := WinList.Values['Svr ' + Version] + ' ' + Version
         else
            Result := WinList.Values[Version] + ' ' + Version;
      end;
   finally
      FreeMem(Buffer);
      WinList.Free;
   end;

end;

procedure TForm1.Button1Click(Sender: TObject);
begin
   TaskMessageDlg('Windows Version', GetWindowsKernelVersion, mtInformation, [mbOK], 0);
end;

end.
El código anterior en Delphi XE7 sobre Windows 7 Professional x32, Permite por medio de funciones de Windows (APIs) obtener la versión del SO, como se muestra en la siguiente imagen:



Notas:

1- Esta función es un bit más compleja y rápida que la planteada en el Msg #2.

2- La función basada en WMI del Msg #2, es más simple y expresiva en información.

3- Ambas funciones detectan correctamente la versión de Windows.

Información relacionada:
Espero sea útil :)

Nelson.


La franja horaria es GMT +2. Ahora son las 12:45:21.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi