How to get output value (customOut) from EnvDTE Commands.Raise method? - visual-studio

I am writing a Visual Studio 2012 add-in that needs to send a command to the built-in T-SQL Editor. The command in question, sqlEditorSqlDatabaseCommand, can be used to either set or get the name of the current database in the editor. Here is some (working) code that sets the database name:
const string guidSqlEditorCommandSet = "b371c497-6d81-4b13-9db8-8e3e6abad0c3";
const int sqlEditorSqlDatabaseCommand = 0x312;
object customIn = "myDatabaseName";
object customOut = null;
m_applicationObject.Commands.Raise(guidSqlEditorCommandSet, sqlEditorSqlDatabaseCommand, ref customIn, ref customOut);
The problem is, I need to get the current database name, which would require use of the customOut parameter, and I can't figure out how to make customOut work.
The implementation of sqlEditorSqlDatabaseCommand is as follows (via Reflector):
protected override int HandleExec(uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut)
{
AuxiliaryDocData auxiliaryDocDataForEditor = base.GetAuxiliaryDocDataForEditor();
if (auxiliaryDocDataForEditor != null)
{
QueryExecutor queryExecutor = auxiliaryDocDataForEditor.QueryExecutor;
if (queryExecutor != null)
{
if (pvaIn != IntPtr.Zero)
{
string objectForNativeVariant = (string) Marshal.GetObjectForNativeVariant(pvaIn);
this.SetDatabase(auxiliaryDocDataForEditor, objectForNativeVariant);
}
else if (pvaOut != IntPtr.Zero)
{
object database = string.Empty;
IDbConnection connection = queryExecutor.ConnectionStrategy.Connection;
if (((connection != null) && (connection.State == ConnectionState.Open)) && !string.IsNullOrEmpty(connection.Database))
{
database = connection.Database;
}
else
{
database = string.Empty;
}
Marshal.GetNativeVariantForObject(database, pvaOut);
}
}
}
return 0;
}
According to every marshaling example I've seen, I should be able to pass null for both customIn and customOut, and the database name should be placed in customOut. When I do this, I get an E_INVALIDARG exception from Commands.Raise:
System.ArgumentException: The parameter is incorrect. (Exception from HRESULT: 0x80070057 (E_INVALIDARG))
at EnvDTE.Commands.Raise(String Guid, Int32 ID, Object& CustomIn, Object& CustomOut)
at RDSVisualStudioAddIn.Exec(String commandName, vsCommandExecOption executeOption, Object& varIn, Object& varOut, Boolean& handled) in c:\RDS\RDSVisualStudioAddIn\Connect.cs:line 193
Has anyone used Commands.Raise with the customOut parameter?

Related

CertSetCertificateContextProperty returning true but no changes in the certificate

so I have an issue now with Windows Certificates. I have a list of certificates (identified by SerialNumber/Thumbprint) for which I have to set EnhancedKeyUsage
So what I would like to happen is for a certificate:
From code to "Enable only for following purposes" and only "Client Authentication" to be selected, basically I would like to set a specific certificate as client auth certificate.
So the end-result should be :
Now from what I've read only ( information is very limited) I found that I should use CertSetCertificateContextProperty from Crypt32.dll.
My code looks like this:
public async Task<bool> SetAuthKeyUsageExtension(string certThumbprint)
{
//open certificate store for Read/Write
using X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadWrite);
//find certificate
var certificate = FindCertificate(certThumbprint, store);
if (certificate != null)
{
//set EKU for Client Auth
SetKeyExtangeUsage(certificate);
return true;
}
return false;
}
private X509Certificate2 FindCertificate(string thumbPrint, X509Store store)
{
X509Certificate2Collection foundX509Certificates = store.Certificates.Find(X509FindType.FindByThumbprint, thumbPrint, false);
if (foundX509Certificates != null || foundX509Certificates.Count > 0)
{
return foundX509Certificates.FirstOrDefault();
}
return null;
}
My native class looks like this:
[DllImport("Crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern Boolean CertSetCertificateContextProperty(
[In] IntPtr pCertContext,
[In] UInt32 dwPropId,
[In] UInt32 dwFlags,
[In] IntPtr pvData);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct CRYPT_OBJID_BLOB
{
public uint cbData;
public IntPtr pbData;
}
private const string OID_PKIX_KP_CLIENT_AUTH = "1.3.6.1.5.5.7.3.2";
private const int CERT_ENHKEY_USAGE_PROP_ID = 9;
public static bool SetKeyExtangeUsage(X509Certificate2 cert)
{
//Create a new Oid collection
OidCollection oids = new OidCollection();
//add to collection
oids.Add(new Oid
{
Value = OID_PKIX_KP_CLIENT_AUTH
});
X509EnhancedKeyUsageExtension eku = new X509EnhancedKeyUsageExtension(oids, true);
//pbData
var pbData = Marshal.AllocHGlobal(eku.RawData.Length);
CRYPT_OBJID_BLOB objID = new CRYPT_OBJID_BLOB();
IntPtr pvData = Marshal.AllocHGlobal(Marshal.SizeOf(objID));
objID.pbData = pbData;
objID.cbData = (uint)eku.RawData.Length;
Marshal.StructureToPtr(objID, pvData, false);
// var result = CertSetCertificateContextProperty(cert.Handle, CERT_ENHKEY_USAGE_PROP_ID, 0, objID.pbData);
var result = CertSetCertificateContextProperty(cert.Handle, CERT_ENHKEY_USAGE_PROP_ID, 0, pvData);
Marshal.FreeHGlobal(objID.pbData);
Marshal.FreeHGlobal(pvData);
return true;
}
This code "works" in terms that it does not break or throw any errors, but when I check the certificate using the UI, no Extended Key Usage are changed, basically it looks like I did nothing. I am sure I am missing something, but I have very few experience with X509Certificate2 and also Interop so I am guessing that somewhere in SetKeyExtangeUsage I am missing something. 5
I used this How to set certificate purposes? as reference, but there is no working code there, only steps, which I think I followed.
Any ideas, what I am missing?
NEDIT: Now running the same code I get this error:
"Attempted to read or write protected memory. This is often an indication that other memory is corrupt."
EDIT2: Changed pbData to pvData as mentioned.
EDIT3: Changed function
public static bool SetClientAuthEKU(X509Certificate2 cert)
{
OidCollection oids = new OidCollection();
oids.Add(new Oid
{
Value = OID_PKIX_KP_CLIENT_AUTH
});
X509EnhancedKeyUsageExtension eku = new X509EnhancedKeyUsageExtension(oids, true);
CRYPT_OBJID_BLOB objID = new CRYPT_OBJID_BLOB();
//allocate space in memory
IntPtr pbData = Marshal.AllocHGlobal(eku.RawData.Length);
IntPtr pvData = Marshal.AllocHGlobal(Marshal.SizeOf(objID));
//copy eku raw data into pbData
Marshal.Copy(eku.RawData, 0, pbData, eku.RawData.Length);
//set CRYPT_OBJECT value with ekuRaw data and Length
objID.pbData = pbData;
objID.cbData = (uint)eku.RawData.Length;
//copy CRYPT OBJECT into IntPtr
Marshal.StructureToPtr(objID, pvData, false);
var result = CertSetCertificateContextProperty(cert.Handle, CERT_ENHKEY_USAGE_PROP_ID, 0, pvData);
Marshal.FreeHGlobal(objID.pbData);
Marshal.FreeHGlobal(pvData);
return true;
}
EDIT4:
The problem is that you pass actual raw data (without length indicator) to CertSetCertificateContextProperty function, while it must be a pointer to CRYPTOAPI_BLOB. That is, last parameter of CertSetCertificateContextProperty function must be pvData.
The mistake can be easily detected by finding usages of pvData in your code. You write structure into pvData pointer, but the pointer is not used anywhere in the code.
Update:
I just noticed that you don't put anything in pbData. You allocate the buffer, but don't write anything there. You have to copy extension's raw data into pbData buffer.

Iaccessible interface , call to accChild[] does not give child element name , accChildCount returns the count properly

I have written the below functions in C# (GetObjectByName and GetAccessibleChildren) by calling oleacc.dll. I am not able to understand when there is child of child items, it is not getting their name, i get the error "entry point not found" in accessibility.dll. Can someone help me what is happening, accChildCount gives the number correctly, but calling accChild[] doesnt give the child of child items.
IntPtr vsHandle = Process.GetProcessById(vsProcessId).MainWindowHandle;
IAccessible Paccessible = GetWindowAccessibleByHwnd(vsHandle);
IAccessible vaccessible = GetObjectByName(Paccessible, " UTF-8");
Details of the functions is below
using System.Runtime.InteropServices;
using System.Diagnostics;
using Accessibility;
[System.Runtime.InteropServices.DllImport("oleacc.dll", PreserveSig = false, CharSet = System.Runtime.InteropServices.CharSet.Auto, SetLastError = true)]
[return: System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.Interface)]
public static extern int AccessibleChildren(IAccessible paccContainer, int iChildStart, int cChildren, [Out] object[] rgvarChildren, ref int pcObtained);
public static IAccessible[] c(IAccessible accContainer)
{
// Get the number of child interfaces that belong to this object.
int childNum = 0;
try
{
childNum = accContainer.accChildCount;
Console.WriteLine("Child count is " + childNum);
}
catch (Exception ex)
{
childNum = 0;
}
// Get the child accessible objects.
IAccessible[] accObjects = new IAccessible[childNum];
int count = 0;
if (childNum != 0)
{
AccessibleChildren(accContainer, 0, childNum,
accObjects, ref count);
}
return accObjects;
}
public static IAccessible GetObjectByName(IAccessible Parent, string Name)
{
// Return null if Parent is Null or not a COM Object
if (Parent == null || !Marshal.IsComObject(Parent))
{
return null;
}
// Return the Parent if the parent matches the name
if (Parent.accName[0] != null && Parent.accName[0].Equals(Name))
{
return Parent;
}
// Recursively check the child objects
IAccessible[] children = GetAccessibleChildren(Parent);
foreach (IAccessible child in children)
{
//Console.WriteLine("Got Child as " + child.get_accName(0));
Console.WriteLine("Name" + child.accName);
IAccessible objAcc = GetObjectByName(child, Name);
if (objAcc != null) return objAcc;
}
// If we're still here then return null
return null;
}

CrmServiceClient cannot be instantiated

We have a situation where the CrmServiceClient class cannot be instantiated, with an 'Object reference not set to an object' error coming from deep within the bowels of the constructor. I've also received a Collection was modified; enumeration operation may not execute error in a few situations.
This does not happen all the time, but we seem to be able to reproduce it when we trigger multiple requests very quickly.
We create the object as follows:
var ctx = new CrmServiceClient(ConfigurationManager.ConnectionStrings["Xrm"].ConnectionString);
The connection string is valid and we have set RequireNewInstance to true
We were originally using the ctx in a using block but we were advised that we shouldn't be disposing of the CrmServiceClient, so we've removed the using block, but this has not resolved the problem.
The stack trace is below - i've only pasted the relevant part. The stack leading up to this point can be any piece of code that attempts to connect to the CRM to retrieve data
at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
at System.Collections.Generic.List`1.Enumerator.MoveNextRare()
at System.Collections.Generic.List`1.Enumerator.MoveNext()
at Microsoft.Xrm.Tooling.Connector.Utilities.GetOrgnameAndOnlineRegionFromServiceUri(Uri serviceUri, String& onlineRegion, String& organizationName, Boolean& isOnPrem)
at Microsoft.Xrm.Tooling.Connector.CrmConnection.SetOrgnameAndOnlineRegion(Uri serviceUri)
at Microsoft.Xrm.Tooling.Connector.CrmConnection..ctor(String serviceUri, String userName, String password, String domain, String homeRealmUri, String authType, String requireNewInstance, String clientId, String redirectUri, String tokenCacheStorePath, String loginPrompt, String certStoreName, String certThumbprint, String skipDiscovery)
at Microsoft.Xrm.Tooling.Connector.CrmConnection..ctor(IDictionary`2 connection)
at Microsoft.Xrm.Tooling.Connector.CrmConnection.Parse(String connectionString)
at Microsoft.Xrm.Tooling.Connector.CrmServiceClient.ConnectToCrmWebService(String crmConnectionString)
at Microsoft.Xrm.Tooling.Connector.CrmServiceClient..ctor(String crmConnectionString)
I believe I've tracked down the issue. I used DotNetPeek to look at the underlying code that was failing. The static method GetOrgnameAndOnlineRegionFromServiceUriwas where the error was occurring.
I tracked it down to a static list (discoSvcs) that was being set to null before the method returns. Other threads that call this method are also trying to do things with this list. It ends up that there is a race condition where one thread could check to see if it isn't null.
The only way I can get around it now is making sure only one CrmServiceClient is being instantiated at any time, by using a lock. This isn't ideal but I am running out of time
Static list definition
namespace Microsoft.Xrm.Tooling.Connector
{
public class Utilities
{
private static CrmOnlineDiscoveryServers discoSvcs;
private static List<string> _autoRetryRetrieveEntityList;
private Utilities()
{
}
Problem Function
The static list variable is checked at the beginning of this function and if it is null, it is populated with some values. It is then used later in the method before being set to null in the finally block.
public static void GetOrgnameAndOnlineRegionFromServiceUri(
Uri serviceUri,
out string onlineRegion,
out string organizationName,
out bool isOnPrem)
{
isOnPrem = false;
onlineRegion = string.Empty;
organizationName = string.Empty;
if (serviceUri.Host.ToUpperInvariant().Contains("DYNAMICS.COM") || serviceUri.Host.ToUpperInvariant().Contains("MICROSOFTDYNAMICS.DE") || (serviceUri.Host.ToUpperInvariant().Contains("MICROSOFTDYNAMICS.US") || serviceUri.Host.ToUpperInvariant().Contains("DYNAMICS-INT.COM")))
{
if (Utilities.discoSvcs == null)
Utilities.discoSvcs = new CrmOnlineDiscoveryServers();
try
{
List<string> stringList = new List<string>((IEnumerable<string>) serviceUri.Host.Split(new string[1]
{
"."
}, StringSplitOptions.RemoveEmptyEntries));
organizationName = stringList[0];
stringList.RemoveAt(0);
StringBuilder stringBuilder = new StringBuilder();
foreach (string str in stringList)
{
if (!str.Equals("api"))
stringBuilder.AppendFormat("{0}.", (object) str);
}
string crmKey = stringBuilder.ToString().TrimEnd('.').TrimEnd('/');
stringBuilder.Clear();
if (!string.IsNullOrEmpty(crmKey))
{
CrmOnlineDiscoveryServer onlineDiscoveryServer = Utilities.discoSvcs.OSDPServers.Where<CrmOnlineDiscoveryServer>((Func<CrmOnlineDiscoveryServer, bool>) (w =>
{
if (w.DiscoveryServer != (Uri) null)
return w.DiscoveryServer.Host.Contains(crmKey);
return false;
})).FirstOrDefault<CrmOnlineDiscoveryServer>();
if (onlineDiscoveryServer != null && !string.IsNullOrEmpty(onlineDiscoveryServer.ShortName))
onlineRegion = onlineDiscoveryServer.ShortName;
}
isOnPrem = false;
}
finally
{
Utilities.discoSvcs.Dispose();
Utilities.discoSvcs = (CrmOnlineDiscoveryServers) null;
}
}
else
{
isOnPrem = true;
if (((IEnumerable<string>) serviceUri.Segments).Count<string>() < 2)
return;
organizationName = serviceUri.Segments[1].TrimEnd('/');
}
}

Failed to create a 'System.Char' from the text '#' in WP7.1

I'm creating MaskedTextBox in WP7.1 In that i want to set the Prompt char as '#'.
For ex: ##-##-#### ##:##. While running this i got an error message as
Failed to create a 'System.Char' from the text '#'
Please anyone can help me....
Please, post more details regarding your exception.
Also, consider using standard PasswordBox with PasswordChar property:
<PasswordBox PasswordChar="#"/>
UPDATE:
Use this char converter on your PromptChar property:
public class CharTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
return true;
return base.CanConvertFrom(context, sourceType);
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
return true;
return base.CanConvertTo(context, destinationType);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value == null)
return '_';
if (value is string)
{
string s = (string)value;
if (s.Length == 0 || s.Length > 1)
return '_';
return s[0];
}
return base.ConvertFrom(context, culture, value);
}
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if (value != null && !(value is char))
throw new ArgumentException("Invalid prompt character", "value");
if (destinationType == typeof(string))
{
if (value == null)
return String.Empty;
char promptChar = (char)value;
return promptChar.ToString();
}
return base.ConvertTo(context, culture, value, destinationType);
}
}
Usage:
[TypeConverter(typeof(CharTypeConverter))]
public char PromptChar
{
get { ... }
set { ... }
}

Error updating Sharepoint List item, when called from web service

I'm using ajax to call a webservice which updates a sharepoint list.
It works when I call the code from unit tests, but running the code in a browser causes an exception:
System.InvalidOperationException: Operation is not valid due to the current state of the object.
at Microsoft.SharePoint.WebControls.SPControl.SPWebEnsureSPControl(HttpContext context)
at Microsoft.SharePoint.WebControls.SPControl.GetContextWeb(HttpContext context)
at Microsoft.SharePoint.SPContext.get_Current()
at Microsoft.SharePoint.SPListItem.AddOrUpdateItem(Boolean bAdd, Boolean bSystem, Boolean bPreserveItemVersion, Boolean bNoVersion, Boolean bMigration, Boolean bPublish, Boolean bCheckOut, Boolean bCheckin, Guid newGuidOnAdd, Int32& ulID, Object& objAttachmentNames, Object& objAttachmentContents, Boolean suppressAfterEvents)
at Microsoft.SharePoint.SPListItem.UpdateInternal(Boolean bSystem, Boolean bPreserveItemVersion, Guid newGuidOnAdd, Boolean bMigration, Boolean bPublish, Boolean bNoVersion, Boolean bCheckOut, Boolean bCheckin, Boolean suppressAfterEvents)
at Microsoft.SharePoint.SPListItem.Update()
My code to update the list item is:
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite site = new SPSite(siteURL))
{
using (SPWeb web = site.OpenWeb(path))
{
SPList userProfile = web.Lists[userList];
SPQuery qry = new SPQuery
{
Query =
"<Where><Eq><FieldRef Name='Title' /><Value Type='Text'>" +
accountName +
"</Value></Eq></Where><ViewFields><FieldRef Name='ID' /><FieldRef Name='Title' /><FieldRef Name='LastUpdated' /><FieldRef Name='Reason' /></ViewFields>"
};
SPListItemCollection spListItemCollection = userProfile.GetItems(qry);
if (spListItemCollection.Count == 1)
{
//edit user
SPListItem item = spListItemCollection[0];
item["Updated"] = DateTime.Now;
item["Reason"] = updateReason;
item.Update();
}
}
}
});
It errors on item.Update();
Try adding this:
HttpContext context = HttpContext.Current;
if (HttpContext.Current != null)
{
if (context.Items["HttpHandlerSPWeb"] == null)
context.Items["HttpHandlerSPWeb"] = site.RootWeb;
if (context.Items["Microsoft.Office.ServerContext"] == null)
context.Items["Microsoft.Office.ServerContext"] = ServerContext.GetContext(site);
}
The problem was with security. The following line needs to be added (although not ideal)
web.AllowUnsafeUpdates = true;
I also removed the line
SPSecurity.RunWithElevatedPrivileges(delegate()
and changed the SPSite and SPWeb to not use "using".

Resources