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
Related
I'm creating Windows Runtime Component (c++) to use it later in windows phone 8.1 application (c#). My problem is preety simple but I cannot find any answer to it:
I need to create a method which take string/char */anything which is filepath as parameter and pass it to external method which takes char * as parameter.
I've tried with std::string, String^, char *. But I still get errors like such types are not supported (not in String^ case) or some other one.
Is there some simple answer which tells me how should I do this?
Code samples with errors
beginning
#include "pch.h"
#include "Class1.h"
using namespace Platform;
namespace WindowsRuntimeComponent2
{
public ref class Class1 sealed
{
various types:
int Foo(std::string param) {
cause: Foo': signature of public member contains native type 'std::basic_string<char,std::char_traits<char>,std::allocator<char>>' WindowsRuntimeComponent2 and few more containing same information about string's dependencies
int Foo(char * param) {
cause: 'Foo': signature of public member contains native type 'std::basic_string<char,std::char_traits<char>,std::allocator<char>>' WindowsRuntimeComponent2
int Foo(String^ photoPath) {
this one do not cause any errors but I don't know how to parse it to my char *.
Essentially here you just need to know how to convert from System.String^ to std::string, this can be done in C++/CLI mode as follows:
#include <msclr\marshal_cppstd.h>
//...
int Foo(String^ photoPath) {
std::string unmanaged_photoPath = msclr::interop::marshal_as<std::string>(photoPath);
// then convert to c-style string as normal using unmanaged_photoPath.c_str();
return 0;
}
I am trying to make use from C++ of a library that is written in C#. For this I was told to use COM Interop, about which I knew very little.
I am trying to pass a 1D array one way and get a 1D array back, but my return array ends up being just full of zeros.
In order to simplify the problem for this forum I have simplified my program: I don't even pass an input array.
My C# program looks like this
using System;
using System.Runtime.InteropServices;
namespace FillArray
{
[ComVisible(true)]
[Guid("DABAEF7C-D2B8-4769-98C8-1AF211EF7D48")]
public interface IFillArray
{
int fillTheArrayWithSquares(int[] array);
}
[ComVisible(true)]
[Guid("124A66FD-CED3-4a8e-B0F0-BAA88B421E97")]
public class Class1: IFillArray
{
public int fillTheArrayWithSquares(int[] array)
{
int len = array.Length;
int i;
for (i = 0; i < len; i++)
array[i] = i * i;
return len;
}
}
}
In the same solution I have a C++ Client that looks like this:
#import "D:\dev\CSharp\FillArray\FillArray\bin\Release\FillArray.tlb" raw_interfaces_only
#include "stdafx.h"
using namespace FillArray;
int _tmain(int argc, _TCHAR* argv[])
{
HRESULT hr = CoInitialize(NULL);
long retval;
IFillArrayPtr pIFillArray(__uuidof(Class1));
SAFEARRAY *output;
SAFEARRAYBOUND BoundOutput;
BoundOutput.cElements = 10;
BoundOutput.lLbound = 0;
output = SafeArrayCreate(VT_I4, 1, &BoundOutput);
int *p_output_contents;
HRESULT hrFill = pIFillArray->fillTheArrayWithSquares( output, &retval);
HRESULT hrOutput = SafeArrayAccessData(output, (void HUGEP**)&p_output_contents);
if(SUCCEEDED(hrFill) && SUCCEEDED(hrOutput))
{
for(int i = 0; i < 10; i++)
printf("%d ",p_output_contents[i]);
printf("\n");
printf("retval = %d\n",retval);
SafeArrayUnaccessData(output);// not robust error handling
SafeArrayDestroy(output);//not robust error handling logic
}
CoUninitialize();
return 0;
}
I have configured the C++ project to use /clr: oldsyntax because I am adapting an old article that recommended this. Unfortunately it looks like this is deprecated in VS 2008 (which I am using) and I will have trouble porting this to say VS2013.
So I have two questions:
1) Why is my C++ application printing 10 zeros?
2) How would I update my syntax to avoid /clr:oldsyntax.
One more remark: I have seen on some discussions that C# arrays dont correspond to SAFEARRAYS, but the choice of the type is what Intellisense tells me I should be using.
Thx.
Fir of all, there're 2 types of C++ projects in VS:
Native C++ project, without /clr option by default.
C++/CLI project, with /clr option by default. C++/CLI can access both native and managed world, so if you want use a C# DLL, just add this DLL as a reference and use it directly, you don't need COM for this case.
If the native C++ project wants to use C# DLL, one way is via COM, another way is use C++CLI project as a bridge.
If you use COM, then you have to deal with the SAFEARRAY, which is error prone. As to your question 1, you're using SAFEARRAY as an out parameter, this is complex. I suggest you just change the definition of function fillTheArrayWithSquares to:
public int[] fillTheArrayWithSquares( )
So it will return a SAFEARRAY to C++ code, and the lengh of SAFEARRAY is already contained in the SAFEARRAY.
I am in the need of using some functions in a C made program. To test I defined the following :
This is my .h file :
namespace amt
{
class AMT_EXPORT FaceRecognition
{
public:
std::string amt_test_string(std::string in);
};
};
This is my .cpp file :
#include <memory.h>
#include <string>
#include <iostream>
#include <fstream>
#include "api_shared.h"
#include <sys/stat.h>
using namespace std;
std::string amt::FaceRecognition::amt_test_string (std::string in)
{
std::string s="in: "+in;
std::cout<<s<<std::endl;
return s;
}
I am trying to invoke the method like this :
const string str = "C:\\minimal.dll";
[DllImport(str)]
public static extern string amt_test_string(string input);
static void Main(string[] args)
{
string myinput = "12";
string myoutput = "";
myoutput = amt_test_string(myinput);
Console.WriteLine(myoutput);
Console.Read();
}
But im getting an error saying that it cannot find the entry point named amt_test_string..why so? I am a newbie in C btw
That's not a C DLL, that's a C++ DLL. C and C++ are not the same language. In particular, C++ has name mangling, so the function name which gets exported to the DLL is decorated.
I'd strongly recommend that you avoid having C++ exports in your DLL for that reason. If you use only C exports, the symbol name will be predictable (i.e. will not depend on the specific details of how your C++ compiler decorates names), and you won't have to worry about runtime differences, like how your C++ standard library implements std::string.
I'd recommend your DLL export look like this:
extern "C" // This says that any functions within the block have C linkage
{
// Input is 'in', output gets stored in the 'out' buffer, which must be 'outSize'
// bytes long
void DLLEXPORT amt_FaceRecogniztion_amt_test_string(const char *in, char *out, size_t outSize)
{
...
}
}
This interface does not rely on any particular library's std::string implementation, and C# knows how to martial char* parameters as C strings. However, memory management is more complicated, as you need to figure out an upper bound on how big the output is going to be and pass in an appropriately sized bufer.
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 :-)
I'm working on a c++ project which uses a string path to call an XML file. When i compiled the c++ everything works perfectly and i'm able to use the XML file as my project requires.
I needed to use a C# GUI, so i made a wrapper to call all my functions from my C++ file. One problem arises after debugging between the both platforms, c# does not recognize the string path to call my file, the error that i got is that it can not find the given path. Does anyone know how to send a valid string path between both platforms?
Thanks in advance,
Carolina
int ClassUnmanaged::ReadFile(string path_to_file)
{
int status = XMLClass->ReadConfigFile(path_to_file);
if(status)
{
return status; //Error
}
else
{
return 0;
}
}
Wrapper.h for the C++ class
public __gc class Wrapper
{
public: Wrapper(void);
public: ~Wrapper(void);
/** Unmanaged pointer to Class Unmanaged API
*
*/
private: ClassUnmanaged__nogc* pointerUnmanaged;
public: int NewReadfile(string path_to_file);
}
Wrapper.cpp
int Wrapper::NewReadFile(string path)
{
pointerUnmanaged->ReadFile(path);//here i access to my class unmanaged
return 0;
}
UI.cs
In the UI.cs i can not call the function NewReadfile from the wrapper because of the string type that c++ uses. Any idea how to solve this?
You will need to change the NewReadFile method to public and then change it to take as input a type that C# know about like Sytem::String it should look like this (using the new managed C++ syntax adapt to the old one if needed)
int Wrapper::NewReadFile(System::String^ path)
{
char* pathAsCharArray = (char*)(void*)Marshal::StringToHGlobalAnsi(str);
try
{
std::string pathAsStdString(pathAsCharArray);
pointerUnmanaged->ReadFile(pathAsStdString);
}
finally
{
Marshal::FreeHGlobal(pathUnmanaged);
}
return 0;
}
There is a KB article named "How to convert from System::String* to Char* in Visual C++" that explain the concept. If your underlying API could support unicode and you use the new syntax a better way to do the conversion is something like :
pin_ptr<const wchar_t> pathAsCharArray = PtrToStringChars(path);
std::wstring pathAsStrign(pathAsCharArray);