I have an Excel addin created using ATL COM. Usually this addin is installed using self registration, but I want to move away from that. I created an installer that manually adds everything to the registry. So far everything seems to load since Excel sees the addin, but I always get an error when trying to load it on startup. Even the LoadBehavior changes from 3 to a 2. Right now I am adding the values using RegistryKey and RegistryValue nodes, but when I looked at another SO post with a similar topic I just didn't grasp what Rob had mentioned as the .rgs script doesn't have any proxy clsid or interfaces so I am not sure what I need to place there. Is there any online tutorial that I can use to help further understand manual registration in WiX?
EDIT
So I assume that the Proxy information comes from the .idl file instead of the .rgs. If that is true I think that I filled out the correct information needed. However, Excel still says that there was an error loading the addin during runtime. Any other information would be greatly appreciated.
Example:
<File Id="AddinDll" Name="addin.dll" Source=".\addin.dll" KeyPath="yes" >
<TypeLib Id="TYPELIB-ID-HERE" MinorVersion="0" MajorVersion="1" Language="0" Description="addin" HelpDirectory="INSTALLLOCATION" >
<Class Id="GUID-HERE" Context="InprocServer32" ThreadingModel="apartment" Version="1.0" Programmable="yes" Description="Example" >
<ProgId Id="Addin.Example.1" Description="Example" >
<ProgId Id="Addin.Example" Description="Example" />
</ProgId>
</Class>
<Class Id="PROXY-STUB-CLSID-HERE" Context="InprocServer32" ThreadingModel="both" >
<Interface Id="INTERFACEID-HERE" Name="IExample" />
</Class>
</TypeLib>
</File>
Related
I have an installer that consists of lots of files in individual components that installs correctly.
I have now been told that one of these files needs to be registered only if it doesn't already exist and hasn't yet been registered.
I have use heat to generate the appropriate entries for the file;
<Component Id="AXSListenerdll" Guid="b1f80295-8806-4f6a-bf28-0ee35540317c">
<File Name="AXSListener.dll" KeyPath="yes" Vital="yes">
<TypeLib Id="{CE807033-6BEE-44D3-A86A-E9BC1D0716A4}" Description="AXSListenerLib" Language="0" MajorVersion="1" MinorVersion="0">
<Class Id="{C66BC66D-546E-4E74-A69F-BA97E4117E6B}" Context="InprocServer32" Description="IImplementedAlarmTypesCollection Class" ThreadingModel="both" Programmable="yes">
<ProgId Id="SymEvents.IImplementedAlarmTypesCollection.1" Description="IImplementedAlarmTypesCollection Class">
<ProgId Id="SymEvents.IImplementedAlarmTypesCollection" Description="IImplementedAlarmTypesCollection Class" />
</ProgId>
</Class>
</TypeLib>
</File>
</Component>
My question is, how do I prevent this particular file from being installed if it is already there and registered.
I just having a bit of a mental block about this.
I'm sure the answer must be obvious, I just can't see it!
Thanks in advance.
By default, Windows Installer uses file versioning to decide if this file needs to be installed/reinstalled. As an example, if the MSI has version 1.0.0.0 to install and 1.0.0.0 is already there then it won't reinstall. When it installs, it will reapply the registry entries for the DLL.
The requirement provided to you is a little weird / wrong. It could be read as if the MSI has file 2.0 but 1.0 is already present, don't install. That's not a good design and MSI doesn't operate that way.
Is there a way to associate a file extension to an external program in my WiX setup?
For example, my application uses .xyz files, but I use a third party program to edit them, like Notepad++. I would include Notepad++ during the setup or bootstrap its installer. Is there a way to associate Notepad++ with my .xyz files using only WiX?
I've looked at the ProgId element, but I don't think it can do this.
Unfortunately, the strongly typed elements cannot be used to refer to an executable outside of the install today. However, you can write the registry keys yourself. Something like:
<RegistryValue Root="HKCR" Key=".xyz" Value="xyz-progid" Type="string" />
<RegistryKey Root="HCKR" Key="xyz-progid>
<RegistryValue Key="shell\Open\command" Value="[NOTEPADPLUSPLUSPATH]" Type="string" />
<RegistryValue Key="DefaultIcon" Value="[!NOTEPADPLUSPLUSPATH]" Type="string" />
</RegistryKey>
For this to work, you'll need to find Notepad++ on the machine. I'm not sure how to do that but let's say there was a registry key that told you:
<Property Id="NOTEPADPLUSPLUSPATH">
<RegistrySearch Id="FindNotepadPlusPlus" Root="HKLM" Key="Software\NotepadPlusPlus"
Name="InstallPath" Type="raw" />
</Property>
I am trying to register a new filter with Windows Desktop Search. Ideal way to achieve do this would be registering new filter with existing persistent handler CLSID. But this cannot be done since .html PersistentHandler CLSID, {eec97550-47a9-11cf-b952-00aa0051fe20}, is protected under WRP (More about the problem).
As a workaround, I am trying to create a different CLSID that does the same job as {eec97550-47a9-11cf-b952-00aa0051fe20}.
This is the sample code I am following. I am quite new to WiX and editing Windows registry.
<File Id="HTMLfilter.DLL">
<Class Id="$(var.CLSID_HtmlIFilter)" Context="InprocServer32" ThreadingModel="both" Description="Html Filter" />
</File>
Could someone help me regarding these;
How to create a CLSID that is not affiliated to any file? Since my
new CLSID is doing the work of above mentioned CLSID, I think this is
how it should be.
How to create a a sub-directory named PersistentAddinsRegistered
instead of InprocSever32
Thanks
Have a look at this page here shows how to add COM objects to installers
I suggest export selected branch to registry file (Export all or part of the registry to a text file).
Then using Heat.exe harvest registry file and include its output in your project.
This is an example
<Fragment>
<DirectoryRef Id="TARGETDIR">
<Component Id="cmp6E2CE62C9ADECD355465514E3C8F354E" Guid="PUT-GUID-HERE" KeyPath="yes">
<RegistryKey Key=".ascx\PersistentHandler" Root="HKCR">
<RegistryValue Value="{eec97550-47a9-11cf-b952-00aa0051fe20}" Type="string" />
</RegistryKey>
</Component>
</DirectoryRef>
</Fragment>
Background:
Our application is a plugin for a much larger application. Everything we create are DLL files that the larger application hooks to. Because of this our .NET (C#), DLL files must be registered for a COM interface.
We have a working InstallShield project, but for many reasons which I won't go into here, we wish to migrate it to WiX. The only thing left to be done for the installer is to register our DLL files for COM.
Problems
Here is a sample component with a single DLL file.
<Component Id="MyComponent" Guid="COMPONENT-GUID" SharedDllRefCount="yes" >
<File Id="MyDLL.dll" Name="MyDLL.dll" KeyPath="yes" Assembly=".net"
AssemblyManifest="MyDLL.dll" AssemblyApplication="MyDLL.dll" />
</Component>
As per the accepted answer of How do you register a Win32 COM DLL file in WiX 3?, it is recommended to add SelfRegCost=1 to the File tag. This results in an error during install:
Module C:\Program files\Product\MyDll.dll failed to register. HRESULT -2147024769. Contact your support personnel.
The second answer in the same question (by Rob Menshing) recommends against this approach, but to add inside the file tag this:
<Class Id="PUT-CLSID-HERE" Context="InprocServer32" ThreadingModel="apartment" Description="Your server description">
<ProgId Id="Your.Server.1" Description="Your ProgId description">
<ProgId Id="Your.Server" Description="Your ProgId description" />
</ProgId>
</Class>
<Class Id="PUT-PROXY-CLSID-HERE" Context="InprocServer32" ThreadingModel="both" Description="Your server Proxies, assuming you have them">
<Interface Id="PUT-INTERFACEID-HERE" Name="IInterface1" />
<Interface Id="PUT-INTERFACEID-HERE" Name="IInterface2" />
<Interface Id="PUT-INTERFACEID-HERE" Name="IInterface3" />
<Interface Id="PUT-INTERFACEID-HERE" Name="IInterface4" />
</Class>
I am a bit confused as to put in as the CLSID ids. I put in a generated GUID and installed it. It installed fine, but the larger application could not find the DLL files. (I used the interface tags generated from heat.exe.)
Another approach found in the same question (by Adan Tegen) recommends using
heat.exe file myDll.dll -out my.wxs
Using the output, I add this to the File tag:
<TypeLib Id="Another Guid" Language="0" MagorVersion="1">
<!--Interfaces generated from heat.exe-->
</TypeLib>
Every way I have tried to register .NET for COM has failed and after reading so many questions about the topic I am no closer to knowing the correct way of doing it. What should I do? Why is this such a difficult task when everything else in WiX has been fairly simple?
I should mention that the original InstallShield project created a custom action that would call regasm.exe. If all else fails that could be a possibility, but I would rather do things right.
I just found that heat.exe file myDll.dll -scom -o myDll.wxs outputs registry values similar to what I need. Now, how do I reference the newly created component inside the DLL component?
I just found that heat.exe file myDll.dll -scom -o myDll.wxs outputs registry values similar to what I need.
Are you sure about -scom there? AFAIK, that option actually suppresses COM registration!
Now how do I reference the newly created component inside the DLL component?
The component generated by heat.exe already includes a File element for the DLL. So it actually contains everything needed to install and register the DLL file. You don't need the original "DLL component".
If you need to put the file and its COM registration in separate components, then you will have to remove the File element from the component generated by heat.exe.
Also, components cannot reference other components. You can have references between ComponentGroups though, something that we use heavily in our wixlibs to model dependencies, but that's a rather advanced use case.
I found an example on registering DLLs, Registering an Assembly for COM Interop in a MSI file with the Windows Installer XML toolset., and WiX complains about the "AssemblyRegisterComInterop" attribute.
I removed that and changed the "Assembly" attribute to win32, and it says I need to specify the AssemblyManifest attribute, but what should I put there?
The easiest way (and Rob M will rant and rave about how this is wrong) is just to use SelfRegCost=1 on the File tag for the DLL.
This is wrong, because we should be explicitly controlling the registration of the DLL, not allowing it just to run arbitrary code via DllRegisterServer. The theory being that a DLL should do nothing beyond putting the appropriate entries in the registry when DllRegisterServer is called. Unfortunately, a lot of of them do more than that, so self-registration might be the only way to get your install to work.
It's also wrong, because that means the Windows installation system doesn't know anything about those registry keys, and what should and shouldn't be there. That means repairing won't work, and possibly un-installation won't clean up properly, etc.
Otherwise, you can generate the appropriate WiX code by pointing heat.exe at your DLL, and integrating its output into your current WiX project. You'll get a variety of Class, ProgID, TypeLib, and Registry tags. You may need to manually edit that output to get it to compile.
I hope that helps.
It isn't just me that will rant and rave about how SelfReg is evil. The MSI SDK gives you a list of seven reasons why not to use SelfReg.
Example:
<Component Id="Component" Guid="*">
<File Source="ComServer.dll">
<Class Id="PUT-CLSID-HERE" Context="InprocServer32" ThreadingModel="apartment" Description="Your server description">
<ProgId Id="Your.Server.1" Description="Your ProgId description">
<ProgId Id="Your.Server" Description="Your ProgId description" />
</ProgId>
</Class>
<Class Id="PUT-PROXY-CLSID-HERE" Context="InprocServer32" ThreadingModel="both" Description="Your server Proxies, assuming you have them">
<Interface Id="PUT-INTERFACEID-HERE" Name="IInterface1" />
<Interface Id="PUT-INTERFACEID-HERE" Name="IInterface2" />
<Interface Id="PUT-INTERFACEID-HERE" Name="IInterface3" />
<Interface Id="PUT-INTERFACEID-HERE" Name="IInterface4" />
</Class>
</File>
</Component>
Ultimately, Troy's answer is all correct.
Use the heat.exe program that comes with the WiX toolset, to generate the wxs registration fragment:
heat.exe file <filename> -out <output wxs file>
eg.
heat.exe file my.dll -out my.wxs
Copy the contents of the <Component> tag from that new wxs file and paste it into the <Component> of your existing wxs file that references your dll using a <File> tag. Delete the <File> tag you pasted and replace all references to that file Id with the one that was already there; if the existing one didn't have an Id attribute, add it and set it to whatever you want.