Archive: Better ActiveX registration


Better ActiveX registration
There's a problem with the way we can check the version number when doing ActiveX registration. It requires the filename on the install system...

Typically you want to install an ActiveX component if the file is newer than the one already on the system... The problem is that you don't know the filename/location of the component on the system. :( The only thing you know is the "class id" of the component that you want to install. And you dont want to write the class-id's in the NSIS script, instead you want the NSIS to retrieve it from the file in...

What I am looking for could be expressed in pseudo-code it as:



NDLL=the DLL in the NSIS package
IF NDLL.classid already exists on system {
SDLL=the install systems DLL coresponding to NDLL.classid
IF SDLL.version<NDLL.version {
UNREG SDLL
REG NDLL
}
}


I have no idea how to implement this in the NSIS source. But I doubt i am the only one that would like this feature. If there only was a function that could retrieve the filename of SDLL.

Am I the only one interrested in this?

I really can't imagine it.. If your product is one with lots of ActiveX components then this feature is almost essential.

This would be the case for almost all VB/Delphi coded products...

Anybody got a solution?


If nobody here has a solution then I think I will switch to the "inno" installer. It's also free, albeit not as cool...

I might even consider writing my own using the "Seer" Scripting language.

I don't want to switch so please send any solutions to my problem....

;)


oh no... an unbeliever.. arrhgg... I will see what I can do.. if you could find an expample of how to do this progmatically, I would appreciate. I cant give it a lot of attention at the moment 'cause I'm busy ;)


would one just read the reg key HKEY_CLASSES_ROOT\CLSID\<clsid goes here>\InprocServer32\

??
e.g.

the default key value for
HKEY_CLASSES_ROOT\CLSID\{00000107-0000-0010-8000-00AA006D2EA4}\InprocServer32 is "C:\PROGRAM FILES\COMMON FILES\MICROSOFT SHARED\DAO\DAO360.DLL"


as well as that, there are various other keys that can be read to get filename of related modules (16/32 bit)..

(copied and pasted)
InprocHandler Registers a 16-bit handler DLL
@ String value
Specifies the custom handler used by the application.
InprocHandler32 Registers a 32-bit handler DLL
@ String value
Specifies the custom handler used by the application.
InprocServer Registers a 16-bit in-process server DLL
@ String value
Specifies the path to the in-process server DLL.
InprocServer32 Registers a 32-bit in-process server DLL
@ String value
Specifies the path to the 32-bit in-process server.
ThreadingModel String value
Specifies the threading model of the apartment the server can run in.
In-process servers are loaded into an existing apartment and so do not call CoInitialize or CoInitializeEx; they must use the registry to specify an application's threading model.
Allowable values are:
ThreadingModel=Apartment. Single-threaded apartment.
ThreadingModel=Both. Single-threaded or multithreaded apartment.
ThreadingModel=Free. Multithreaded apartment.
ThreadingModel=Neutral. Neutral apartment (available in Windows 2000).

Insertable Indicates whether the object is insertable in COM applications.
Objects of this class should appear in the Insert Object dialog box's list box when used by COM container applications.
@ String value
Specifies the path to the 32-bit in-process server.
LocalServer Full path to a 16-bit local server application
@ String value
Specifies the full path to the local server, and can include command-line arguments.
LocalServer32 Full path to a 32-bit local server application
@ String value
Specifies the full path to the local server, and can include command-line arguments.


"And you dont want to write the class-id's in the NSIS script, instead you want the NSIS to retrieve it from the file in... "

actually, on reading this, it seems that you also want a way to automatically get the CLSID from a program id, so you dont have to manually find the CLSID.

I haven't worked with COM/ActiveX objects before, but I think you need CLSIDFromProgID and StringFromCLSID.

I will implement this in the next release of my nsis dll.

I think it would be possible though, to load the CLSID directly from the CLSID registry key in HKEY_CLASSES_ROOT\<progid>. This would save a bit in your exe header.


Thanks a lot... this really helped me out :)


So How do you read the default value with ReadRegStr?


OK.....


Here's a little VBscript tool i made for genereating NSIS code for ActiveX registration.... :p

I have only tested it briefly so you might want to check it out yourself... I use the generated script in conjunction with the NSIS !include command. It seems to work great.

This is the ".vbs" CODE... If you want to know how it works i suggest you start reading about the TypeLibInfo object....




Option Explicit

Dim LabelOffset

Dim oFileOut
Dim oFSO
Dim oTLI

LabelOffset=1

Set oFSO=CreateObject("scripting.filesystemobject")
Set oFileOut = oFso.CreateTextFile("DLLs-include.NSI", True)
Set oTLI=CreateObject("TLI.TLIApplication")

dumpTypeLibInfo "c:\winnt\system32\msvbvm60.dll","$SysDir","c:\winnt\system32\vb6stkit.dll",true
dumpTypeLibInfo "c:\winnt\system32\comdlg32.ocx","$SysDir","",true
dumpTypeLibInfo "c:\winnt\system32\mci32.ocx","$SysDir","",true
dumpTypeLibInfo "c:\winnt\system32\mscomctl.ocx","$SysDir","",true
dumpTypeLibInfo "c:\winnt\system32\mswinsck.ocx","$SysDir","",true
dumpTypeLibInfo "c:\winnt\system32\tabctl32.ocx","$SysDir","",true


oFileOut.close



Sub dumpTypeLibInfo(localfilename,outpath,additionalfiles,isTypeLib)
Dim guid
Dim TII
Dim fname
Dim l
Dim sFiles

Set TII = oTLI.TypeLibInfoFromFile(localfilename)

fname = outpath & "\" & mid(localfilename,instrrev(localfilename,"\")+1)


guid = TII.GUID


oFileOut.WriteLine("SetOutPath """ & outpath & """")

If isTypeLib Then
oFileOut.WriteLine("ReadRegStr $9 HKCR ""TYPELIB\" & guid & "\" & TII.majorversion & "." & TII.minorversion & "\" & TII.lcid & "\win32"" """"")
Else
oFileOut.WriteLine("ReadRegStr $9 HKCR ""CLSID\" & guid & "\InprocServer32"" """"")
End If

oFileOut.WriteLine("ClearErrors")
oFileOut.WriteLine("StrCmp $9 """" RegisterDLL" & LabelOffset)
oFileOut.WriteLine("CompareDLLVersions /STOREFROM """ & localfilename & """ """ & fname & """ UnRegisterDLL" & LabelOffset & " RegComplete" & LabelOffset)
oFileOut.WriteLine("Goto RegComplete" & LabelOffset )

oFileOut.WriteLine("UnRegisterDLL" & LabelOffset & ":")
oFileOut.WriteLine("UnRegDLL """ & fname & """")
oFileOut.WriteLine("Sleep 1000")
oFileOut.WriteLine("RegisterDLL" & LabelOffset & ":")
oFileOut.WriteLine("File """ & localfilename & """")
sFiles=split(additionalfiles,";")
For l=0 to UBound(sFiles)
oFileOut.WriteLine("File """ & sFiles(l) & """")
Next
oFileOut.WriteLine("RegDLL """ & fname & """")


oFileOut.WriteLine("RegComplete" & LabelOffset & ":")
oFileOut.WriteLine("")

LabelOffset=LabelOffset+1
End sub



I've been looking at safe ActiveX registration and came up with this script that seems to work well. Is there an easier way? If anyone has any suggestions or improvments feel free to post.

------------------

[edit]edited by kichik. please attach huge scripts. attached below :down:[/edit]


.


Seems fine. You can put it in a function since it doesn't use the File command. You can also use the System plug-in to automatically get the GUID. Can you please add it to the archive so everyone else can easily find it?


>automatically get the GUID.

I originally thought I would do that. I figured I could write a DLL plugin to use "TLI.TLIApplication" to extract typeLibInfo. In order to do this though, I'd have to distribute (and register) TLBINF32.DLL which comes with Visual Studio.

> System plug-in

Does the System::call work on In-proc ActiveX components? (The documentation is hairy, it seemed like it was meant for standard DLLs)

Is there another way?


I am sorry, I have no idea. I have never worked with ActiveX. Just thought you can call CLSIDFromProgID that pjw mentioned using System.dll but it doesn't seem like it accepts file names.

System.dll is meant for normal DLLs, but if the function is exported you can call it with System.dll. If they are not exported you'll have to use the same code you'll use with your C plug-in, but then again, it will be simpler to just create a plug-in.