Wednesday, November 17, 2021

Update an MSI Installer without rebuilding


In many development environments, updating outdated Installers of the development tools can be challenging.
In most cases, the original development environment used for generating the installer will be no longer available. In such cases, an installer can be disassembled, changes be applied and reassembled back using MS installer APIs.

Steps

1. Extract the contents of the installer to a temp location. For example,
msiexec.exe  /a xxxx.msi targetdir=d:\temp  /quiet
This step will create following file structure
d:\temp
    xxxx.msi 
    WinRoot
        Temp
              <files to be deployed>
The xxxx.msi under d:\temp is barred off the installation files, which are stored in d:\temp\WinRoot\Temp folder. Any changes required can be applied here,

2. After the changes, the MSI can be assembled back using the following command.
cscript WiMakCab.vbs d:\temp\IW_eIFU.msi  Data1  /U /E /S /C
The VBScript file WiMakCab.vbs can be downloaded from this location.
The installer file xxxx.msi under d:\temp  now will contain the new changes.

It's also possible to do much more than this, for example update GUIDs etc. This is implemented in this post.


Source and Binaries can be found here.



Thursday, November 11, 2021

Easy MSI Installer Creator with Actions

Often times software, data files etc. needs to be packaged and sent across. Zip files are sufficient in most cases. However, sometimes complex deployment needs could arise, For example, multiple versions, operations on the files, etc.

Easy Installer Creator addresses this as described below:
  • Standalone application – only .Net 3.5 is required
  • Create layout file containing files, directories and sub directories etc by drag drop from windows explorer
  • Folders can be pre configured or can be supplied on demand during installation
  • Installer properties such as Manufacturer, upgrade Id, product id can be updated
  • Custom file operations can be defined.
  • Pre and Post deployment operations supported.
  • Creates Installers (.MSI files) that support silent installation.
  • Command line operation is supported for build scripts
  • Templates for COM+ Server COM+ Client and WCF Server
In addition, this also comes with tools that integrate components into COM+ as discussed in the previous posts "COM+ integrated WCF Service" and "Late binding Client code generator for COM components". An example to demonstrate these capabilities is also provided. Please refer to the documentation for details.


Create a new Layout 1

This creates a new .layout file. Files and folders can be added at root by drag and drop from windows explorer. Three options are available.

Simple – Creates a basic installer.

DCOM Server – Facilitates installing COM components in COM+ application also provides server side DCOM patching. Users can customize by editing server.vbs.

 DCOM Client - Provides client side DCOM patching. Users can customize by editing client.vbs.

Open existing Layout 2

This opens an existing layout. The tree view is populated with the file structure.

Save Layout 3

After files are added to a new layout, the layout needs to be saved to create the installer. Note that a new package code is created for every time a layout is saved. Following describes the user interface in detail.


Name of the layout and the package1

Location of the layout file2

Version of the layout and the package3

The name and the version of the layout file. This will be embedded into the package.  The location of the layout file specifics the directory.

Set new product code to the package 4

It lets a new product code to be defined for the package. This will allow creation of a new product in the families of products. The upgrade code will remain same.

Scripts to run before and after the file copy 5

Users can configure operations to be executed before and after file copy of an installation.

Scripts to run before and after file copy 6

Users can configure operations to be executed before and after file delete of an uninstallation.

Command to execute before file copy during install or before file delete during uninstall 7

These commands typically do checks to be performed before install or uninstall. Upon exceptions, StopInstall environment variable must be set to 1 to abort.

Command to execute after file copy during install or after file delete during uninstall 8

These commands typically do post install and uninstall operation. Upon exceptions, StopInstall environment variable must be set to 1 to rollback.

Save Layout 10

This saves the current layout and settings to disk. The new layout will be associated with new package code, product code, and upgrade codes. The file name will be name+version.layout. Example, example_1.layout.

The pre post commands for install and uninstall commands are also stored. By default, the only files specified in the commands are added to the setup folder discussed later. Additional dependencies such as assemblies must be added to setup folder by drag drop from explorer. 

Set values for logical folders and add additional parameters 9

When defining a layout, logical folders can be defined whose path is inputted during installation. However, if the path is already known it can be entered ash shown below. All the logical folders defined in the layout are listed. If the input is already defined, these appear as default values during installation. The values can be entered in the second column1. Also new parameters can also be defined by entering the name and value 3. For silent installation mode, asking user input can be turned off by checking off the ask input option 2.    Note that during installation and uninstallation, an environment variable will be created for each of the parameters.

 A list of existing environment variables can be listed. 4

File Actions 4

This dialog enables defining a new custom action or edit an existing. There are 18 predefined commands. Refer to the appendix for the details. These commands cannot be edited or deleted.  New user defined commands can be defined that can also be deleted. During installation these commands are executed after the files are copied. During uninstallation, the commands are executed before deleting the files.

List of actions 1

This is a list of all actions including built in and user defined commands.

Folder level or File level command 4


This indicates if a command is applicable only to a folder or only a file or both to file and folder. For example, regasm is applicable to a file. Whereas create new is applicable to a folder.

Name of the command 5

This indicates the name of the command. The name cannot be changed once the command created. It can be specified only when a new command is created.

Priority of the command 6

This indicates the priority of the command. 0 is highest and 5 is the least. Commands with highest priority are run first.

 Applicable File extensions for the command 7

This indicates the file extensions of the file to which this command is applicable. * indicates for all file extensions. Multiple extension can be applied separated by ;. E.g., dll;exe

Path and arguments for the command 8

The “Executable” indicates the path of the executable with full path. The Arguments indicates the applicable arguments. The installer passes the actual file name as last argument to the command. If Group 10 option is supported, the filenames will be combined with other files executing the same command and the arguments. The arguments within <> needs to be edited.

Wait for command to complete 9

This indicates that the installation or uninstallation waits till the commands are completed.

Command can be applied in group 10

This indicates that this command takes multiple files are arguments. This command is executed it will include all the files that indicate execution of this command and having same command arguments.

Command applies during Installation 12

This indicates that this command is available only for installation.

Command applies during Uninstallation 13

This indicates that this command is available only for Uninstallation.

Tool tip for the user 14

Provides useful information to the user

Update 11

This will commit changes done to the command .

Add new command 2

This will add a new command. Following describe adding a new command notepad.exe.

1.       Click New2  button.

2.       Enter name5 as Notepad

3.       Check Leaf level 4

4.       Enter * for the filter 7

5.       Select 1 for priority 6

6.       Enter %windir%\notepad.exe for Executable 8

7.       Enter filename(s) for Arguments 8

8.       Leave Wait for Exit and Support group 10 unchecked

9.       Click the Update 11 button

10.   Click Save and Exit button to save the command

Note that all the fields except the name can be edited.

Delete command5

This will delete the selected command.

Actions on the File 16

This sets actions on the individual file and folder items. Installation actions are called after files are copied. Uninstallation actions are called before deleting the files. The physical file path is passed as last argument to the command. Based on the group action setting 6, the action can be combined with other files.  Arguments with <> require user inputs. For example, <app name> represents the name of the COM+ App.


Example
Creating Server Installer

Launch Easy InstallerCreator.exe  Execute following steps:
1.       Click new and select DCOM Server
2.       Add a logical folders “WCFCalc. “
3.       Rename “%Components%” to “%Calc%”
4.       Add a physical folder “server “ under example.
5.       Drag and drop files from D:\Github\TechBlog\File Utilities\Easy Installer Creator\Example\server

6.       Define custom actions as below. 


Save the layout file as below.



Click Set parameters and Save as below:



Create the installer

For more information check out the chm file.


Source and Binaries can be found here.




Sunday, November 7, 2021

Digital Code Signing binaries and scripts during Nightly Builds

Digital Code signing binaries such as exes, dlls , scripts by the software supplier is now a  de facto requirement. The digital signatures not only identifies the source of the software but also  asserts authenticity. Also AppLocker  rules can be configured to check digital certificates.

Digital Code signing is usually done as part of the build process where binaries are digitally signed as they are built. However this can impose overhead and add complexities in development build environments. Also there could be older digitally unsigned 3rd party binaries supplied as a part of the software. An ideal solution would be to do digital signing as a separate step during nightly production builds as discussed below:

Concepts
A digital certificate issued by vendors such as Verisign. This is to authenticate the source of the software. It's basically cryptographic public key. 
signtool.exe from Microsoft is used for signing the binaries. For example, icudt.dll was digitally signed and after signing, the digital certificate would be embedded as shown below.


Implementation
A script is created such that
  • It is invoked before creating the iso file of the software before deployment. 
  • It recursively extracts binaries in msi, .zip, cab files, digitally signs them using signtool.exe and packages back.
Extracting and packaging a msi file is done using installer APIs as discussed here.
Extracting and packaging a cab files is done using CabArc.Exe.
Extracting and packaging a zip files is done using 7z.Exe.


Source and Binaries can be found here.


Friday, October 1, 2021

ISQL - Query, Manage any ODBC based data source

Open Database Connectivity or ODBC is a part of the windows OS that enables accessing data from different data sources using a single interface. For example, RDBMS such as Access, SQL Server, Oracle, text files, excel files etc. using Structured Query Language or SQL.

There are no tools available by the OS to query using SQL hence ISQL.exe was created.


It has following features:
  • The user interface has a single SQL command window where sql commands can be entered and executed.
  • If the sql command ends with a ; , the results of the view are posted to a common view window.
  • If the sql command ends with a :, the results of the view are posted to a new view window also additional rows can be fetched.
  • The view windows can be tiled vertically or horizontally
  • The SQL Commands in the SQL command window can be  saved to a text file and loaded.
  • A new view window containing results of sql query is created depending on the command.
  • VSQL.INI is used for data keeping.
Example
ROSE perf numbers.xls contains multiple worksheets such as job, final. An ODBC data source can be created and data can be queried using SQL commands below.
Operation
Launch ISQL tool. Click ... button to create Excel Data source.

 
Select Machine data Source, Select Excel driver and Click New button. 


Using the wizard create the DSN.

Select Excel driver

Complete creation by entering  a  name for dsn.



Click Select workbook and select a excel worksheet.


Execute following commands
select * from [job$]:
select * from [final$]:


The output looks like as below


Source and Binaries can be found here.



Wednesday, September 29, 2021

Transform COM+ serviced component to WCF Service

With the advent of WCF, there is a paradigm shift in developing applications interacting across network. However porting existing COM based applications to WCF architecture can be daunting task. A balance can be achieved by deploying existing COM based applications as a WCF service so that it can be accessed by WCF clients.

Any COM component can be simply made as a WCF service using he LBGenrator.Following defines the process.
1.      Select COM components as described in DCOM Client
2.      Navigate to WCF Server tab, enter a namespace for the generated wrapper class
3.      The Generate Code option does following
a.       Scan through the selected COM objects and generate an Interface for each
b.      A project is created containing a COM object COM_LB_<prog id> that implements ServicedComponent and the interface
c.       This project is compiled and wcfserver.dll is generated and copied to wcfserver.dll

Example
As described in the previous post, use sillycalc.wsc. Copy the code and save it to sillycalc.wsc and register it.
Load the WCF component in a COM+ Application as discussed in the previous post.


 
Load  the wsc file as shown below and generate wcfserver.dll from WCF Server tab. This contains a COM class implementing wcf service. wcfserver.COM_LB_SillyCalc_WSC_1. 
Copy wcfserver.dll from the output folder and Execute following command to deploy  WCF service.

ComAppHelper -ins -app:wcfcalc  -gac -runforever -svc  D:\Github\TechBlog\COM+\WSC\wcf_client\wcfserver.dll


WCF Client

Create a console project and add a service reference for address net.pipe://localhost/wcfcalc/wcfserver.COM_LB_SillyCalc_WSC_1/mex



The app.config needs be edited to comment as below:
       
	   
<!--
<identity>
<userPrincipalName value="VEDAVYASARAO\rvvya" />
</identity>
-->

 
 

Consume the service as below
       
	   
static void Main(string[] args)
{
    var x = new ServiceReference1.SillyCalc_WSC_1Client();
    Console.WriteLine("calling x.add(10, 2) Result:{0}", x.add(10, 2));
    Console.ReadKey();
}

 
 

Result



Adding a  different service endpoints to WCF service
Currently the installer deploys a named pipes endpoint. Additional endpoint such as net.tcp can be easily added using “SCConfiguration Editor”(svcConfigEditor.exe ) as shown below.

  1.         Open the COM+ application from File->Open->COM+ Application.
  2.         Select WCFCalc Application

.     



   3      3. Add a new service point as shown below.


Similarly Managed COM component CalcServer.Calucalator, hosted in a COM+ application can be utilized as  a WCF service.


Source and Binaries can be found here.





Monday, September 13, 2021

Working with Managed COM Component

COM components can also be generated under .net environment using Visual studio and languages such as C#.

A COM component is essentially class library having an interface declared as below.

    [ComVisible(true)]
    [Guid("E3D02A14-ED36-471E-BE32-2D65F1BC97DA")]
    public interface ICalucalator
    {
        int add(int op1, int op2);
    }
and class implementation as below. TheComvisible attribute makes the class visible to COM based clients and the guid serves as clsid. The class name serves as the second parts of the program id. for example, servercalc.calucalator.
    [ComVisible(true)]
    [Guid("0AD70785-5539-4EE0-83D5-37A62CF5318F")]
    public class Calucalator :  ICalucalator
    {

        public int add(int op1, int op2)
        {
            return op1 + op2;
        }
      
    } 
AssemblyInfo.cs should look as below. The Comvisible attribute makes the class visible to COM based clients and the guid identifies the  typelib.  A typelib contains metadata about the classes, interfaces, methods within the assembly. It will be used com based clients to make calls.
// Setting ComVisible to false makes the types in this assembly not visible 
// to COM components.  If you need to access a type in this assembly from 
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(true)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("8CF1D751-666D-40C6-A741-0C14B4727A9E")]
the project file .csproj should look as below. The assembly name serves as the first part of the program id. for example, servercalc.calucalator. The registerforInterop executes RegAsm for the assembly making it visible for  COM clients.
<AssemblyName>CalcServer</AssemblyName>
<RegisterForComInterop>true</RegisterForComInterop>

Note:- All the guids must be unique. if the same project is  cloned they must be replaced apart from the code 

Registration
The assembly must be registered. it's done Regasm tool as below. Note that a typelibrary is also generated.

regasm D:\Github\TechBlog\COM+\Managed\server\bin\CalcServer.dll /tlb:D:\Github\TechBlog\COM+\Managed\server\bin\CalcServer.tlb

Com callable wrappers are used to consume managed com components from native clients. The process involves creating the type library from the managed dll by using tlbexp.exe and import it. Later native clients query type library for published interfaces to make calls. 

Serviced Component
COM+ offers services such as object pooling. A Serviced component can take advantage of this by deriving from System.EnterpriseServices.ServicedComponent class.
    public class Calucalator : System.EnterpriseServices.ServicedComponent, ICalucalator
This enable overriding the default methods such as object pooling with custom code.


Scripting host Client
The component can be consumed by a scripting host client such as cscript or wscript as below. Save the 
Save the following to calcserver_client.vbs.
       
 set calc = createobject("CalcServer.Calucalator")
 msgbox calc.add(40,6)
 
 
Execute it in a WOW64 command window. The message box should popup as shown below


C# client
Unlike unmanaged com component, managed com component cannot be consumed by importing typelibrary in a managed client. It needs to be hard coded as below. 

       
static void Main(string[] args)
{
    dynamic remoteobj = Activator.CreateInstance(Type.GetTypeFromProgID("CalcServer.Calucalator"));
    Console.WriteLine("40+6={0}", remoteobj.add(40, 6));
}
 
 
The output looks as below:

Debugging scripting component
It's possible to debug Managed Com Component at run time using Visual Studio as below.
1. Start the client
2. Load the symbols for the managed com component

3.step into the managed component  implementation



Source and Binaries can be found here.


Thursday, September 2, 2021

Working with WSC (Windows scripting component)

Often times an application require a certain functionality to be extended by users .For example a workflow engine can let users customize start or end steps. The .NET framework provides perfect mechanism to implement this but it comes with a steep leaning curve.

Windows scripting component or WSC provide an easier javascript or vscript based solution for creating COM components  using command line tools. WSC are essentially XML based  that can be used to generate COM based object that can even support events.
What's more interesting is it's possible to host these in COM+ applications for remote access and integrated as a WCF service.

Below is a simple example. This hosts a single component that has a single method Add.
<?xml version="1.0"?>
<component>

<?component error="true" debug="true"?>

<registration
 description="silly calculator"
 progid="SillyCalc.WSC"
 version="1"
 classid="{502B2117-D5AC-41B2-9441-B466932F613F}"
>
</registration>

<public>
 <method name="add" >
 <PARAMETER  name="op1" />
 <PARAMETER  name="op2" />
 </method >
</public>

<script language="VBScript">
<![CDATA[


Function add(op1, op2)
add=op1 + op2
End Function 


]]>
</script>

</component>

The window scripting component wizard can also be used for creating wscs. It can be installed by running wz10en.exe.

Registration
  1. Save the above text to file sillycalc.wsc
  2. open a WOW64 command window and run following command.
regsvr32 sillycalc.wsc

Scripting host Client
The component can be consumed by a scripting host client such as cscript or script as below. Save the following to sillycalc_client.vbs and execute it in a WOW64 command window. The message box should popup as shown below. 
       
        set calc = createobject("sillycalc.wsc")
	msgbox calc.add(40,6)
       
 


C# client with WSC unregistered
The wsc can be consumed directly by a c# client without even registering as below:
   dynamic remoteobj;
   remoteobj = (dynamic)Marshal.BindToMoniker(@"script:D:\Github\TechBlog\COM+\WSC\server\SillyCalc2.wsc");
   Console.WriteLine("40+6={0}", remoteobj.add(40,6));
       
 
However this requires hardcoding the method names and its parameters which can be problematic to maintain.

C# client with WSC registered
CLR uses Runtime callable wrapper to consume unmanaged COM components. 
The process involves generating an interop dll from the type library of  the unmanaged COM dll usng tlbimp.exe and adding it as a reference to the project. Alternatively this can be done by adding tlb as a reference.
However this method does not work for wsc tlb files as Visual studio does not interpret wsc tlb files.
The when wsc is registered, it can be consumed by a c# client  by hard coding method name as below. also this needs to be executed in WOW64 command window.
       
 dynamic remoteobj;
 remoteobj=(dynamic)Activator.CreateInstance(Type.GetTypeFromProgID("SillyCalc.WSC.1"));
 Console.WriteLine("40+6={0}", remoteobj.add(40, 6));
 
 

The output should like below:

Debugging scripting component
It's possible to debug WSCs at run time using Visual Studio as below.

CSCRIPT //X  calc_client.vbs

This will  launch JIT debugger and source code is loaded into it.
stepping into the wsc method will load the source code of the wsc as below

Note:- The wsc file should explicitly allow debugging as below.

<?component error="true" debug="true"?> 

Source and Binaries can be found here.