Archivi tag: Toolbar

Inno Setup & Browser Helper Objects & IE Toolbars

In un mio recente progetto, ho avuto la necessità di creare ,per Internet Explorer, un Browser Helper Object (un plugin che sfrutta le stesse interfacce e tecnologie delle Toolbar) che eseguisse delle operazioni custom su un particolare sito in ambiente Intranet.
La realizzazione del BHO, è relativamente semplice usando le interfacce IObjectWithSite e le direttive di interoperabilità del codice.
Per il setup invece è tutto particolarmente difficile. Le interfacce del BHO vanno registrate nel registry di Windows e rese accessibili al sistema di plugin di IE.
Per far questo ho usato un software free, INNO SETUP, che permette di generare degli installer a partire da uno script.
Inno Setup

Lo script, permette di definire il comportamento del setup, le informazioni da visualizzare nelle maschere, e tutte le operazioni da effettuare sul registry di Windows, compresa la problematica di differenze di posizionamento e nome di alcune voci tra i sistemi a 32 e a 64 bit. Il Bho di cui realizzo il setup è compilato in maniera da funzionare compatibilmente con tutti i sistemi e quindi richiede un setup compatibile sia con i sistemi a 32 che a 64 bit.

Lo script inizia con una serie di definizioni di costanti usate poi nel resto delle direttive, tra cui il nome della dll, il nome del namespace utilizzato, e il nome della classe interna che viene esposta al browser, contenente i metodi pubblici da utilizzare.

1
2
3
4
5
6
7
8
9
#define MyAppDescription "My Helper Objects"
#define MyAppName "MyBHO"
#define MyAppVersion "1.0.0.0"
#define MyAppPublisher "Metalide"
#define MyAppURL "http://www.metalide.com"
#define MyAppDllName "MyBHO.dll"
#define MyAppId "{A80C384E-4178-4AD0-85BC-3196241437C5}"
#define MyAppNamespace "MyBHO.MyHelperObject"
#define MyAppClass "MyBHOExtension"

Subito dopo si crea una sezione [Setup] per associare le costanti ai parametri dell’installer e altri attributi:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[Setup]
AppId={#MyAppName}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName={pf}\MyTools\MyHelperObjects
DefaultGroupName=My_IETOOLS
DisableProgramGroupPage=yes
DisableDirPage=yes
CreateAppDir=yes
OutputBaseFilename=My_IETOOLSBHOSetup
Compression=lzma
SolidCompression=yes

Viene poi impostata la lingua del setup e il path di destinazione della dll (che in questo caso va registrata nella GAC di Windows), e l’eventuale icona da usare per le voci di unistall:

1
2
3
4
5
6
7
8
[Languages]
Name: "italian"; MessagesFile: "compiler:Languages\Italian.isl"

[Files]
Source: "D:\Dev\MyBho\MyBHOBHOSETUP\MyBHO.dll"; DestDir: "{app}"; Flags: ignoreversion

[Icons]
Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}"

Fatto questo si passa alla sezione [Code] che mantiene delle funzioni (sono scritte in Pascal) generiche richiamate dai metodi “hook” gestiti da Inno stesso,come ad esempio il methodo InitializeSetup che viene eseguito a startup dell’installazione.
In questa sezione ho messo un metodo per la rilevazione dell’installazione su sistemi a 64 e 32 bit e sulla verifica del framework .net installato (il bho che ho realizzato in c# richiede, visto il codice managed, la presenza di .net 4.0)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
[Code]
function IsDotNetDetected(version: string; service: cardinal): boolean;
//    'v1.1.4322'     .NET Framework 1.1
//    'v2.0.50727'    .NET Framework 2.0
//    'v3.0'          .NET Framework 3.0
//    'v3.5'          .NET Framework 3.5
//    'v4\Client'     .NET Framework 4.0 Client Profile
//    'v4\Full'       .NET Framework 4.0 Full Installation
//service: per la presenza richiesta di service pack:
//    0               No service packs
//    1, 2, etc.      Service pack 1, 2, etc..
var
    key: string;
    install, serviceCount: cardinal;
    success: boolean;
begin
    key := 'SOFTWARE\Microsoft\NET Framework Setup\NDP\' + version;
    // .NET 3.0 usa InstallSuccess nella chiave Setup
    if Pos('v3.0', version) = 1 then begin
        success := RegQueryDWordValue(HKLM, key + '\Setup', 'InstallSuccess', install);
    end else begin
        success := RegQueryDWordValue(HKLM, key, 'Install', install);
    end;
    // .NET 4.0 usa Servicing al posto di SP
    if Pos('v4', version) = 1 then begin
        success := success and RegQueryDWordValue(HKLM, key, 'Servicing', serviceCount);
    end else begin
        success := success and RegQueryDWordValue(HKLM, key, 'SP', serviceCount);
    end;
    result := success and (install = 1) and (serviceCount >= service);
end;



function Install32BitOn64Bit(S: String):string;
begin
    if IsWin64 then
      Result := 'Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects\{#MyAppId}'
    else
      Result := 'Software\Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects\{#MyAppId}'
end;

function InitializeSetup(): Boolean;
begin
  if  IsDotNetDetected('v4\Client', 0) or  IsDotNetDetected('v4\Full', 0) then
      Result :=true
  else begin
      MsgBox('Attenzione Framework .NET 4.0 non rilevato', mbError, mb_Ok);
      Result :=false;
     end
 
end;

Come ultimo step del nostro script andiamo ad indicare nella sezione [Registry] tutte le chiavi da impostare (e sono molte) per il funzionamento del nostro componente come plugin di IE. Il guid che si passa, è il guid associato serve a indicare i componenti .net.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
[Registry]
Root: HKCR; Subkey: "CLSID\{{#MyAppId}"; Flags: uninsdeletekey
Root: HKCR; Subkey: "CLSID\{{#MyAppId}"; ValueType: string; ValueName: ; ValueData: {#MyAppNamespace}
Root: HKCR; Subkey: "CLSID\{{#MyAppId}"; ValueType: string; ValueName: MenuText; ValueData: {#MyAppName}
Root: HKCR; Subkey: "CLSID\{{#MyAppId}"; ValueType: string; ValueName: HelpText; ValueData: {#MyAppDescription}
Root: HKCR; Subkey: "CLSID\{{#MyAppId}\Implemented Categories\{{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}"
Root: HKCR; Subkey: "CLSID\{{#MyAppId}\InprocServer32"; ValueType: string; ValueName: ; ValueData: mscoree.dll
Root: HKCR; Subkey: "CLSID\{{#MyAppId}\InprocServer32"; ValueType: string; ValueName: ThreadingModel; ValueData: Both
Root: HKCR; Subkey: "CLSID\{{#MyAppId}\InprocServer32"; ValueType: string; ValueName: Class; ValueData: {#MyAppNamespace}
Root: HKCR; Subkey: "CLSID\{{#MyAppId}\InprocServer32"; ValueType: string; ValueName: CodeBase; ValueData: file:///{pf}\MyTools\MyBrowserHelperObjects\{#MyAppDllName}
Root: HKCR; Subkey: "CLSID\{{#MyAppId}\InprocServer32"; ValueType: string; ValueName: Assembly; ValueData: {#MyAppName}, Version={#MyAppVersion}, Culture=neutral, PublicKeyToken=dedfcbc464c1d691
Root: HKCR; Subkey: "CLSID\{{#MyAppId}\InprocServer32"; ValueType: string; ValueName: RuntimeVersion; ValueData: v4.0.30319

Root: HKLM; Subkey: "Software\Classes\CLSID\{{#MyAppId}"; Flags: uninsdeletekey
Root: HKLM; Subkey: "Software\Classes\CLSID\{{#MyAppId}"; ValueType: string; ValueName: ; ValueData: {#MyAppNamespace}
Root: HKLM; Subkey: "Software\Classes\CLSID\{{#MyAppId}"; ValueType: string; ValueName: MenuText; ValueData: {#MyAppName}
Root: HKLM; Subkey: "Software\Classes\CLSID\{{#MyAppId}"; ValueType: string; ValueName: HelpText; ValueData: {#MyAppDescription}
Root: HKLM; Subkey: "Software\Classes\CLSID\{{#MyAppId}\Implemented Categories\{{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}"
Root: HKLM; Subkey: "Software\Classes\CLSID\{{#MyAppId}\InprocServer32"; ValueType: string; ValueName: ; ValueData: mscoree.dll
Root: HKLM; Subkey: "Software\Classes\CLSID\{{#MyAppId}\InprocServer32"; ValueType: string; ValueName: ThreadingModel; ValueData: Both
Root: HKLM; Subkey: "Software\Classes\CLSID\{{#MyAppId}\InprocServer32"; ValueType: string; ValueName: Class; ValueData: {#MyAppNamespace}
Root: HKLM; Subkey: "Software\Classes\CLSID\{{#MyAppId}\InprocServer32"; ValueType: string; ValueName: CodeBase; ValueData: file:///{pf}\MyTools\MyBrowserHelperObjects\{#MyAppDllName}
Root: HKLM; Subkey: "Software\Classes\CLSID\{{#MyAppId}\InprocServer32"; ValueType: string; ValueName: Assembly; ValueData: {#MyAppName}, Version={#MyAppVersion}, Culture=neutral, PublicKeyToken=dedfcbc464c1d691
Root: HKLM; Subkey: "Software\Classes\CLSID\{{#MyAppId}\InprocServer32"; ValueType: string; ValueName: RuntimeVersion; ValueData: v4.0.30319

Root: HKLM; Subkey: {code:Install32BitOn64Bit};  Flags: uninsdeletekey
Root: HKLM; Subkey: {code:Install32BitOn64Bit}; ValueType: dword; ValueName: NoExplorer; ValueData: 1

Fatto questo, eseguendo lo script dal compilatore di Inno Setup, è possibile ottenere l’installer/uninstaller del nostro componente.

Ovviamente questo tutorial è il frutto di molte ricerche sulla rete, e di riferimenti presi da diversi blogger che hanno affrontato l’argomento, a cui vanno i miei ringraziamenti, e a quel pozzo infinito di spunti e riflessioni che è la comunità di StackOverflow, a cui va la mia gratitudine eterna 🙂 .

Cocos2d Mac Osx e Setup finestra e risoluzione rendering

Lavorando con Cocos2d su mac osx e non su dispositivo iOS, mi sono imbattuto nella complessità di gestire la finestra a diverse risoluzioni, a calcolare la toolbar o bottombar della finestra nei resize, e nella gestione del fullscreen, requisito oramai fondamentale affinché l’applicazione venga accettata sullo store per osx.

Dopo molti test e molti tutorial cercati sulla rete sono riuscito a trovare una strada che mi permetta di lavorare in maniera decente.

Come prima cosa ho ridimensionato la finestra nella view presente nel template di cocos2d, in modo da gestire l’intera area, portandola da questa:
1

a questa (facendo in modo che la view interna occupi l’intera area della finestra)
2

e poi negli attributi della window, settare il fullscreen:

3

Fatto questo, nel nostro AppDelegate, dove generalmente inizializziamo il nostro framework e la nostra applicazione, arriviamo a definire e ridefinire una serie di caratteristiche della finestra, della view opengl e del frame:

Inizializziamo il nostro director e prendiamo le dimensioni del display principale, e calcoliamo la dimensione della title bar facendo la differenza tra le dimensioni dei due frame ottenuti:

1
2
3
4
5
6
NSRect frameOpenGL = glView_.frame;
NSRect frameWindow = window_.frame;
NSRect mainDisplayRect = [[NSScreen mainScreen] frame];
CGFloat display_width = mainDisplayRect.size.width;
CGFloat display_height = mainDisplayRect.size.height;
CGFloat titleBarHeight =frameWindow.size.height-frameOpenGL.size.height;

 
a questo punto calcoliamo l’aspect ratio dello schermo, per capire se stiamo lavorando in 4:3, 16:9, 16:10 etc, questo perche vogliamo riproporre lo stesso aspect ratio alla nostra finestra.

1
double ar = mainDisplayRect.size.width / mainDisplayRect.size.height;

Definiamo la dimensione iniziale che vogliamo dare alla finestra (forzando cosi la dimensione definita nel nostro Xib)
La height la calcoliamo in base alla width e al nostro aspect ratio.

1
2
CGFloat min_width = 800;
CGFloat min_height = roundf(min_width / ar);

poi impostiamo la risoluzione della view opengl. Le due sono indipendenti. Possiamo avere una finestra di 800×600 pixel ma ad una risoluzione inferiore o maggiore. Ovviamente maggiore e’ la risoluzione e migliore sarà la qualità grafica.

1
2
CGFloat work_width = 1280;
CGFloat work_height = roundf(work_width / ar);

ora aggiorniamo la dimensione del frame (del rettangolo) della finestra e della view opengl con i dati impostati precedentemente e impostiamo l’aspect ratio alla finestra:

1
2
3
4
[window_ setFrame:NSMakeRect(0, 0, min_width, min_height+titleBarHeight ) display:YES];

[glView_ setFrame:CGRectMake(0, 0, min_width, min_height)];
[window_ setContentAspectRatio:NSMakeSize(display_width, display_height)];

infine centriamo la finestra nello schermo sulla base della risoluzione e del frame .

1
2
3
NSScreen * screen = window_.screen;
NSRect r = screen.frame;
[window_ setFrameTopLeftPoint:NSMakePoint(r.size.width/2 - frameWindow.size.width/2, r.size.height/2 + frameWindow.size.height/2)];

In questo modo otteniamo un sistema gestibile per il controllo della dimensione della finestra a runtime e della risoluzione di rendering.