Different behavior with FindAll for AutomationElement between MC++ and C# - c#

I am trying to find the ControlType.DataItem children of a DataGrid control using UI automation in managed C++. The following snippet works from C# on a known HWND value:
var automationElement = AutomationElement.FromHandle(new IntPtr(0x000602AE));
var propertyCondition = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.DataItem);
var dataItems = automationElement.FindAll(TreeScope.Subtree, propertyCondition).Count;
Console.WriteLine("Found {0} DataItem(s)", dataItems);
This yields the following output:
Found 2 DataItem(s)
Converting the code to MC++ yields zero results. Here is the converted MC++ code:
auto automationElement = AutomationElement::FromHandle(IntPtr(0x000602AE));
auto propertyCondition = gcnew PropertyCondition(AutomationElement::ControlTypeProperty, ControlType::DataItem);
auto dataItems = automationElement->FindAll(TreeScope::Subtree, propertyCondition)->Count;
Console::WriteLine("Found {0} DataItem(s)", dataItems);
Has anyone else ran into this issue using UI Automation from managed C++? I've used MC++ for UIA in the past and this is the first difference that I have came across between using it from C#. Thanks in advance for any information.

I'm not sure why this happens, but it works whenever I extract the UI Automation code into another class and invoke it like that. I do not claim to be an expert on MC++ or how it loads the .NET framework, but this is how I fixed my issue.
Create the AutomatedTable Class
AutomatedTable.h
#pragma once
using namespace System;
using namespace System::Windows::Automation;
ref class AutomatedTable {
public:
AutomatedTable(const HWND windowHandle);
property int RowCount {
int get();
}
private:
AutomationElement^ _tableElement;
};
AutomatedTable.cpp
#include "StdAfx.h"
#include "AutomatedTable.h"
AutomatedTable::AutomatedTable(const HWND windowHandle) {
_tableElement = AutomationElement::FromHandle(IntPtr(windowHandle));
}
int AutomatedTable::RowCount::get() {
auto dataItemProperty = gcnew PropertyCondition(AutomationElement::ControlTypeProperty, ControlType::DataItem);
return _tableElement->FindAll(TreeScope::Subtree, dataItemProperty)->Count;
}
Invoke From main.cpp
main.cpp
#include "stdafx.h"
#include "AutomatedTable.h"
int main(array<System::String ^> ^args) {
auto automatedTable = gcnew AutomatedTable((HWND)0x000602AE);
Console::WriteLine("Found {0} DataItem(s)", automatedTable->RowCount);
return 0;
}
Output
Found 2 DataItem(s)
Any insight as to why this is any different would be much appreciated :-)

Related

How to find supported Direct3D Feature Levels

I would like to find which Direct 3D Feature Levels (shown here) are supported in my C# UWP program.
Note: I am doing this in trying to research possible answers to my question How do I know, in code, if RadialGradientBrush is not being shown correctly?
In C++, there is a call to D3D11CreateDevice that might possibly be useful, but there does not appear to be a C# equivalent.
Or, even better, might be the ID3D11Device, which has a GetFeatureLevel() call. Again, these are C++ items.
I figured this out:
C++ DLL:
#include "pch.h"
#include <wrl.h>
#include <d3d11_2.h>
#include "BKGraphicsDLL.h"
using Microsoft::WRL::ComPtr;
extern "C"
{
__declspec(dllexport) D3D_FEATURE_LEVEL GetGraphicsFeatureLevel()
{
HRESULT hr = E_FAIL;
D3D_FEATURE_LEVEL MaxSupportedFeatureLevel = D3D_FEATURE_LEVEL_9_1;
D3D_FEATURE_LEVEL FeatureLevels[] = {
D3D_FEATURE_LEVEL_11_1,
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
D3D_FEATURE_LEVEL_9_3,
D3D_FEATURE_LEVEL_9_2,
D3D_FEATURE_LEVEL_9_1
};
hr = D3D11CreateDevice(
NULL,
D3D_DRIVER_TYPE_HARDWARE,
NULL,
0,
FeatureLevels,
ARRAYSIZE(FeatureLevels),
D3D11_SDK_VERSION,
NULL,
&MaxSupportedFeatureLevel,
NULL
);
return MaxSupportedFeatureLevel;
}
}
An enum and a NativeMethods class to access the DLL in my MainPage C#:
public enum D3DFeatureLevel
{
D3D_FEATURE_LEVEL_9_1 = 0x9100,
D3D_FEATURE_LEVEL_9_2 = 0x9200,
D3D_FEATURE_LEVEL_9_3 = 0x9300,
D3D_FEATURE_LEVEL_10_0 = 0xa000,
D3D_FEATURE_LEVEL_10_1 = 0xa100,
D3D_FEATURE_LEVEL_11_0 = 0xb000,
D3D_FEATURE_LEVEL_11_1 = 0xb100,
D3D_FEATURE_LEVEL_12_0 = 0xc000,
D3D_FEATURE_LEVEL_12_1 = 0xc100
};
// used to get Graphics capabilities
internal static class NativeMethods
{
[DllImport("BKGraphicsDLL.dll", ExactSpelling = true)]
public static extern D3DFeatureLevel GetGraphicsFeatureLevel();
}
Wherever I need to Feature Level in my code, uses this line:
D3DFeatureLevel maxFeatureLevel = NativeMethods.GetGraphicsFeatureLevel();

How to pass List<int> from C# to C++ CLi?

I am beginner in C language family...
So, problem is - in my solution I have a repo (wrote in C#) that store List<int>, also I have an engine that (wrote in C++). So, I need pass List from C# implementation to C++ CLI for executing...
As far as I understood problem is C++ know how to work with std::vector and C# know how to work with List and I need somehow convert List to vector...
How to do it?
Any assumption appropriate.
EDIT
Sorry for misunderstanding, but my CLI works as a mapper for pure C++ implementation. So, as far as I understood from C# I need to pass my List to C++ CLI , C++ CLI will convert a List to vector and invoke another C++ file with pure C++ implementation.
This is my solution
h file
using namespace System;
using namespace System::Collections::Generic;
//forward declaration
class MathCore;
namespace MathCore_CLI_namespace
{
public ref class MathCore_CLI
{
public:
MathCore_CLI();
~MathCore_CLI();
int computeMulPlusVals(List<int>^ list_first, List<int>^ list_second);
//int computeMulPlusVals(std::vector<int> vect_first, std::vector<int> vect_second);
private:
MathCore * m_pMathCore;
};
}
cpp file
#include "stdafx.h"
#include "MathCore_CLI.h"
#include "..\Engine\MathCore.h"
#include <iostream>
#include <array>
using namespace System;
using namespace System::Collections::Generic;
namespace MathCore_CLI_namespace
{
const int size = 5;
int count = 0;
int arrayVal[size];
MathCore_CLI::MathCore_CLI()
{
m_pMathCore = new MathCore();
}
MathCore_CLI::~MathCore_CLI()
{
delete m_pMathCore;
}
int computeMulPlusVals(List<int>^ list_first, List<int>^ list_second)
{
return 0;
}
}
Error
What am I doind wrong?
C++ CLI directly supports List and you don't need a conversion. Here is a typical signature.
private: System::Void FooMethod( System::Collections::Generic::List<Int32>^ list )
Besides, In your updated question, you have a linker error.
Open C++ project properties, Find Linker and then Input. Add the location to your (EngineLib_Cli.dll) Library there
Also I found more optimized solution
int MathCore_CLI::computeMulPlusVals(array<int>^ arr_first, array<int>^ arr_second)
{
auto vec_first = std::vector<int>(arr_first->Length);
cli::pin_ptr<int> pPinnedFirst = &arr_first[0];
memcpy(vec_first.data(), pPinnedFirst, arr_first->Length * sizeof(int));
auto vec_second = std::vector<int>(arr_second->Length);
cli::pin_ptr<int> pPinnedSecond = &arr_second[0];
memcpy(vec_second.data(), pPinnedSecond, arr_second->Length * sizeof(int));
return m_pMathCore->computeMulPlusVals(vec_first, vec_second);
}
By steps
1) you need to create your vector
2) hold this memory in heap
3) just copy the data
It is going to be much more faster

How I can get map<string, int> from C++ to C#

I am trying to get map from dll c++
So I have to get the map and parsing it as dictionary in C# side.
I have tried to do below steps and it is not worked.
C++ code:
extern "C" __declspec(dllexport) map<string, int> createMap(string &fileName) {
ifstream infile(fileName);
vector<string> bitsLine;
bool headerEnded = false;
string line;
int i = 0;
int length = 0;
while (getline(infile, line)) {
if (headerEnded) {
bitsLine = split(line, ',');
signalsMap.insert({ bitsLine.at(0), length });
}
else {
if (line.find("HEADER_END") != std::string::npos) {
headerEnded = true;
}
}
length = infile.tellg();
i++;
}
return signalsMap;
}
C# code:
Dictionary<string, int> x = createMap("C:/users/asalah/source/repos/WindowsFormsApp3/WindowsFormsApp3/RR_Test2_3.csv");
The simple answer to this question is unfortunately "you shouldn't". You shouldn't export STL types from a dll in the first place, much less try to marshal them in C#. An STL type may vary in memory layout from compiler to compiler, C++ runtime to C++ runtime. It could cause very fragile code. So if you export a C function it should take a const char* instead of std::string for example.
What you could do could be to just marshal each key and value as they are made available. The advantage of this is that you don't have to do any work with memory management and it's fairly simple to integrate in what you already have, though I'm making no statement about performance.
Here is a short C++ and C# example to get you going on such a solution if it is of any help to you:
extern "C" __declspec(dllexport) void doFoo(void(*adder)(const char*, int32_t))
{
adder("Test", 346);
}
Below is the C# code for consuming this API. It should simply just add "Test" with the value 346 to the dictionary and nothing more. It does this by invoking a callback function which is a native shim around Dictionary.Add for the specified instance of the dictionary.
namespace Eff3
{
using System.Collections.Generic;
using System.Runtime.InteropServices;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate void DictionaryAdd(string key, int value);
class Program
{
[DllImport("TestDll", CallingConvention = CallingConvention.Cdecl)]
static extern void doFoo(DictionaryAdd callback);
static void Main()
{
var result = new Dictionary<string, int>();
doFoo(result.Add);
}
}
}
I've tested this on my machine, and I built the DLL in Visual C++ 2017 in x64 and disabled "Prefer 32-bit" in C#.

How to call C++ function takes Vector call from C#

I am working in C++ and creating library which analyses the data. I have created few classes which have functions taking C++ vector. Now I want to create UI in C# and call these classes. I am thinking to create API to call from C#.
Since data are arrays/vector then how can I call it from C#?
I would have just made this a comment, but my rep isn't high enough. There are some complications when using STL classes (such as vector or string) in a class library with C++. You can check here for some more info and possible solutions: I can pass std::string for a Dll and what i can do with DLL´s?
You need to create your own C++/CLI interop to achieve this.
Strongly recommend a nice book, "Expert C++/CLI" by Marcus Heege, quite a good read.
Here's my brief example:
// Program.cs
static void Main(string[] args)
{
List<string> someStringList = new List<string>();
someStringList.Add("Betty");
someStringList.Add("Davis");
someStringList.Add("Eyes");
NativeClassInterop nativeClass = new NativeClassInterop();
string testString = nativeClass.StringCat(someStringList);
}
// NativeClass.h, skipping this, it's obvious anyways
// NativeClass.cpp, normal C++ class, this was in some DLL project, don't need exports
#include "stdafx.h"
#include "NativeClass.h"
std::string NativeClass::StringCat(std::vector<std::string> stringList)
{
std::string result = "";
for(unsigned int i = 0; i < stringList.size(); i++)
{
if(i != 0)
{
result += " ";
}
result += stringList[i];
}
return result;
}
// NativeClassInterop.cpp, in same DLL project, but compile this file with /clr switch
#include <gcroot.h>
#using <System.dll>
#include <vector>
#include <string>
#include "NativeClass.h"
// Helper method
static std::string nativeStringFromManaged(System::String^ str)
{
System::IntPtr hGlobal =
System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi(str);
std::string nativeString((hGlobal.ToPointer() == 0)
? "" : (char*)hGlobal.ToPointer());
System::Runtime::InteropServices::Marshal::FreeHGlobal(hGlobal);
return nativeString;
}
// C++/CLI wrapper class
public ref class NativeClassInterop
{
public:
System::String^ StringCat(System::Collections::Generic::List<System::String^>^ someStringList)
{
// You get to do the marshalling for the inputs
std::vector<std::string> stringList;
for(int i = 0; i < someStringList->Count; i++)
{
stringList.push_back(nativeStringFromManaged(someStringList[i]));
}
NativeClass nativeClass;
std::string nativeString = nativeClass.StringCat(stringList);
// And for the outputs ;-)
System::String^ managedString = gcnew System::String(nativeString.c_str());
return managedString;
}
};

Best practice to share a struct from a C# program to a C++ win32 DLL?

What is the best practice to share memory of a struct from a C# program to a C++ win32 DLL?
I've used structs in managed shared memory using Boost between two C++ programs and it worked great. I'm lost on the best way to accomplish this between where the struct gets populated in the C# program and the C++ DLL that is an SNMP subagent.
Here's the C++ DLL:
//==================== Code Excerpt from the main cpp file ======================
#include "stdafx.h"
//================= Here we are setting up the shared memory area =====================
#pragma data_seg (".SHAREDMEMORY")
struct sharedData {
int sharedA;
int sharedB;
};
static sharedData A;
#pragma data_seg()
#pragma comment(linker,"/SECTION:.SHAREDMEMORY,RWS")
BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved )
{
return TRUE;
}
//=============================================================================================
//====================== Here we are writing wrappers to the shared memory area ===========================
//=You must declare it as an Extern "C" to prevent name mangling. This is absolutely necessary in order to import it into c# =
//=============================================================================================
extern "C" __declspec(dllexport) sharedData __stdcall getMyData()
{
A.sharedA = 1237;
A.sharedB = 31337;
//return gshared_nTest;
return A;
}
extern "C" __declspec(dllexport) void __stdcall setMyData( sharedData buff )
{
A = buff;
}
Here's the calling C# function:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace sharedMemTestCS
{
public partial class frmSharedMemTestCS : Form
{
struct sharedData {
int sharedA;
int sharedB;
};
static sharedData A;
//============== here we are importing the methods from the win32 dll into the c# console application =================
[DllImport(#"C:\Documents and Settings\My Documents\Visual Studio 2010\Projects\sharedMemTestCPP\Debug\sharedMemTestCPP.dll")]
public static extern sharedData getMyData();
[DllImport(#"C:\Documents and Settings\My Documents\Visual Studio 2010\Projects\sharedMemTestCPP\Debug\sharedMemTestCPP.dll")]
public static extern void setMyData(int data);
public frmSharedMemTestCS()
{
InitializeComponent();
//============== here i am incrementing the value =================
//== i use a message box so that i can have multiple console applications running at once and it will pause at the messagebox (if i don't click ok)
//== i do this so i can see the values changing in the shared memory.
//MessageBox.Show( getMyData().ToString() );
getMyData();
//txtBoxA.Text = (getMyData().ToString() );
}
private void btnAdd_Click(object sender, EventArgs e)
{
//setMyData( getMyData() + 100 );
//txtBoxA.Text = (getMyData().ToString() );
}
}
}
The error message I get is:
Error 1 Inconsistent accessibility: return type
'sharedMemTestCS.frmSharedMemTestCS.sharedData' is less accessible
than method
'sharedMemTestCS.frmSharedMemTestCS.getMyData()' c:\documents and
settings\mconrad\my documents\visual studio
2010\Projects\sharedMemTestCS\sharedMemTestCS\Form1.cs 23 37 sharedMemTestCS
The best practice for sharing memory would be to use the MemoryMappedFile class in C# and CreateFileMapping/MapViewOfFile in C++.
First thing, you cannot straightway use Boost for data sharing. You need to have some well-defined data-structures that you share between the managed and unmanaged worlds.
You may start here
Well your actual problem is your p/invoke expression is public but your struct is private, which is what the error is telling you. Making your p/invoke expression private or your struct public will resolve the immediate issue.
As for the actual data sharing, I've never tried doing it quite like that so I can't tell you if it will or won't work. All the pieces I've worked with are marshalled back and forth. Looking at your example code, it's quite possible it could work. You'll probably want to either copy the data to a new struct for c# or pin your struct that you get back so the GC won't move it around in memory.

Categories

Resources