Compiling C++ DLL and passing a string by reference

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
RHCP
Posts: 202
Joined: 30 Sep 2013, 10:59

Compiling C++ DLL and passing a string by reference

20 Sep 2014, 21:58

I would like to pass a string to my DLL function and have it modify the string. Something like this AHK code.

Code: Select all

string := "1,10|2,20|4,40|3,30"
DllCall("dll\sortSelection", "Str", string, "Cdecl")
msgbox % string ; string  now equals 4|3|2|1
I've tried compiling various simple string functions and calling them, but i'm a noob and they all failed. However simple integer functions did work.

The real function is actually sorting a list of items via each items associated fields/values. In this test example each item only has one field to sort by (value) so the passed string will have this form.

Code: Select all

item1ID,Item1Value|item2ID,item2Value ....

Each item is pipe delimited. Each field within an item is comma delimited. The function will sort the list and update the passed string with the sorted items IDs.

How should the below function be modified so as to allow it to be compiled as a DLL and called from AHK? (I would like to update the passed string)

Many thanks.

The c++ function:

Code: Select all

#include "StdAfx.h"
//#include <windows.h>
//#include <ostream> 
#include <iostream> 
#include <string> 
#include <sstream> 
#include <vector> 
#include <algorithm>
using namespace std;

struct item 
{
	int id;
	int value;
	item(string const& inputString) // inputString = comma delimited "id,value" 
	{
		istringstream input(inputString); 
		string number;
		for (int i=0; getline(input, number, ','); i++)
		{
			istringstream iss(number);
			if (i == 0)
				iss >> id;
			else 
				iss >> value;
		}
	}
    static bool compare(const item& lhs, const item& rhs) // might be able to use strcmp() to prevent conversions
    { 
		if (lhs.value > rhs.value)
			return 1;
		return 0;
	}
};
string sortSelection(string &inputString)
{ 
	vector<item> items;
	istringstream input(inputString); 
	string param;
	// convert the pipe delimited string into the individual comma delimited param list and populate the vector.
	while (getline(input, param, '|'))
		items.push_back(item(param));
	sort(items.begin(), items.end(), item::compare);
	ostringstream outputString; //output string stream
	// loop through the sorted vector and extract the ID values and convert these back into a pipe delimited string
	for (int i=0; i < items.size(); i++)
		outputString << (i != 0 ? "|" : "") << items[i].id; //use the string stream just like cout
	return inputString = outputString.str(); //the str() function of the stream 
} 

int main() 
{ 
	//string param --> item1ID,Item1Value|item2ID,item2Value.....
	// will return a string of IDs ranked by value (higher first). The byRef passed param will equal the return value.
	// Should return 4|3|2|1
	string myString = "1,10|2,20|4,40|3,30";
	cout << sortSelection(myString) << endl << myString << endl; 

	system("pause");
	return 0; 
}  
User avatar
MilesAhead
Posts: 232
Joined: 03 Oct 2013, 09:44

Re: Compiling C++ DLL and passing a string by reference

21 Sep 2014, 14:11

If you look in the help for DllCall read the section on Str type. It's made to be used with pointers to C style null terminated strings. Not C++ string objects. Also you may have an easier time if you use the WinAPI calling type to get away from C++ name mangling.
"My plan is to ghostwrite my biography. Then hire another writer to put his
name on it and take the blame."

- MilesAhead
User avatar
LinearSpoon
Posts: 156
Joined: 29 Sep 2013, 22:55

Re: Compiling C++ DLL and passing a string by reference

21 Sep 2014, 16:26

MilesAhead is right about str type. You will want your C++ function to accept/return char* or wchar_t* to use AHK str type.

Specifying cdecl calling convention is sufficient to avoid name mangling, but you will need to specify cdelc whenever you write dllcall.
You can also set up a DEF file. In this case, your AHK code will not need to specify cdecl, and your C++ code will not need extern "C".

Code: Select all

//extern "C" = cdecl
//__declspec(dllexport) = expose it in the dll for other programs to call
extern "C" __declspec(dllexport) char* sortSelection(char* inputString)
{
	vector<item> items;
	istringstream input(inputString);
	string param;
	// convert the pipe delimited string into the individual comma delimited param list and populate the vector.
	while (getline(input, param, '|'))
		items.push_back(item(param));
	sort(items.begin(), items.end(), item::compare);
	ostringstream outputString; //output string stream
	// loop through the sorted vector and extract the ID values and convert these back into a pipe delimited string
	for (int i = 0; i < items.size(); i++)
		outputString << (i != 0 ? "|" : "") << items[i].id; //use the string stream just like cout	

	//return inputString = outputString.str(); //the str() function of the stream 

	//copy outputString to inputString and return it
	string tmp = outputString.str();
	strcpy_s(inputString, tmp.length() + 1, tmp.c_str());  //Visual Studio tells me strcpy is unsafe...use strcpy_s to make it happy
	return inputString;
}
Since the C++ function accepts char*, we need to tell AHK to use astr type, to have it run correctly for ANSI and Unicode AHK.

Code: Select all

string := "1,10|2,20|4,40|3,30"
r := DllCall("dll\sortSelection", "astr", string, "Cdecl astr")
msgbox % r "`n" string "`nErrorLevel:" ErrorLevel ; string  now equals 4|3|2|1
RHCP
Posts: 202
Joined: 30 Sep 2013, 10:59

Re: Compiling C++ DLL and passing a string by reference

22 Sep 2014, 10:19

Thanks for the great replies and the working example, I appreciate the help.

Thanks.
david8u8
Posts: 6
Joined: 03 Nov 2022, 10:43

Re: Compiling C++ DLL and passing a string by reference

14 Nov 2022, 09:40

@LinearSpoon, Thank you very much. you help me.

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Araphen, Dobbythenerd1 and 314 guests