Export COM Registration Information - c++

Is there a possibility, in any language (c/c++/c#,VB etc I DONT CARE) to export all the COM Registration information (such as clsid, progid, typelib, interface, appid etc)? Or do you know a reliable tool that exports that information including all of the 32 bit and 64 information?
Basically what I wanna do is what regsvr32 does but "in a file" and not write it to the registry. The solution can be a API-Call or Assembly class OR ANYTHING that supports me by doing this or it can be a tool where you are able to export the infos to a file. Please be aware that the tool, if so, should do this for COM as well as for interop assemblies.
(I am not interessted in wisecomcaputure or the equivalent of adminstudio)
For clarification my point is here:
I am a setup engineer. I basically want to know a way to get all the registration information of a COM or an Interop Object that's normally placed in the registry by calling regsvr32.
I am very glad of any help or hints
Eliane

There is a little-known but very handy API: RegOverridePredefKey. It allows to do exactly what you're looking for:
The RegOverridePredefKey function is intended for software
installation programs. It allows them to remap a predefined key, load
a DLL component that will be installed on the system, call an entry
point in the DLL, and examine the changes to the registry that the
component attempted to make. The installation program can then write
those changes to the locations intended by the DLL, or make changes to
the data before writing it.
Follow the docs for further details. Once you have re-mapped the HKEY_CLASSES_ROOT key and called the COM server's DllRegisterServer, use RegSaveKey to save the re-mapped key to a file, process the file and change the mapping back to HKEY_CLASSES_ROOT.

We use WiX in our company to create installers and gathering this registry information for COM assemblies is often essential in the installation process. Within the WiX suite there is a tool called Heat that basically scrapes this information and puts it in an xml file. This xml is specific to WiX but it may still help you.
An example heat command to do this would be:
C:\Program Files (x86)\WiX Toolset v3.8\bin\Heat.exe dir ..\ExactaRFBinaries\ -cg ExactaRF -dr RFINSTALLFOLDER -srd -var var.RFBasePath -gg -sfrag -suid -out ExactaRF.wxs
It's output would look something like this:
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<DirectoryRef Id="RFINSTALLFOLDER">
<Component Id="ContainerObj.dll" Guid="{A23592C5-E88D-4F56-A853-AE62085F9A91}">
<File Id="ContainerObj.dll" KeyPath="yes" Source="$(var.RFBasePath)\ContainerObj.dll">
<TypeLib Id="{8EB27E71-FA87-11D3-A3B3-00104B082353}" Description="ContainerObj 1.0 Type Library" HelpDirectory="RFINSTALLFOLDER" Language="0" MajorVersion="1" MinorVersion="0">
<Class Id="{2F467C72-FE8A-11D3-A3B7-00104B082353}" Context="InprocServer32" Description="Containers Class" ThreadingModel="apartment" Programmable="yes">
<ProgId Id="ContainerObj.Containers.1" Description="Containers Class">
<ProgId Id="ContainerObj.Containers" Description="Containers Class" />
</ProgId>
</Class>
<Class Id="{8EB27E80-FA87-11D3-A3B3-00104B082353}" Context="InprocServer32" Description="Container Class" ThreadingModel="apartment" Programmable="yes">
<ProgId Id="ContainerObj.Container.1" Description="Container Class">
<ProgId Id="ContainerObj.Container" Description="Container Class" />
</ProgId>
</Class>
<Interface Id="{2F467C71-FE8A-11D3-A3B7-00104B082353}" Name="IContainers" ProxyStubClassId32="{00020424-0000-0000-C000-000000000046}" />
<Interface Id="{8EB27E7F-FA87-11D3-A3B3-00104B082353}" Name="IContainer" ProxyStubClassId32="{00020424-0000-0000-C000-000000000046}" />
</TypeLib>
</File>
</Component>
<Component Id="ContainerUseMod.dll" Guid="{48616A97-02AA-4C02-AC5D-F41313B3C0F2}">
<File Id="ContainerUseMod.dll" KeyPath="yes" Source="$(var.RFBasePath)\ContainerUseMod.dll">
<TypeLib Id="{7590DB15-C326-11D3-99A9-0080C84E7C62}" Description="ContainerUseMod 1.0 Type Library" HelpDirectory="RFINSTALLFOLDER" Language="0" MajorVersion="1" MinorVersion="0">
<Class Id="{7590DB22-C326-11D3-99A9-0080C84E7C62}" Context="InprocServer32" Description="ContainerUse Class" ThreadingModel="apartment" Programmable="yes">
<ProgId Id="ContainerUseMod.ContainerUse.1" Description="ContainerUse Class">
<ProgId Id="ContainerUseMod.ContainerUse" Description="ContainerUse Class" />
</ProgId>
</Class>
<Interface Id="{7590DB21-C326-11D3-99A9-0080C84E7C62}" Name="IContainerUse" ProxyStubClassId32="{00020424-0000-0000-C000-000000000046}" />
</TypeLib>
</File>
</Component>
</DirectoryRef>
</Fragment>
<Fragment>
<ComponentGroup Id="ExactaRF">
<ComponentRef Id="ContainerObj.dll" />
<ComponentRef Id="ContainerUseMod.dll" />
</ComponentGroup>
</Fragment>
</Wix>
WiX is open source so you could probably look at the Heat source code if you want and engineer your own solution as well.

Yes, this is possible. However, the only tool I know of is proprietary and used internally within my company. I'm not sure exactly how it does it and I can't give out the source, unfortunately.
From poking around in the source, it seems like it's getting all the resources of COM DLLs and doing something with the resources, and it's pulling out some info from the type libraries (it's a command-line program that can be given a dll or a tlb).
The code is written in C++ and C# and is about 1400 LOC.
The code makes use of the COM interfaces ITypeLib and ITypeInfo and the TYPEATTR structure. I see calls to ITypeInfo::GetDocumentation, ITypeInfo::GetTypeAttr, LoadTypeLibEx, EnumResourceNames. The output of the program is a .reg file, which appears to be formatted by the tool's code rather than an external library.

We found a little utility called RegCap that Microsoft included with a visual studio extension called Visual Studio Installer Projects. The overall package can be downloaded from the Visual Studio Marketplace (it's a vsix file) here:
https://marketplace.visualstudio.com/items?itemName=VisualStudioClient.MicrosoftVisualStudio2017InstallerProjects
I've had a brief play and it certainly seems to extract the COM registration information. Whether it extracts all the information that regsvr32 would have put into the registry is another matter.

Related

Step into custom nuget c++ package

I am trying to release a C++ nuget package into our company Nuget feed. The problem is that we can't step into functions during debugging (F11). We need to be able to debug inside the package sources but it seems i cannot made it work.
I enabled in VS the option "Debug not only my code", included the generated vc110.pdb files in the package and finally added in the .nuspec the line
<repository type="git" url="http://xxxx" />
Unfortunately, VS17 does not step into the code of my package. We are pretty desperate and we really need a solution to this problem in order to make our toolchain leaner.
This is a C++ question so please do not link me to C#/.NET solutions because they don't work.
NOTE 1: When i pack with nuget i do not use the -Symbols option because it generates 2 packages and the second one cannot be pushed on our nuget feed (dupikcated package)
NOTE 2: I looked into the /SourceLink option but it seems to be supported only in C#
NOTE 3: I cannot use the .vcxproj when packing (it does not work, nuget says that i didn't give it any input file so i have to use my own .nuspec:
<package >
<metadata>
<id>x</id>
<version>1.0.2</version>
<title>$title$</title>
<authors>x</authors>
<projectUrl>yyy</projectUrl>
<description>static .lib</description>
<tags>native</tags>
<repository type="git" url="yyy" />
</metadata>
<files>
<file src="include\**\*.*" target="include" />
<file src="x64\**\*.lib" target="lib\x64" />
<file src="x64\**\*.pdb" target="lib\x64" />
<file src="build\**\*.*" target="build" />
</files>
</package>
NOTE 4: Ours GIT repo is on a Azure Devops TFS machine
NOTE5 : We are using VS17 but compiling with vc110 toolset (yeah know, don't comment on that please)
Thanks all

Register Windows Runtime Component (c++winrt) in native c++ application

Native c++ application is using c++/winrt classes to instantiate and use winrt::Windows::Media::Audio::AudioGraph. Inside AudioGraph there is possibility to add effects to graph nodes. There are some already created effects (like echo effect) but there is also possibility to create custom audio effect. Custom audio effect class must be a Windows Runtime Component. There is a way to create custom audio effect in Windows Runtime Component c++/winrt project by creating class with Windows.Media.Effects.IBasicAudioEffect interface in idl file (and providing implementation). This generates winmd, lib and winrt headers files. Until this point everything is fine and working. But to instantiate audio effect it need to be registered and this steep I am missing. Application at runtime throw's an exception with "Class not registered" message when I want to instantiate audio effect class and also throw an exception "Failed to activate audio effect" when I want to instantiate it inside AudioGraph node.
I do not know how to registered Windows Runtime Component from native c++ application.
Steps to create and use custom audio effect are describe here https://learn.microsoft.com/en-us/windows/uwp/audio-video-camera/custom-audio-effects. Code is in C# and used in UWP application but it could be converted to c++/winrt almost 1:1.
This article solves this problem:
https://blogs.windows.com/windowsdeveloper/2019/04/30/enhancing-non-packaged-desktop-apps-using-windows-runtime-components/
It is possible to use Registration-free WinRT (starting from Windows 10 1903) by modifying application manifest file (and not Windows Runtime Component Package manifest as suggested in documentation) like this:
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
<file name="WinRTComponent.dll">
<activatableClass
name="WinRTComponent.Class1"
threadingModel="both"
xmlns="urn:schemas-microsoft-com:winrt.v1" />
<activatableClass
name="WinRTComponent.Class2"
threadingModel="both"
xmlns="urn:schemas-microsoft-com:winrt.v1" />
</file>
</assembly>

How does Windows 7 determine, if you need admin rights? (vc60)

Problem: I'm writing unittests for a Setup program in c++. The Setup needs admin rights, but the unittests do not. On starting the tests, I get asked for starting the test/program as Administrator.
This started happening when I included the rc-file of the original project.
Edit: I was upgrading this project to VS2010, but still using vc60, so there is no manifest support. This might be related.
Generally, the resources contain a manifest, and a portion of the manifest states whether the program needs administrator access. Since this is a setup utility, it probably has a manifest requiring administrator access and your tests picked it up when it tried to share the resource file.
(Other people are talking about the heuristics used to guess whether a program needs administrator access when it doesn't have a manifest. For example, if you have an old program that was made before manifest files were common, the OS might try to guess whether it's an installer by looking for certain phrases like "setup" in the file name. I believe there are other heuristics as well. This is a hack for older programs that were written before manifests made it possible to explicitly declare your need for administrator access.)
You can fix your problem by providing your own manifest. The easiest way is to use the /MANIFESTUAC linker option.
If you're using an older toolchain, you'll probably have to make the manifest file yourself and include it in your resources.
The manifest is a chunk of XML. The important bit for you would look something like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity version="1.0.0.0" name="yourprogram.exe" type="win32"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker"/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>
To embed this in your resources, your .RC file should have:
1 RT_MANIFEST <filename>
If your SDK is so old that RT_MANIFEST is not defined, you can define it yourself:
#define RT_MANIFEST 24
One criteria for evaluating the needed rights for an application is the name.
So if the name contains the Word "Setup", you will be asked for admin rights.
Also, as this started with the rc file, another criteria are the names written in the rc-File, under "Version". In my case in "VS_VERSION_INFO".
The following entries are should not contain the word Setup:
FileDescription
InternalName
OriginalFilename
ProductName
You might change any occurance of "Setup" to "Settup". That would prevent the dialog.
Even though, you might not be able to change this in the "real" rc-file.

How to use the Web Publishing Pipeline and Web Deploy (MSDEPLOY) to Publish a Console Application?

I would like to use web deploy to publish a Visual Studio "Console" application to a folder on the target system.
I have had some luck, and have been able to produce something similar to what I need, but not quite.
I've added the following to the console .csproj:
added the following projectName.wpp.targets file
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
and I've added the following projectName.wpp.targets:
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<PropertyGroup>
<DeployAsIisApp>false</DeployAsIisApp>
<IncludeSetAclProviderOnDestination>false</IncludeSetAclProviderOnDestination>
</PropertyGroup>
<ItemGroup>
<FilesForPackagingFromProject Include="$(IntermediateOutputPath)$(TargetFileName).config">
<DestinationRelativePath>bin\%(RecursiveDir)%(FileName)%(Extension)</DestinationRelativePath>
<FromTarget>projectName.wpp.targets</FromTarget>
</FilesForPackagingFromProject>
</ItemGroup>
</Project>
I then edit the .SetParameters.xml file as follows:
<parameters>
<setParameter name="IIS Web Application Name" value="c:\company\project" />
</parameters>
When I then deploy using the generated .cmd file, I get all the files deployed to C:\company\project\bin.
That's not bad, but I'd like to do better. In particular, I'd like to omit the "bin" folder and put all files in the "C:\company\project" folder, and I'd like to be able to specify the ACLs
Has anybody been able to work around these problems?
Ok, so here's the way how to omit the 'bin' folder.
First of all, I'd like to emphasize that all this msdeploy-related stuff is for web apps deployment, and 'bin' folder seems for me to be almost hardcoded deeply inside. So if you want to get rid of it - you have to do some dirty things. Which I did.
We'll have to change $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets project a little bit, so it's better to change not it, but it's copy.
Steps:
1.Backup $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets(alternatively, you could install MSBuild.Microsoft.VisualStudio.Web.targets package, redirect your csproj file to Microsoft.WebApplication.targets file obtained from package and work with it).
2. In the $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplicaton.targets find the xml node which looks like <CopyPipelineFiles PipelineItems="#(FilesForPackagingFromProject)"(there are several ones of them, take the one from the line ~2570).
3. Comment the node out, replace with the custom one, so eventually it will look like:
<!--
<CopyPipelineFiles PipelineItems="#(FilesForPackagingFromProject)"
SourceDirectory="$(WebPublishPipelineProjectDirectory)"
TargetDirectory="$(WPPAllFilesInSingleFolder)"
SkipMetadataExcludeTrueItems="True"
UpdateItemSpec="True"
DeleteItemsMarkAsExcludeTrue ="True"
Condition="'#(FilesForPackagingFromProject)' != ''">
<Output TaskParameter="ResultPipelineItems" ItemName="_FilesForPackagingFromProjectTempory"/>
</CopyPipelineFiles>-->
<!-- Copying files to package folder in 'custom'(dirty) way -->
<CreateItem Include="$(OutputPath)\**\*.*">
<Output TaskParameter="Include" ItemName="YourFilesToCopy" />
</CreateItem>
<Copy SourceFiles="#(YourFilesToCopy)"
DestinationFiles="#(YourFilesToCopy->'$(WPPAllFilesInSingleFolder)\%(RecursiveDir)%(Filename)%(Extension)')" />
Then
4. Your projectName.wpp.targets don't have to have FilesForPackagingFromProject, so it will look like:
<!-- targets -->
<PropertyGroup>
<DeployAsIisApp>false</DeployAsIisApp>
<IncludeSetAclProviderOnDestination>false</IncludeSetAclProviderOnDestination>
</PropertyGroup>
<ItemGroup>
<!-- intentionally left blank -->
</ItemGroup>
</Project>
That's it. Worked for me(tm), tested. Let me be honest, I don't like this approach, but that was the only way I made it working in the needed way. It's up to you whether you'll use it in your project or not.
My opinion is not to use msdeploy here - it was not for you task.
Better to write msbuild-scripts from scratch or accept the 'bin' folder, and fight against the framework again once next customization is required.

Can partial config files linked to a web.config via configSource be transformed in a web project?

Looking for some help from anyone that's worked with SlowCheetah to transform config files under a web project. We're finding that partial config files referenced from the web.config are not being transformed.
For example, we've included references to partial configs AppSettings.config and ConnectionsString.config in the web.config like so:
</system.web>
<connectionStrings configSource ="ConnectionsString.config"></connectionStrings>
<appSettings configSource ="AppSettings.config"></appSettings>
</configuration>
and then in the AppSettings.config we have just the AppSettings section like so:
<appSettings>
<add key="LostPasswordBCC" value="knock#timmons.com" />
</appSettings>
and finally in the transform file AppSettings.Debug.config we have some additions:
<?xml version="1.0" encoding="utf-8" ?>
<!-- For more information on using transformations
see the web.config examples at http://go.microsoft.com/fwlink/?LinkId=214134. -->
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<appSettings >
<add key="Release" value="Something" xdt:Transform="Insert" />
</appSettings>
</configuration>
Obviously the above is just a test to see the transform occur, but what we're finding is that on attempting to preview the transform all we get back is an error "There was an error processing the transformation." The publish attempt also fails.
If we make the config files fully formed xml and not referenced from web.config, the transformation seems to work fine - but were looking to share these files across multiple projects.
Does anyone know if there's a workaround where we can both reference partial configs from the web.config and also have transforms off those partial files? We're dealing with legacy code with a large number of config files across multiple web projects that were attempting to consolidate, thus the need to link from web config to separate shared files.
Problem has been resolved, turns out after help from Sayed, we determined that in our efforts to understand the config transformation process with a web project we had corrupted the transform config file's format. With freshly created config files we were able to get transforms to work using SlowCheetah.
This allowed us to move on the real problem we needed to address which was wanting to transform project configs other than the web.config using Visual Studio 2012's publish profiles. This did not work originally, but again Sayed helped us out and provided a new copy of SlowCheetah that allowed this to work.
Below is a link to the new version of SlowCheetah with the fix: https://github.com/sayedihashimi/slow-cheetah/issues/46
Much thanks for all your time and patience Sayed.