I'm trying to convert a bit of VBA (outlook) to c# for an addin. Struggling with it. The code changes the account dropdown on the reply/replyall/forward form in outlook. Now I have to type more useless stuff because the editor is moaning about more code than text. I have converted 99% of it.
public string Set_Account(string AccountName, Outlook.MailItem M)
{
string tempSet_Account = null;
Outlook.Inspector OLI = null;
string strAccountBtnName = null;
int intLoc = 0;
const int ID_ACCOUNTS = 31224;
Office.CommandBars CBs = null;
Office.CommandBarPopup CBP = null;
Office.CommandBarControl MC = null;
M.Display();
OLI = M.GetInspector;
if (OLI != null)
{
CBs = OLI.CommandBars;
CBP = CBs.FindControl(, ID_ACCOUNTS); // This line errors and I can't find what goes in it to make it work
CBP.Reset();
if (CBP != null)
{
foreach (Office.CommandBarControl MCWithinLoop in CBP.Controls)
{
MC = MCWithinLoop;
intLoc = MCWithinLoop.Caption.IndexOf(" ") + 1;
if (intLoc > 0)
{
strAccountBtnName = MCWithinLoop.Caption.Substring(intLoc);
}
else
{
strAccountBtnName = MCWithinLoop.Caption;
}
if (strAccountBtnName == AccountName)
{
MCWithinLoop.Execute();
tempSet_Account = AccountName;
break;
}
}
}
}
tempSet_Account = "";
MC = null;
CBP = null;
CBs = null;
OLI = null;
return tempSet_Account;
}
I am having trouble with this line specifically:
CBP = CBs.FindControl(, ID_ACCOUNTS);
It fails and says it needs a type "MsoControlType" but I cannot find any control type that fits. It seems in VBA you can findcontrol with just one entry (the other being blank) In C# you need 2. Every thing I put it the compiler moans about
cannot convert Microsoft.Office.Core.MsoControlType.msoCommandBarControl to ...msoCommandBarPopup
But I cannot find a reference to it anywhere.
In C#, you can't leave out a parameter like you're doing here: ".FindControl(,". If you have to pass "null" or a null object.
Related
According to this post, you can make Visual Studio find.
I update the code of Asif Iqbal K from the article a bit to eliminate build error.
public const string vsWindowKindFindResults1 = "{0F887920-C2B6-11D2-9375-0080C747D9A0}";
public string FindInFiles(string searchText)
{
EnvDTE80.DTE2 dte;
dte = (EnvDTE80.DTE2)System.Runtime.InteropServices.Marshal.GetActiveObject("VisualStudio.DTE");
dte.MainWindow.Activate();
EnvDTE.Find find = dte.Find;
find.Action = EnvDTE.vsFindAction.vsFindActionFindAll;
find.FindWhat = searchText;
find.MatchWholeWord = false;
find.ResultsLocation = EnvDTE.vsFindResultsLocation.vsFindResults1;
find.Target = EnvDTE.vsFindTarget.vsFindTargetSolution;
find.PatternSyntax = EnvDTE.vsFindPatternSyntax.vsFindPatternSyntaxRegExpr;
find.SearchSubfolders = true;
var x = dte.Find.FindWhat;
EnvDTE.vsFindResult result = find.Execute();
var findWindow = dte.Windows.Item(vsWindowKindFindResults1);
string data = "";
System.Threading.Thread.Sleep(5000);//Comment out this code to see the problem, this line of code is not the solution though.
if (result == EnvDTE.vsFindResult.vsFindResultFound)
{
var selection = findWindow.Selection as EnvDTE.TextSelection;
selection.SelectAll();
data = selection.Text;
}
return data;
}
I see that the problem is the function return the string (string data) too early, so it can't get all the text from the result window.
So the code comes so close to get the find text. One remaining puzzle is to check if the find process complete, then get the text.
So the question is: replace what code with the code
System.Threading.Thread.Sleep(5000);
So that the function FindInFiles() can get all the text of 'FindResult 1" window.
Thanks for reading.
Here is the solution
EnvDTE80.DTE2 s_dte;
EnvDTE.FindEvents s_findEvents;
public const string vsWindowKindFindResults1 = "{0F887920-C2B6-11D2-9375-0080C747D9A0}";
public frmFindHelper()
{
InitializeComponent();
s_dte = (EnvDTE80.DTE2)System.Runtime.InteropServices.Marshal.GetActiveObject("VisualStudio.DTE");
s_dte.MainWindow.Activate();
s_findEvents = s_dte.Events.FindEvents;
s_findEvents.FindDone += new EnvDTE._dispFindEvents_FindDoneEventHandler(OnFindDone);
}
private void OnFindDone(EnvDTE.vsFindResult result, bool cancelled)
{
if (result == EnvDTE.vsFindResult.vsFindResultFound)
{
var findWindow = s_dte.Windows.Item(vsWindowKindFindResults1);
string data = "";
var selection = findWindow.Selection as EnvDTE.TextSelection;
selection.SelectAll();
data = selection.Text;
MessageBox.Show("Done!");
}
}
private void btnFind_Click(object sender, EventArgs e)
{
EnvDTE.Find find = s_dte.Find;
find.Action = EnvDTE.vsFindAction.vsFindActionFindAll;
find.FindWhat = txtSearch.Text;
find.MatchWholeWord = false;
find.ResultsLocation = EnvDTE.vsFindResultsLocation.vsFindResults1;
find.Target = EnvDTE.vsFindTarget.vsFindTargetSolution;
find.PatternSyntax = EnvDTE.vsFindPatternSyntax.vsFindPatternSyntaxRegExpr;
find.SearchSubfolders = true;
var x = s_dte.Find.FindWhat;
EnvDTE.vsFindResult result = find.Execute();
}
Thanks to Ed Dore from this post
I'm not a developer so maybe the answer is out there for a different solution but I can't really translate it from python or something else.
I'm trying to use the AWS .NET SDK to find an instance and then get the instance's tags. I've gotten as far as being able to determine if an instance is up and running or not. I also see how I can create and delete tags (not in code example below). But I don't see an easy way to actually check if a tag exists and get the value of the tag if it does exist.
Sorry if I'm missing the obvious but this is all new to me. Here's an example of the code I'm using to check if an instance is running.
instanceID = "i-myInstanceID";
do {
var myrequest = new DescribeInstanceStatusRequest();
DescribeInstanceStatusResponse myresponse = ec2.DescribeInstanceStatus(myrequest);
int isCount = myresponse.DescribeInstanceStatusResult.InstanceStatuses.Count;
for (int isc=0; isc < isCount; isc++) {
InstanceStatus instanceStatus = myresponse.DescribeInstanceStatusResult.InstanceStatuses[isc];
if (instanceStatus.InstanceId.Contains(instanceID)) {
Console.WriteLine("It looks like instance "+instanceID+" is running.");
idIdx = isc;
foundID = true;
break;
}
}
if ((foundID==false) && (secondCounter==1)) {
Console.Write("Looking for instance "+instanceID);
} else {
Console.Write(".");
}
Thread.Sleep(1000);
secondCounter++;
if (secondCounter > 5) {
break;
}
} while (foundID == false) ;
First send a DescribeInstancesRequest to get the list of Instances:
public DescribeInstancesResult GetInstances(Ec2Key ec2Key)
{
_logger.Debug("GetInstances Start.");
AmazonEC2 ec2 = CreateAmazonEc2Client(ec2Key);
var ec2Request = new DescribeInstancesRequest();
DescribeInstancesResponse describeInstancesResponse = ec2.DescribeInstances(ec2Request);
DescribeInstancesResult result = describeInstancesResponse.DescribeInstancesResult;
_logger.Debug("GetInstances End.");
return result;
}
Then loop through the instances until you find the one you want, and then use the Tag.GetTagValueByKey method:
// This just calls the above code
DescribeInstancesResult ec2Instances = _ec2ResourceAccess.GetInstances(ec2Key);
var returnInstances = new List<Ec2UtilityInstance>();
foreach (var reservation in ec2Instances.Reservation)
{
foreach (var runningInstance in reservation.RunningInstance)
{
var returnInstance = new Ec2UtilityInstance();
returnInstance.InstanceId = runningInstance.InstanceId;
returnInstance.InstanceName = runningInstance.Tag.GetTagValueByKey("Name");
returnInstance.Status = (Ec2UtilityInstanceStatus)Enum.Parse(typeof(Ec2UtilityInstanceStatus), runningInstance.InstanceState.Name, true);
returnInstance.DefaultIp = runningInstance.Tag.GetTagValueByKey("DefaultIp");
returnInstance.InstanceType = runningInstance.InstanceType;
returnInstance.ImageId = runningInstance.ImageId;
returnInstances.Add(returnInstance);
}
}
Here is the link for full source that this was taken from:
https://github.com/escherrer/EC2Utilities
Common\Manager
and
Common\ResourceAccess
I've been having a little weekend project for myselff which involves getting all my ToDo tasks from Outlook, put them in a DataGridView and me being able to edit and export them.
The only problem I've been running into is me being unable to get the task specific properties for flagged emails while they still exist, I just don't see any way to access them.
Here is a portion of my current code.
private void retrieveTasks()
{
//Clear datagrid so we won't have duplicate information
taskList.Rows.Clear();
//Define some properties so we can use these to retrieve the tasks
Outlook.Application app = null;
_NameSpace ns = null;
Store outlookStore = null;
Outlook.MAPIFolder taskFolder = null;
Outlook.MAPIFolder specialFolder = null;
TaskItem task = null;
DateTime nonDate = new DateTime(4501, 1, 1);
try
{
//Connect to Outlook via MAPI
app = new Outlook.Application();
ns = app.GetNamespace("MAPI");
ns.Logon(null, null, false, false);
/*
outlookStore = ns.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderInbox).Store;
taskFolder = outlookStore.GetSpecialFolder(Microsoft.Office.Interop.Outlook.OlSpecialFolders.olSpecialFolderAllTasks);
*/
//Get the taskfolder containing the Outlook tasks
//taskFolder = ns.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderTasks);
outlookStore = ns.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderInbox).Store;
taskFolder = outlookStore.GetSpecialFolder(OlSpecialFolders.olSpecialFolderAllTasks);
//Console.WriteLine(specialFolder.Items[1].Subject.ToString());
/*for (int i = 1; i <= specialFolder.Items.Count; i++)
{
//task = (Outlook.TaskItem)specialFolder.Items[i];
Console.WriteLine(specialFolder.Items[i].ToString());
}*/
for (int i = 1; i <= taskFolder.Items.Count; i++)
{
//Get task from taskfolder
Object item = taskFolder.Items[i];
if (item is Outlook.MailItem)
{
MailItem mail = (Outlook.MailItem)item;
if (mail.TaskCompletedDate.Equals(nonDate))
{
string percentComplete = "";
string taskPrio = "";
if (mail.UserProperties.Find("Prio") == null)
{
taskPrio = "";
}
else
{
taskPrio = mail.UserProperties.Find("Prio").Value.ToString();
}
//mail.UserProperties.
if (mail.UserProperties.Find("% Complete") == null)
{
percentComplete = "";
}
else
{
percentComplete = mail.UserProperties.Find("% Complete").Value.ToString();
}
//Add the tasks details to the datagrid
taskList.Rows.Add(
i.ToString(),
checkForNull(mail.Subject),
parseDate(mail.TaskStartDate.ToString()),
parseDate(mail.TaskDueDate.ToString()),
percentComplete, "Taak voltooid",
//statusToFriendlyName(mail.Status.ToString()),
taskPrio
);
}
}
else if (item is Outlook.TaskItem)
{
task = (Outlook.TaskItem)item;
Console.WriteLine(task.Subject);
if (task.Complete == false)
{
string taskPrio = "";
//Make sure custom task property is failed or set it to empty text to prevent crashes
if (task.UserProperties.Find("Prio") == null)
{
taskPrio = "";
}
else
{
taskPrio = task.UserProperties.Find("Prio").Value.ToString();
}
//Add the tasks details to the datagrid
taskList.Rows.Add(
i.ToString(),
task.Subject.ToString(),
parseDate(task.StartDate.ToString()),
parseDate(task.DueDate.ToString()),
task.PercentComplete.ToString(),
statusToFriendlyName(task.Status.ToString()),
taskPrio
);
}
}
}
}
catch (System.Runtime.InteropServices.COMException ex)
{
MessageBox.Show(ex.ToString());
}
finally
{
//Release Outlook sources
ns = null;
app = null;
}
}
So specifically I am looking for the "% complete" property and the status property, everything else I am able to work around on.
It would make my life SO MUCH EASIER if I can get this to work :)
Hope to hear from anyone on here!
Jeffrey
Do you mean you need to retrieve the task specific properties from a MailItem object (as opposed to the TaskItem object)?
Take a look at the message with OutlookSpy (I am its author) - click IMessage button, look at the MAPI properties in the GetProps tab. Any property can be accessed using MailItem.PropertyAccessor.GetProperty. The DASL name to be used by GetProperty is displayed by OutlookSpy (select the property in the IMessage window, see the DASL edit box).
I'm making an app where a use enters values for two times (starthour, startminute, endhour, endminute). I wrote a function that saves the values and then checks for value and puts the values inside the text boxes. However, it isn't working and I'm not sure why. I'm assuming its a mistake on my part, but I'm not exactly sure. Here's the code:
public async Task savedata()
{
while (true)
{
var localSettings = Windows.Storage.ApplicationData.Current.LocalSettings;
localSettings.Values["starthour1"] = starthour1.Text;
localSettings.Values["starthour2"] = starthour2.Text;
localSettings.Values["starthour3"] = starthour3.Text;
localSettings.Values["starthour4"] = starthour4.Text;
localSettings.Values["starthour5"] = starthour5.Text;
localSettings.Values["starthour6"] = starthour6.Text;
localSettings.Values["starthour7"] = starthour7.Text;
localSettings.Values["startminute1"] = startminute1.Text;
localSettings.Values["startminute2"] = startminute2.Text;
localSettings.Values["startminute3"] = startminute3.Text;
localSettings.Values["startminute4"] = startminute4.Text;
localSettings.Values["startminute5"] = startminute5.Text;
localSettings.Values["startminute6"] = startminute6.Text;
localSettings.Values["startminute7"] = startminute7.Text;
localSettings.Values["endhour1"] = endhour1.Text;
localSettings.Values["endhour2"] = endhour2.Text;
localSettings.Values["endhour3"] = endhour3.Text;
localSettings.Values["endhour4"] = endhour4.Text;
localSettings.Values["endhour5"] = endhour5.Text;
localSettings.Values["endhour6"] = endhour6.Text;
localSettings.Values["endhour7"] = endhour7.Text;
localSettings.Values["endminute1"] = endminute1.Text;
localSettings.Values["endminute2"] = endminute2.Text;
localSettings.Values["endminute3"] = endminute3.Text;
localSettings.Values["endminute4"] = endminute4.Text;
localSettings.Values["endminute5"] = endminute5.Text;
localSettings.Values["endminute6"] = endminute6.Text;
localSettings.Values["endminute7"] = endminute7.Text;
//get data
Object starthour1o = localSettings.Values["starthour1"];
if (starthour1o == null)
{
// No data
}
else
{
starthour1.Text = starthour1o.ToString();
}
Object starthour2o = localSettings.Values["starthour2"];
if (starthour2o == null)
{
// No data
}
else
{
starthour2.Text = starthour2o.ToString();
}
Object starthour3o = localSettings.Values["starthour3"];
if (starthour3o == null)
{
// No data
}
else
{
starthour3.Text = starthour3o.ToString();
}
Object starthour4o = localSettings.Values["starthour4"];
if (starthour4o == null)
{
// No data
}
else
{
starthour4.Text = starthour4o.ToString();
}
Object starthour5o = localSettings.Values["starthour5"];
if (starthour5o == null)
{
// No data
}
else
{
starthour5.Text = starthour5o.ToString();
}
Object starthour6o = localSettings.Values["starthour6"];
if (starthour6o == null)
{
// No data
}
else
{
starthour6.Text = starthour6o.ToString();
}
Object starthour7o = localSettings.Values["starthour7"];
if (starthour7o == null)
{
// No data
}
else
{
starthour7.Text = starthour7o.ToString();
}
await Task.Delay(10);
}
}
Two things you need to do, first you need to explicitly save your settings for them to be persisted by calling Save(). Somewhere in your code you need to do localSettings.Save() and it should work.
2nd, if you have saved settings the first thing your code does is overwrite them with the current values of the text boxes, the whole top section where it is localSettings.Values["Foo"] = Foo.Text needs to be moved to the bottom.
As a side comment, do you really need to be updating your code every 10 miliseconds? That is going to eat up a TON of resources in your program. A much more normal approach is load the values at start-up then save them at shutdown.
I am trying to set the Template property in the Summary Information Stram but whatever I do, it fails. I can read the property from the handle but can't write it back.
I want to generate multilingual copies of the MSI which is built (candled and light) in English. I am able to replace all the respective translated data in all the tables; the only thing I can not change is the Template property above.
I have tried all the ways I can use to pass the new String value, but it always says invalid parameter.
Here's the function I am using to do the same (C#):
public Boolean ChangeTemplateSummaryProperty(String strLangID) {
IntPtr hSIHandle;
if (MsiError.Success == MsiInterop.MsiGetSummaryInformation(IntPtr.Zero, m_strMSIPath, 1, out hSIHandle))
{
VariantType vtType = VariantType.LPStr;
int iVal = 0;
FILETIME oFileTime;
oFileTime.HighDateTime = 0;
oFileTime.LowDateTime = 0;
int iValSz = 0;
MsiError err = MsiInterop.MsiSummaryInfoGetProperty(hSIHandle, (uint)(SummaryInformationStreamProperty.Template),
out vtType, out iVal, out oFileTime, String.Empty, ref iValSz);
String strValue = new String('l', ++iValSz);
if (err == MsiError.MoreData)
{
err = MsiInterop.MsiSummaryInfoGetProperty(hSIHandle, (uint)(SummaryInformationStreamProperty.Template),
out vtType, out iVal, out oFileTime, strValue, ref iValSz);
}
else
{
Logger.LogError("Failed to get SummaryInformationStreamProperty.Template... err = " + err);
}
//I get the correct value here. as ";1033\0"
Logger.LogInfo("SummaryInformationStreamProperty.Template: " + strValue);
char[] arrNV = new char[strLangID.Length+2];
arrNV[0] = ';';
for (int i = 1; i < strLangID.Length + 1; i++) {
arrNV[i] = strLangID[i-1];
}
arrNV[strLangID.Length+1] = '\0';
String strNewVal = new String(arrNV);
//tried this, but fails.
//string strNV = ";";
//string strNV2 = strNV.Insert(1, strLangID);
//strNV2 = strNV2.Insert(strLangID.Length + 1, "\0");
err = MsiInterop.MsiSummaryInfoSetProperty(hSIHandle, (uint)(SummaryInformationStreamProperty.Template),
vtType, iVal, oFileTime, strNewVal);
if (err != MsiError.NoError)
{
Logger.LogError("Failed to set SummaryInformationStreamProperty.Template... err = " + err);
MsiInterop.MsiSummaryInfoPersist(hSIHandle);
MsiInterop.MsiCloseHandle(hSIHandle);
return false;
}
MsiInterop.MsiSummaryInfoPersist(hSIHandle);
MsiInterop.MsiCloseHandle(hSIHandle);
}
else
{
Logger.LogError("Failed to MsiGetSummaryInformation...");
return false;
}
return true;
}
Get rid of the MsiInterop that you are using and use the interop found in WiX's DTF. The Microsoft.Deploymnet.WindowsInstaller namespace has a SummaryInformation Class that exposes a read/write string Template property. Way better object model and interop without worrying about all the P/Invoke details that your current interop makes you deal with.
I'm home now so here's a code snippet:
using Microsoft.Deployment.WindowsInstaller;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
using( var database = new Database(#"C:\orca.msi", DatabaseOpenMode.Direct ))
{
database.SummaryInfo.Template = "Intel;666";
}
}
}
}
Notice the use of the using() clause. The Database class implements the IDisposable interface and automatically handles ( pun intended ) cleaning up all those pesky unmanaged handles for you.
Database msidb = objInstaller.OpenDatabase(MSIFileNameWithPath,MsiOpenDatabaseMode.msiOpenDatabaseModeTransact);
SummaryInfo info = msidb.get_SummaryInformation(1);
info.set_Property(2, (object)("sample title"));
info.Persist();
msidb.Commit();
The best reference to answer this is in detail is
https://learn.microsoft.com/en-us/archive/blogs/mwade/sail-away-with-me-to-another-world