I have the following C++ function from the MyCppLib.h file of a third party library:
int CppFunc(int Index, wchar_t* String, int StringLength);
where the maximum length of String is StringLength. String is returned by the function (out).
I am trying to wrap this in C++/CLI for use in C#. According to this page it looks like StringBuilder should be used to marshall wchar_t* back to C++/CLI.
So I believe the C++/CLI should look something like this:
#include "MyCppLib.h"
using namespace System;
using namespace System::Text;
namespace MyCppCliLib
{
int CppCliFunc(int Index, StringBuilder^ sB, int StringLength) {
return ::CppFunc(Index, ???, StringLength);
}
}
Now, how can I retrieve the wchar_t* from C++ back to StringBuilder^ ? I can't find a good example on the topic...
I believe the C# side would then looks like:
StringBuilder sB = new StringBuilder();
int x = CppCliFunc(2, sB, 4096);
EDITS:
Thanks to all the comments, I finally got something working, it looks like this (don't quote me on it, it's my first steps in C++/CLI):
#include "MyCppLib.h"
#include <string.h>
#include <stdlib.h>
using namespace System;
using namespace System::Text;
namespace MyCppCliLib
{
String^ CppCliFunc(int Index, int StringLength) {
String^ newString="";
wchar_t* wchar = (wchar_t*)calloc(StringLength, sizeof(wchar_t));
if (wchar != NULL) {
int errorInt = ::CppFunc(Index, wchar, StringLength);
newString = gcnew String(wchar);
if(errorInt != 0){
throw gcnew Exception("Error #" + errorInt.ToString());
}
}else{
throw gcnew Exception("Error wchar is null");
}
free(wchar);
return newString;
}
}
Related
I've written c# code for a registry modifying application, but the problem is c# is easily reversible and obfuscators make the program look like malware. So my problem is that I can't find anything close to Registry.SetValue for c++. Any help is appreciated.
I've tried using a c# to c++ tool by tangible but it was bad and it didn't work as expected at all.
I've also tried RegSetValueEx but I think I used it incorrectly.
This is what I tried:
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <Windows.h>
using namespace std;
int main()
{
HKEY key;
if (RegOpenKey(HKEY_LOCAL_MACHINE, TEXT("Software\\Microsoft\\Windows\\CurrentVersion"), &key) != ERROR_SUCCESS)
{
cout << "unable to open registry";
}
if (RegSetValueEx(key, TEXT("value_name"), 0, REG_SZ, (LPBYTE)"value_data", strlen("value_data")*sizeof(char)) != ERROR_SUCCESS)
{
RegCloseKey(key);
cout << "Unable to set registry value value_name";
}
else
{
cout << "value_name was set" << endl;
}
return 0;
}
Could someone explain what is value_name value_data and how to use it with an example as that is the main thing I'm confused with.
Your best bet is to use RegSetValueEx - all C++ wrappers for the registry are very thin wrappers around the simple C API.
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <Windows.h>
#include <tchar.h>
using namespace std;
int main()
{
HKEY key;
RegOpenKey(HKEY_CLASSES_ROOT, TEXT(""), &key);
LPCTSTR value = TEXT("");
LPCTSTR data = TEXT("");
LONG setRes = RegSetValueEx(key, value, 0, REG_SZ, (LPBYTE)data, _tcslen(data) * sizeof(TCHAR));
RegCloseKey(key);
return 0;
}
this solved it
I'm trying to get out an array in a pythonic format [numpy or list] form a DLLwritten in c#/c++. This DLL gives out the pointer to the memory and not the evaluated array. How can I access the memory in a FAST way (I wrote the DLL to speedup the code)?
I have used the pythonnet module and i managed to get the memory pointer as a but I'm failing in extracting the memory pointer as an integer or binary and then to get the data of the output vector.
Here the python code:
import numpy as np
import clr
clr.AddReference(R'...\PyDLL.dll')
from PyDLL import StringLibrary
my_instance = StringLibrary()
x = my_instance.arrayShift(np.array([1,2,3,4,5,6,7,8,9,0]).reshape(-1))
And then the C# code
namespace PyDLL
{
public class StringLibrary
{
public static double[] arrayShift(double[] array)
{
int b = array.Length;
double[] newArray = new double[b];
for(int i=0; i<b; i++)
{
newArray[i] = array[b-i-1];
}
return newArray;
}
}
}
I expect that the output x in python is a list or a np array, while now it is a System.Double[] object.
the expected output of x is [0,9,8,7,6,5,4,3,2,1]
Thank you for any help
After many tries and researches, I managed to solve the problem in this way:
Cpp part:
Open Visual Studio, then create a new project (Dynamic-Link Library).
Name the project and add a new file in the project (Header file) and name it with the same project name.
Insert the following code in the header:
// headerName.h - Contains declarations of math functions
#pragma once
#ifdef HEADERNAME_EXPORTS
#define HEADERNAME_API __declspec(dllexport)
#else
#define HEADERNAME_API __declspec(dllimport)
#endif
// Define the functions that will be called using the DLL
extern "C" HEADERNAME_API void funName1(...);
extern "C" HEADERNAME_API void funName2(...);
extern "C" HEADERNAME_API void funName3(...);
...;
In the folder 'Source Files' add a new file with extension .cpp (call it with the same name as the project), then write the function in this .cpp file. Here an example code:
#include "pch.h" // use stdafx.h in Visual Studio 2017 and earlier COMPULSORY TO ADD
#include "HEADERNAME.h" // COMPULSORY TO ADD
#include lib#1
#include lib#2
#include lib#3
...
using namespace std;
void funName1(...)
{
...
}
void funName2(...)
{
...
}
void funName3(...)
{
...
}
To be able to pass the arrays between python and c++, in my solution, the use of pointers is needed and no return must be used. The output variable is passed as an input variable, initialized in python, using a pointer. In the DLL the memory cells of the output variables are re-wrote and, doing so, when the DLL completes the function, the output is computed and already usable by python without return.
Here an example of how to write a function using pointers for input and output arrays:
void funName(double* inputArray_pointer, double* outputArray_pointer, int extraVariable)
{
double inner_var = 100;
for (int i = 0; i < extraVariable; i++)
{
inner_var = min(inner_var, *(inputArray_pointer+i));
*(outputArray_pointer + i) = inner_var;
}
}
Then rebuild the DLL.
Python part
To use correctly a DLL in the python code, the modules 'ctypes' and 'numpy' must be imported.
Here follows an example of the python code (This will use the example DLL of point (9)):
import numpy as np
import ctypes
cpp_fun = ctypes.CDLL(R'pathToDll/DLLname.dll')
# Define the types of the arguments of the DLL (pointer, int, double, ecc)
cpp_fun.funName.argtypes = [np.ctypeslib.ndpointer(),
np.ctypeslib.ndpointer(),
ctypes.c_int]
# Allocate or define the input variables using numpy or the standard scalar of python (int, float, ecc..)
inputArray = np.array([0,1,2,3,4,5,6,7,8,9,...,1000]).reshape(-1).astype('f8')
outputArray = np.zeros([inputArray.shape[0]])astype('f8')
extraVariable = inputArray.shape[0]
cpp_fun.funName(inputArray, outputArray, extraVariable)
Doing so, in the variable 'outputArray' we will find the result of the calculations performed inside the DLL as a np array structure.
Hi I've been trying to get name of the metro app with the acquired from AppManifest.xml of the respective app. Came to know that SHLoadIndirectString could be used for this purpose. On checking its functionality manually, I couldn't get the result resource. The code snippet goes as below.
#include <iostream>
using namespace std;
#include <Shlwapi.h>
int main(){
LPWSTR output = L"";
LPWSTR input = L"#{Microsoft.BingMaps_2.1.3230.2048_x64__8wekyb3d8bbwe?ms-resource://Microsoft.BingMaps/resources/AppDisplayName}";
int result = SHLoadIndirectString(input, output, sizeof(output), NULL );
cout<<output;
return 0;
}
The return value "result" is always a negative value(changes if I am changing the input string respective to app). Please guide me on my mistake. Thanks.
Got the right answer.
#include <iostream>
using namespace std;
#include <Shlwapi.h>
int main()
{
PWSTR output = (PWSTR) malloc(sizeof(WCHAR)*256);
PCWSTR input = L"#{C:\\Program Files\\WindowsApps\\Microsoft.BingMaps_2.1.3230.2048_x64__8wekyb3d8bbwe\\resources.pri?ms-resource://Microsoft.BingMaps/Resources/AppShortDisplayName}";
int result = SHLoadIndirectString(input, output, 256, NULL );
cout<<output;
return 0;
}
I'm writing a C# com library. I need a function that takes string from C++ and modifies string, after I have modified this string in my library modified value should be usable by C++ code. Here is my function (it's not working),
C# Interface,
Int32 testString([param: MarshalAs(UnmanagedType.LPStr)] ref string strData);
C# Implementation,
class Test:ITest
{
public int testString(ref string strData)
{
strData = strData + strData;
Console.WriteLine("strData in lib :"+strData);
return 0;
}
}
C++ code (I missed the parts, registering com lib, importing tlb etc.),
ITest * mInterface = NULL;
//...initilizing interface , skipped since this parts has no problem
LPSTR tt = "OLA";
mInterface ->testString(&tt); //It crashes when comes here ..
cout << tt <<endl;
I have found a solution to my problem , I am not sure but maybe we cannot initilized object from c++ to c# using com interop.If a use a null pointer to c# com , and initilize that pointer inside c# library code it worked .You can see the sample below ;
c# library interface
int testString(out string val);
c# library imp
class Test
{
int testString(out string val)
{
val = "Hello world"; //now user of this method can use val
return 0;
}
}
c++ usage
#pragma warning (disable: 4278)
#import "../yourtlb.tlb" no_namespace named_guids
ITestInterface * fpInterface = NULL;
int retval = 1;
CoInitialize(NULL);
HRESULT hr = CoCreateInstance(CLSID_Test ,
NULL, CLSCTX_INPROC_SERVER,
IID_ITestInterface, reinterpret_cast<void**>(&fpInterface));
if(!FAILED(hr))
{
BSTR val = NULL;
int ret = fpInterface->testString(val);
cout <<val<<endl;
}
Of course before using code in c++ , dont forget to generate tlb file from your c# project , and dont forget to edit registry files.Here you can see a good sample
Objective
What I am trying to do is to make a dll from C++(Visual Studio 2012) and call that from C# winform(Visual Studio 2012).
C++ dll is called "Helper.dll".
C# winform is called "WinFormTest.exe".
C++ dll simply connects to a certain web site, and return the html code with cookie string.
Here is my C# code.
Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace WinFormTest
{
public partial class Form1 : Form
{
[DllImport(#"Helper.dll", EntryPoint="CallTest", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.BStr)]
private static extern string CallTest(string Url, StringBuilder Cookies);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool SetDllDirectory(string path);
enum PlatformTarget { x64, x86 }
PlatformTarget _platformTarget;
string _assPath;
public Form1()
{
InitializeComponent();
_platformTarget = IntPtr.Size == 8 ? PlatformTarget.x64 : PlatformTarget.x86;
_assPath = AppDomain.CurrentDomain.BaseDirectory;
_assPath = Path.Combine(_assPath, _platformTarget.ToString());
bool ok = SetDllDirectory(_assPath);
if (!ok)
{
throw new System.ComponentModel.Win32Exception();
}
}
private void button1_Click(object sender, EventArgs e)
{
StringBuilder _cookies = new StringBuilder();
string html = CallTest("http://www.google.com", _cookies);
}
}
}
There is no big issue with my C# code.
Here is C++ code.
PlusPlusClass.cpp
#include "stdafx.h"
#include "PlusPlusClass.h"
#include "Scraper.h"
#include <vector>
#include <boost/algorithm/string.hpp>
using namespace std;
extern "C" __declspec(dllexport) BSTR CallTest(const char* Url, char Cookies[])
{
std::string html;
try
{
CPlusPlusClass* cpc = new CPlusPlusClass();
std::map<std::string, std::string> cookies;
html = cpc->GetCookies(Url, cookies);
std::string cookieData;
for (std::map<std::string, std::string>::iterator iterator = cookies.begin(); iterator != cookies.end(); iterator++)
{
cookieData += iterator->first;
cookieData += "=";
cookieData += iterator->second;
cookieData += ";";
}
sprintf(Cookies, cookieData.c_str(), 0);
delete cpc;
}
catch (...)
{
}
return ::SysAllocString(CComBSTR(html.c_str()).Detach());
}
Scraper* class2;
CPlusPlusClass::CPlusPlusClass(void)
{
class2 = new Scraper();
}
CPlusPlusClass::~CPlusPlusClass(void)
{
delete class2; --> here, I get the error. The error just kills my C# application.
}
std::string CPlusPlusClass::GetCookies(const char* Url, std::map<std::string, std::string>& Cookies)
{
return class2->DoSomething(Url, Cookies);
}
Here is Scraper.cpp.
Scraper.cpp
#include "stdafx.h"
#include "Scraper.h"
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
#include <curl/easy.h>
// split
#include <vector>
#include <boost/algorithm/string.hpp>
Scraper::Scraper(void)
{
}
Scraper::~Scraper(void)
{
}
std::string Scraper::DoSomething(const char* Url, std::map<std::string, std::string>& Cookies)
{
std::string _retValue;
curl_global_init( CURL_GLOBAL_ALL );
CURL* curl;
CURLcode res;
struct curl_slist* headerlist = NULL;
curl = curl_easy_init();
if (curl)
{
headerlist = curl_slist_append(headerlist, "Accept: */*");
headerlist = curl_slist_append(headerlist, "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.116 Safari/537.36");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
curl_easy_setopt(curl, CURLOPT_URL, Url);
curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "");
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &_retValue);
res = curl_easy_perform(curl);
// receive cookies
struct curl_slist* cookies = NULL;
struct curl_slist* nc;
CURLcode ret = curl_easy_getinfo(curl, CURLINFO_COOKIELIST, &cookies);
nc = cookies;
while (nc)
{
std::vector<std::string> split_vector;
boost::split(split_vector, nc->data, boost::is_any_of("\t"));
Cookies.insert( std::pair<std::string, std::string>(split_vector[5], split_vector[6]) ); --> here is the problem, I think.
nc = nc->next;
}
// clean up
curl_slist_free_all(cookies);
curl_easy_cleanup(curl);
curl_slist_free_all(headerlist);
}
curl_global_cleanup();
return _retValue;
}
std::string Scraper::DoSomething2(const char* Url, std::map<std::string, std::string>& Cookies)
{
std::string temp = "some value is not good enough";
std::vector<std::string> split_vector;
boost::split(split_vector, temp, boost::is_any_of("\t"));
Cookies.insert( std::pair<std::string, std::string>(split_vector[0], split_vector[1]) );
return "this function is okay";
}
It's just simple curl example to connect to a certain web site.
But from C#, I have to retrieve cookies as well as html, so I am passing StringBuilder to C++.
So, C++ can write cookie name and value to that StringBuilder.
Actually this codes work great in 64bit.
But if I change it into 32bit(in C# winform property), C++ gives me error in CPlusPlusClass::~CPlusPlusClass(void).
When I try to delete class2 which is Scraper class, it just kills my C# application, so I cannot even trace the error.
I am specious about Scraper.cpp when getting the cookie from curl CURLINFO_COOKIELIST.
And write them to char array which was referenced from C# StringBuilder.
So, I wrote down DoSomething2 function in Scraper.cpp.
Now, it works even when I am deleting class in 32bit or 64bit.
Does anyone have any idea about this problem?
By somehow it was fixed.
I don't know very much about the mechanism x86 nor x64, but it seems that the basic capacity are different.
I edited to fix the size of StringBuilder when I first start from C#.
StringBuilder _cookies = new StringBuilder();
to
StringBuilder _cookies = new StringBuilder(1024);
And now, I don't see that error again in 32bit computers.
Happy coding!!