I've encountered a problem when I try to retrieve the valid states of all features within an MSI package using the Microsoft.Deployment.WindowsInstaller.Installer class.
I want to copy the ValidStates property of each FeatureInfo within a Session. However when doing so I get a "Handle is in an invalid state." exception.
If I print each of these values out using Console.WriteLine() or step through the code in Visual Studio there is no exception.
I am at a loss as to what is preventing me from doing this.
Thanks in advance!
My Code:
var featureDictionary = new Dictionary<string, string[]>();
if (string.IsNullOrWhiteSpace(mPath))
return featureDictionary;
try
{
Installer.SetInternalUI(InstallUIOptions.Silent);
using (var session = Installer.OpenPackage(mPath, true))
{
foreach (var feature in session.Features)
{
try
{
var states = feature.ValidStates.Select((state) => state.ToString());
featureDictionary.Add(feature.Name, states.ToArray());
}
catch (InstallerException ex)
{
Debug.WriteLine(ex.Message);
}
}
}
}
catch (InstallerException) { }
return featureDictionary;
The basic problem appears to be that you are opening the MSI as a file. Since you haven't posted its declaration, or how it is set, I'm assuming that mpath means it's a path to the file. Your OpenPackage method parameters seem to indicate this too. You're getting that error because you are trying to open the MSI file as a file during the actual install, and failing.
The way to get hold of the database for the running install is to use Session.Database.
You can't open the running MSI as a file during the install perhaps for the same reason you can't run an MSI file that you have open with Orca, a simple file sharing violation. When you step through with Visual Studio you're simply accessing the static file and getting default values and the file isn't being used for an install. The other issue is that there can only be one Session object per process (as the OpenPackage docs say) and you are attempting to get a second one while there is already a Session object associated with the handle of the install.
As a custom action it needs to be sequenced after CostFinalize.
Windows Installer conditional expressions such as !feature-state will tell you what state the feature is in, because it's usually better to avoid code where Windows Installer will just give you the answer.
Related
I am attempting to check-out a single file via workspace.PendEdit with an exclusive lock LockLevel.CheckOut. The following function succeeds (no errors) but it seems to have no effect on the file in TFS (not checked-out and no lock).
public static void Lock(string filePath)
{
var workspace = GetWorkspace(filePath);
workspace.PendEdit(new[] {filePath}, RecursionType.None, null, LockLevel.CheckOut);
}
I am suspecting that this has something to do with my TFS Workspace being local. However, Visual Studio 2015 seems to have no problem establishing a lock on the file via [Source Control Explorer]->[Right Click Selected File]->[Advanced]->[Lock]. What am I doing that's different than what VS is doing? Am I missing something?
You should use RecursionType.Full not RecursionType.None.
workspace.PendEdit(new[] {filePath}, RecursionType.Full, null, LockLevel.CheckOut);
The PendEdit() method return the number of files that were checked out/locked for the filePath you specify. The RecursionType.Full will recurse to the last child of the path.
Update:
Please try to install this TFS nuget package(https://www.nuget.org/packages/Microsoft.TeamFoundationServer.ExtendedClient/) for your API project and test if this issue still exists. If it works, no matter what version of VS you use, this issue won't appear.
After much trial and error I ended up implementing an event handler for NonFatalError like this:
private static void VersionControlServer_NonFatalError(object sender, ExceptionEventArgs e)
{
if (e.Failure != null && e.Failure.Severity == SeverityType.Error)
throw new ApplicationException("An internal TFS error occurred. See failure message for details:\r\n"+e.Failure.Message);
}
Once the event handler was hooked up to the versionControlServer object via versionControlServer.NonFatalError += VersionControlServer_NonFatalError; I was able to see what was going on with my exclusive check-outs. As it turned out, TFS was failing silently with the following error:
TF400022: The item $/Fake/Server/Path/project.config cannot be locked for checkout in workspace MYWORKSPACE;Dan Lastname. Checkout locks are not supported in local workspaces.
The solution was to change the LockLevel from LockLevel.CheckOut to LockLevel.Checkin. Its a slightly different type of lock but its sufficient for my needs and that's the type of lock VS is using when you attempt to lock a file in a local workspace. So here is my original function with the tiny change in LockLevel that made all the difference.
public static void Lock(string filePath)
{
var workspace = GetWorkspace(filePath);
workspace.PendEdit(new[] {filePath}, RecursionType.None, null, LockLevel.Checkin);
}
I am attempting to create a copy of an existing dtsx file so I can change a few variables based on input from the user. I am able to make a copy of the file, look at the variables, and set the variables to the correct input. However, when I go to look at the file in Visual Studio I get a few errors.
Microsoft Visual Studio is unable to load this document: The package failed to load to to error 0xC0010014 "One or more error occurred. There should be more specific errors preceding this one that explains the details of the errors. This message is used as a return value from functions that encounter errors". This occurs when CPackage::LoadFromXML fails.
The errors contained in the error list:
Error 3 Error loading test.dtsx: Error loading value "<DTS:Property xmlns:DTS="www.microsoft.com/SqlServer/Dts" DTS:Name="PackageFormatVersion">6</DTS:Property>" from node "DTS:Property". E:\test.dtsx 1 1
The version number in the package is not valid. The version number cannot be greater than current version number.
I looked into these errors and I saw potential issues with the server year and visual studio year. Both of these are the 2008 version.
My code:
string pkgPath = #"\\server\TestFolder\test.dtsx"
app = new Microsoft.SqlServer.Dts.Runtime.Application();
pkg = app.LoadPackage(pkgPath, null);
Console.WriteLine(pkg.Variables["filename"].Value.ToString());
pkg.Variables["filename"].Value = "testFile";
Console.WriteLine(pkg.Variables["filename"].Value.ToString());
app.SaveToXml(pkgPath, pkg, null);
If I open the file I am using to make a copy of in Visual Studio, it works no problem -- something strange is happening when I do app.SaveToXML();
Any ideas or suggestion would be wonderful.
To run this as a process from DTEXEC, it would look something like below. Please check out these two links for further details about ProcessStartInfo and how to use /SET so you can add that to your argument. Test this from the command line first because the syntax can be finicky.
https://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo(v=vs.110).aspx
https://technet.microsoft.com/en-us/library/ms162810(v=sql.105).aspx
Using System.Diagnostics;
string args = #"/F'c:\MyPackage.dtsx' /SET'\package.variables[myvariable].Value;myvalue'";
ProcessStartInfo executePackage = new ProcessStartInfo("dtexec", args);
executePackage.UseShellExecute = false;
executePackage.RedirectStandardError = true;
executePackage.RedirectStandardOutput = true;
executePackage.CreateNoWindow = true;
StringBuilder output = new StringBuilder();
Process executing = Process.Start(executePackage);
while(!executing.StandardOutput.EndOfStream)
{
output.AppendLine(executing.StandardOutput.ReadLine();
}
executing.WaitForExit():
So i am currently building an application that allows a group of users to view all emails from a certain email address. This all works correctly. The problem I am encountering comes when i am trying to get the attachments.
I am relatively new to this area and used the example from Microsoft found here. Compare this to my code below:
protected internal override Stream GetAttachmentStreamFinal(MailAttachmentDetails attachment)
{
var response = m_service.GetAttachments(new[] { attachment.Id }, BodyType.Text, Enumerable.Empty<PropertyDefinitionBase>());
if (response.OverallResult != ServiceResult.Success)
{
if (response.Count > 0)
{
var ex = new MailException(response[0].ErrorMessage);
ex.Data.Add(response[0].ErrorCode, response[0].ErrorMessage);
foreach (var ed in response[0].ErrorDetails)
{
ex.Data.Add(ed.Key, ed.Value);
}
throw ex;
}
throw new MailException("Error occurred while fetching the attachment from the mail service.");
}
foreach (var attachmentResponse in response)
{
if (attachmentResponse.Attachment is FileAttachment)
{
var fa = attachmentResponse.Attachment as FileAttachment;
var cs = new MemoryStream(fa.Content);
fa.Load(cs);
cs.Seek(0, SeekOrigin.Begin);
return cs;
}
}
return null;
}
As you can see both sets of code are very similar. However when I step through and get to the attachmentResponse.Attachment is FileAttachment line I get this error thrown
Attempt by method 'Mail.ExchangeEmailService.GetAttachmentStreamFinal(Mail.MailAttachmentDetails)' to access method 'Microsoft.Exchange.WebServices.Data.GetAttachmentResponse.get_Attachment()' failed.
Everything is being passed in correctly and the response returns as success.
I have noticed when stepping through my code that Attachment shows as a non-public member. But as this is encapsulated in Microsofts class im unsure as to why that is the case or what i can do?
I just want to expand on #Jason Johnstons answer.
For some reason the version of EWS in NuGet is not correct. It throws the error that you are experiencing.
A workaround is to remove the reference to the NuGet package via
Uninstall-Package Microsoft.Exchange.WebServices
Then download and run the MSI file here
https://www.microsoft.com/en-us/download/details.aspx?id=42951
This will install the DLLs you require to the default location of
[ C:\Program Files\Microsoft\Exchange\Web Services\2.2 ]
Then simply copied they into your lib directory (or such) and created references to the DLLs directly instead.
Credit: http://www.resolvinghere.com/sm/microsoftexchangewebservicesdatagetattachmentresponsegetattachment-failed.shtml
As the other answers already mentioned, the nuget package from Microsoft is not up to date. I also had the same problem as the OP.
First I solved it by following the answer of Daniel - SDS Group. But then I found the nuget package Exchange.WebServices.Managed.Api from marklamley. It is the current version 2.2.1.1 of the ews-managed-api GitHub project.
Make sure you have the latest version of the Microsoft.Exchange.WebServices.dll. Older versions didn't return the actual attachment data when calling that particular overload of the GetAttachments method.
I'm currently building a registry explorer, mostly because I want to support some much better searching operations. Like 'find all' and regular expressions. One problem I'm facing is that some keys throw a security exception when opening. I HAVE TRIED running the app with administrator priviledges, my user account is an administrator also. I embedded a manifest with "requireAdministrator" requested priviledges. I have also tried setting the ClickOnce security settings to Full trust, which is incompatible with requireAdministrator, or so Visual Studio tells me.... Nothing seems to help with avoiding this exception.
I would just like to iterate over all of the keys. I do not wish to add/delete keys. If a user wishes to delete a key and does not have permission to do so, it would display an error message. I just want to be able to have unrestricted READ access. Is this possible?
FTR: I'm on Win7 x64 and using Vs2010u and project is written in C# on .net 4.0. If regedit is capable of reading all keys even if it doesn't let you edit some of them. It would seem appropriate that we too can make an app to do the same thing. Though I'm finding it very difficult, and there doesn't seem to be any real help on the www. Only link-link circles, yay.
[EDIT]
Here's the code that reads the keys:
private void IterateSubKeys(RegistryKeyModel key) {
var subKeys = key.Key.GetSubKeyNames();
var values = key.Key.GetValueNames();
foreach (var valuename in values) {
try {
var valueKind = key.Key.GetValueKind(valuename);
var value = key.Key.GetValue(valuename);
key.Values.Add(new RegistryValueModel(valuename, value, valueKind));
}
catch { }
}
foreach (var keyname in subKeys) {
try {
var subkey = key.Key.OpenSubKey(
keyname,
RegistryKeyPermissionCheck.ReadSubTree,
RegistryRights.ReadKey);
key.SubKeys.Add(new RegistryKeyModel(subkey));
}
catch { Console.WriteLine("Error reading key: {0}", keyname); }
}
}
This is by design. There are lots of security related keys that can only accessible to the System account. You can't use that account. Regedit can't read these keys either, they are just not visible. Avoiding the expensive exception is going to require pinvoke.
I've been trying to track down why my Office2010 plugin leaves a null pointer exception during uninstall and the 2007 version does not. (Edit: 2007 is at same state as 2010 - FAIL)
To narrow it down I have put in a couple of eventlog traps, meaning if code reaches this point - I should get something in the Eventlog. No such luck. Now either I written the eventlog trap wrong or code doesn't reach that point.
In the CustomSetupActions - ClickOnceInstaller.cs
public void Uninstall(System.Collections.IDictionary savedState)
{
// write something to eventlog
// This is not being fired, the exception doesn't reach here or writing to eventlog fails.
if (!EventLog.SourceExists("OfficePlugin"))
{
EventLog.CreateEventSource("OfficePlugin", "Application");
}
EventLog.WriteEntry
("OfficePlugin"
, string.Format("Uninstalling: (bug hunting)"), EventLogEntryType.Information);
string deploymentLocation = (string)savedState["deploymentLocation"];
if (deploymentLocation != null)
{
string arguments = String.Format(
"/S /U \"{0}\"", deploymentLocation);
ExecuteVSTOInstaller(arguments);
}
}
As for the ExecuteVSTOInstaller(string arguments)
2007 refers to: string subPath = #"Microsoft Shared\VSTO\9.0\VSTOInstaller.exe";
2010 refers to: string subPath = #"Microsoft Shared\VSTO\10.0\VSTOInstaller.exe";
If the first trap had fired, this is where I would have placed the trap afterwards.
--
I have another method that handles the registration db
RegisterOffice2010AddIn.cs
public void UnRegisterAddIn(string applicationName, string addInName)
{
Next line is precisely the same eventlog trap as I just used/shown.
Difference between the two (2007 vs 2010).
private const string UserSettingsLocation =
#"Software\Microsoft\Office\12.0\User Settings";
vs
private const string UserSettingsLocation =
#"Software\Microsoft\Office\14.0\User Settings";
I can't think of any other place that might be interesting to place the trap. I have a CustomInstaller which doesn't do anything besides Dispose(bool disposing) and InitializeComponent()
Development:
Action start 14:21:00: PublishFeatures.
Action ended 14:21:00: PublishFeatures. Return value 1.
Action start 14:21:00: PublishProduct.
Action ended 14:21:00: PublishProduct. Return value 1.
Action start 14:21:00: InstallExecute.
MSI (c) (B8:BC) [14:21:01:013]: Font created. Charset: Req=0, Ret=0, Font: Req=MS Shell Dlg, Ret=MS Shell Dlg
Error 1001. Error 1001. An exception occurred while uninstalling. This exception will be ignored and the uninstall will continue. However, the application might not be fully uninstalled after the uninstall is complete. --> Object reference not set to an instance of an object.
DEBUG: Error 2769: Custom Action _EE8A0D36_BE55_421F_9A55_95470C001D87.uninstall did not close 1 MSIHANDLEs.
The installer has encountered an unexpected error installing this package. This may indicate a problem with this package. The error code is 2769. The arguments are: _EE8A0D36_BE55_421F_9A55_95470C001D87.uninstall, 1,
Action ended 14:21:05: InstallExecute. Return value 3.
Action ended 14:21:06: INSTALL. Return value 3.
Googling the Error 2769 - gives an answer of "[TARGETDIR]\" , but I dont reference TargetDir, I reference deploymentLocation. And Yes I have tried adding the "\" to places I could think of. Including the setup - Registry - HKLM\Software\MS\Office\12.0\ ...etc... \Addins\Excel/Word/Outlook and the Manifest keyvalue. Gave no feedback, good or bad, errors or otherwise. I'm at a loss what else to try to hunt this one down.
I have a guess it is referencing to this, in the VDPROJ:
{
"Name" = "8:UnregisterOutlookAddIn"
"Condition" = "8:"
"Object" = "8:_73E71A44EB72485AB7367745F7D57F49"
"FileType" = "3:1"
"InstallAction" = "3:4"
"Arguments" = "8:"
"EntryPoint" = "8:"
"Sequence" = "3:3"
"Identifier" = "8:_EE8A0D36_BE55_421F_9A55_95470C001D87"
"InstallerClass" = "11:TRUE"
"CustomActionData" = "8:/addinName=\"OUR.Outlook.Outlook2010AddIn\" /application=\"Outlook\""
}
I found it throws two exception - the secondary under CustomSetupActions and UnregisterAddIn and the primary under ClickOnceInstaller and Uninstall. Howcome I mention them as 2ndary and primary. Well it will do the exception in CustomAction and then the killing one in ClickOnce. I've eliminated the one in CustomActions and I now only have to worry about the ClickOnce. From what I can gather the ClickOnce implements the interface specified in the Setup Project (Install, Rollback, Commit, Uninstall). I only have to figure out how it can run amiss the Uninstall method.
Disclaimer: Unless ofcourse I'm mistaken and is barking up the wrong tree.
Change to WiX. It became a workaround as the original is still true.