Delphi and C/C++ DLL Struct vs.Record - c++

I previously asked a question about a delphi and a C/C++ DLL.
I have now another question about a record / struct.
The DLL should be able to dynamically CHANGE the VALUE of the pointer vars from the MainAPP.
My delphi MAINAPP has the following record:
type MyRec = record
MyInteger : Pointer;
MyWideString : pwidechar;
MyString : pchar;
MyBool : Pointer
end;
type
TMyFunc = function ( p : pointer ): pointer; stdcall;
procedure test;
var
MyFunction : TMyFunc;
TheRecord : MyRec;
AnInteger : Integer;
AWideString : WideString;
AString : String;
ABool : Bool;
begin
AnInteger := 1234;
AWideString := 'hello';
AString := 'hello2';
ABool := TRUE;
TheRecord.MyInteger := #AnInteger;
TheRecord.MyWideString := pwidechar(AWideString);
TheRecord.AString := pchar(AString);
TheRecord.ABool := #ABool;
[...]
#MyFunction := GetProcAddress...
[...]
MyFunction (#TheRecord); // now the DLL should be able to change the values dynamically.
MessageBoxW (0, pwidechar(AWideString), '', 0); // Show the results how the DLL changed the String to...
end;
C/C++ Code (just example)
typedef struct _TestStruct{
void *TheInteger; // Pointer to Integer
wchar_t *TheWideString; // Pointer to WideString
char *TheAnsiString; // Pointer to AnsiString
bool *TheBool // Pointer to Bool
}TestStruct;
__declspec(dllexport) PVOID __stdcall MyExportedFunc (TestStruct *PTestStruct)
{
MessageBoxW(0 ,PTestStruct->TheWideString, L"Debug" , 0); // We read the value.
PTestStruct->TheWideString = L"Let me change the value here.";
return 0;
}
For some reasons it crashes etc.
What do I do wrong?
Thanks for help.

This probably isn't the cause of the crash at the point where the C++ code assigns to the TheWideString pointer, but I do see a problem of expectations...
I notice that you're putting the address of the string data that the Delphi AWideString variable points to into the MyWideString field of the record. You pass the record to the C++ function, which assigns a new pointer value to the TheWideString/MyWideString field of the record. When execution returns to the Delphi code, you output the contents of the AWideString variable.
Your comments indicate that you expect the contents of the AWideString variable to be changed by the C++ function, but that's not what will happen.
The C++ function changes the field in the structure. It does nothing to the memory location that the field previously pointed to. The data that AWideString points to will not be affected by the C++ function.
If the C++ code copied data into the address contained in the field, then it would overwrite the string data that AWideString points to. Since AWideString is a Delphi managed string, and the C++ function would be copying more data to that string memory area than the original string had allocated space for, copying data in the C++ function would write past the end of the Delphi allocated string buffer and probably corrupt the Delphi heap. A crash may occur some time later. So it's a good that you're only assigning the pointer to the field, not copying the data! ;>
To see what the C++ function changed, your Delphi code should output the contents of the MyWideString field of the record after the call to the C++ function.

You are mismanaging the string fields. PWideChar and PChar are not the same thing as "pointer to WideString" and "pointer to AnsiString". Delphi has PWideString (WideString*) and PAnsiString (AnsiString*) types for that purpose instead. You should also use Delphi's PInteger (int*) and PBoolean (bool*) types instead of Pointer (void*). Delphi and C++ are both type-safe languages. Stay away from untyped pointers when possible, your code will be better for it.
type
PMyRec = ^MyRec;
MyRec = record
 MyInteger    : PInteger;
 MyWideString : PWideString;
 MyAnsiString : PAnsiString;
  MyBool       : PBoolean;
end;
 TMyFunc = function ( p  : PMyRec ): Integer; stdcall;
procedure test;
var
 MyFunction  : TMyFunc;
 TheRecord   : MyRec;
 AnInteger   : Integer;
 AWideString : WideString;
 AAnsiString : AnsiString;
 ABool       : Bool;
begin
 AnInteger                := 1234;
 AWideString              := 'hello';
 AAnsiString              := 'hello2';
 ABool                    := TRUE;
 TheRecord.MyInteger      := #AnInteger;
TheRecord.MyWideString   := #AWideString;
 TheRecord.MyAnsiString   := #AAnsiString;
 TheRecord.MyBool         := #ABool;
 [...]
 #MyFunction := GetProcAddress...
 [...]
 MyFunction  (#TheRecord);
 MessageBoxW (0, PWideChar(AWideString), '', 0);
end;
.
typedef struct _MyRec
{
int    *MyInteger;    // Pointer to Integer
WideString *MyWideString; // Pointer to WideString
AnsiString *MyAnsiString; // Pointer to AnsiString  
bool     *MyBool;       // Pointer to Bool
} MyRec, *PMyRec;
__declspec(dllexport) int __stdcall MyExportedFunc (PMyRec PRec)
{
MessageBoxW(NULL, PRec->MyWideString->c_bstr(), L"Debug" , 0);
    *(PRec->MyWideString) = L"Let me change the value here.";
return 0;
}
With that said, it can be very dangerous to manipulate AnsiString (and UnicodeString) values across a DLL boundary like this, especially if the EXE and DLL are written in different versions of Delphi/C++Builder due to RTL differences, memory manager differences, payload layout differences, etc. WideString is OK to pass around, though, because it's memory and layout are controlled by the OS, not the RTL.

Synchronize fields order in the structures. You can break memory heap using wrong pointers. Also, check alignment both in Delphi and C++.

Related

Returning an Array of Structs Solidity

I want to return an array of structs because i want to output all my data.
//SPDX-License-Identifier:MIT
pragma solidity ^0.8.0;
contract MyContract
{
mapping(uint256 => People) dataList;
uint256[] countArr;
struct People{
string name;
uint256 favNum;
}
In this function, i set the data of my struct object and then include it in my mapping.
function setPerson(string memory _name,uint256 _id, uint256 _favNum) public {
dataList[_id]= People(_name,_favNum);
countArr.push(_id);
}
This function here gets me the data of my specified struct object.
function getPerson(uint _id) public view returns(string memory,uint256){
return (dataList[_id].name, dataList[_id].favNum);
}
Now here is the function i think that is causing me trouble because in this function i want to return not the data of a single People object but all of my data and whenever i run this function on my REMIX IDE console it shows me the error: call to MyContract.getAllData errored: VM error: revert. revert
The transaction has been reverted to the initial state.
Note: The called function should be payable if you send value and the value you send should be less than your current balance.
function getAllData()public view returns(People[] memory){
uint256 count = countArr.length;
uint256 i = 0;
People[] memory outputL= new People[](count);
while(count >= 0){
(string memory nam,uint256 num) = getPerson(count-1);
People memory temp = People(nam,num);
outputL[i]=temp;
count--;
i++;
}
return outputL;
}
}
Can anyone help and explain what is wrong and how can i get it running?
This version of the getAllData function works as you expect:
function getAllData() public view returns (People[] memory) {
uint256 count = countArr.length;
People[] memory outputL = new People[](count);
while(count > 0) {
count--;
(string memory nam, uint256 num) = getPerson(countArr[count]);
People memory temp = People(nam, num);
outputL[count] = temp;
}
return outputL;
}
Feel free to ask if you have any questions about the changes.

How to resolve warning "ignoring return value of function declared with 'warn_unused_result' attribute"

I'm writing test automation in QT. I'am using QTest::qWaitFor to wait until the event loop switches to another tab in UI.
QTest::qWaitFor([tabs, &currentIdx]() {
    currentIdx = tabs->currentIndex();
    return currentIdx == 1;
}, 5000);
Each time I'am using such construction following warning appears:
ignoring return value of function declared with 'warn_unused_result' attribute
I spent hours dealing with it but no result. I think the problem is the way functions consume returned values from lambda expressions. Is there any workaround?
Issue is not with lambda, but your usage:
You should use/check return value of qWaitFor (to know if timeout happens):
if (QTest::qWaitFor([tabs, &currentIdx]() {
currentIdx = tabs->currentIndex();
return currentIdx == 1;
}, 5000)) {
// OK.
// ...
} else {
// timeout.
// ...
}

'(maybe you meant to use ‘->’ ?)' in gmock test

I have a unit test using gtest and gmock.
These are provided, and in my turn I should make them pass.
I have a RentalAdministration Object, which takes (in some methods) a Car object pointer. One of the functions looks like this:
bool RentalAdministration::Add(Car *car){
if(!car){
throw invalid_argument("Car parameter can't be null!");
}
if(FindCar(car->GetLicencePlate()) != NULL){
return false;
}
cars.push_back(car);
return true;
}
One of such tests looks like his:
TEST(RentalAdministrationAdd, test_add_car_to_empty_administration)
{
RentalAdministration admin;
Car *car;
EXPECT_CALL(car, GetLicencePlate()).WillOnce(Return("fh-01-ict"));
EXPECT_TRUE(admin.Add(&car));
}
When I try to make these tests, I get loads of errors, all of which are alike:
g++ -Wall -Werror -pedantic -ggdb -O0 -std=c++98 -Iproduct -Itest test/RentalAdministrationTest.cpp product/RentalAdministration.cpp -lgtest -lgmock -lgmock_main -lpthread -o RentalAdministrationTest
In file included from /usr/include/gmock/gmock-generated-function-mockers.h:43:0,
                 from /usr/include/gmock/gmock.h:61,
                 from test/RentalAdministrationTest.cpp:2:
test/RentalAdministrationTest.cpp: In member function ‘virtual void RentalAdministrationAdd_test_add_car_to_empty_administration_Test::TestBody()’:
test/RentalAdministrationTest.cpp:13:5: error: request for member ‘gmock_GetLicencePlate’ in ‘car’, which is of pointer type ‘Car*’ (maybe you meant to use ‘->’ ?)
     EXPECT_CALL(car, GetLicencePlate()).WillOnce(Return("fh-01-ict"));
     ^
In file included from /usr/include/gtest/gtest.h:58:0,
                 from /usr/include/gmock/internal/gmock-internal-utils.h:47,
                 from /usr/include/gmock/gmock-actions.h:46,
                 from /usr/include/gmock/gmock.h:58,
                 from test/RentalAdministrationTest.cpp:2:
test/RentalAdministrationTest.cpp:14:31: error: no matching function for call to ‘RentalAdministration::Add(Car**)’
     EXPECT_TRUE(admin.Add(&car));
                               ^
I wonder what I am doing wrong here. I'm just starting off with C++.
btw: I am compiling in g++ and have version 98.
Thanks.
Edit: excuse me for not posting this, but I have a mock file for Car.h which is in the same folder as the test itself.
#ifndef __CAR_H
#define __CAR_H
#include "gmock/gmock.h"
#include <string>
using namespace std;
class Car
{
public:
MOCK_CONST_METHOD0(GetLicencePlate, string());
MOCK_METHOD0(Rent, bool());
MOCK_METHOD1(Return, double(int kilometers));
MOCK_METHOD0(Clean, void());
};
#endif
Edit1: As suggested I have tried to use the reference (&) of Car*.
This kills the error I've stated above, but leaves me with some other errors:
error: cannot declare field ‘AdminTest::car’ to be of abstract type ‘Car’
Car car;
error: ‘class Car’ has no member named ‘gmock_GetLicencePlate’
car is a pointer to Car. Its type is: Car*. In order to call Car members from a Car*, you must dereference the pointer. This is automatically done when using the car->x syntax, which is equivalent to (*car).x.
I assume that EXPECT_CALL requires a non-pointer argument. Therefore, you can get a reference to car and pass it to the macro:
Car& car_ref = *car;
EXPECT_CALL(car_ref, GetLicencePlate()).WillOnce(Return("fh-01-ict"));
First is the pointer issue, that Vittorio already said but, also, you need to mock Car object to use EXCEPT_CALL:
class MockCar : public Car{
// Here I assume that original method is const
MOCK_CONST_METHOD0(GetLicencePlate);
}
TEST(RentalAdministrationAdd, test_add_car_to_empty_administration)
{
RentalAdministration admin;
MockCar car;
EXPECT_CALL(car, GetLicencePlate()).WillOnce(Return("fh-01-ict"));
EXPECT_TRUE(admin.Add(&car));
}
You can see in my examle that you are not using real car object but a Mock one where you can control access and force return values
I have found the solution.
For anyone wondering: Inside one class (RentalAdministration) I had included the Car.h file from the cars folder. (like #include "cars/Car.h")
However, for the test a different Car.h should be used. Therefore, changing to #include "Car.h" made it work.

(C++) Variable value changing when I call a function

I have the following code
NCore.h
#ifndef _NCORE_H_
#define _NCORE_H_
#include <Windows.h>
#include <cstdio>
namespace Neat
{
class NCore
{
private:
// Structure Definitions
struct NApplicationVersion
{
int major = 0;
int minor = 0;
int build = 0;
LPCSTR toString();
};
// Application Variables
LPCSTR applicationName;
NApplicationVersion applicationVersion;
protected:
public:
NCore();
LPCSTR ApplicationName(LPCSTR _applicationName = NULL);
NApplicationVersion ApplicationVersion(LPCSTR _applicationVersion = NULL);
};
}
#endif
NCore.cpp
#include "NCore.h"
Neat::NCore::NCore()
{
this->applicationName = NULL;
}
LPCSTR Neat::NCore::NApplicationVersion::toString()
{
char str[16];
memset(&str, 0, sizeof(str));
sprintf_s(str, sizeof(str), "%i.%i.%i", this->major, this->minor, this->build);
return str;
}
LPCSTR Neat::NCore::ApplicationName(LPCSTR _applicationName)
{
if (_applicationName)
this->applicationName = _applicationName;
return this->applicationName;
}
Neat::NCore::NApplicationVersion Neat::NCore::ApplicationVersion(LPCSTR _applicationVersion)
{
if (_applicationVersion)
{
//I know this isn't needed. I was just testing something.
Neat::NCore::NApplicationVersion *nav = (Neat::NCore::NApplicationVersion *)malloc(sizeof(Neat::NCore::NApplicationVersion));
sscanf_s(_applicationVersion, "%i.%i.%i", &nav->major, &nav->minor, &nav->build);
this->applicationVersion.major = nav->major;
this->applicationVersion.minor = nav->minor;
this->applicationVersion.build = nav->build;
free(nav);
}
return this->applicationVersion;
}
main.cpp
#include <Windows.h>
#include "NCore.h"
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT iCmdShow)
{
Neat::NCore n;
n.ApplicationName("test");
LPCSTR test = n.ApplicationName();
LPCSTR test2 = n.ApplicationVersion().toString();
if (strcmp(test2, "0.0.0") == 0)
{
MessageBox(NULL, "", "", MB_OK);
}
n.ApplicationVersion("10.50.136");
if (strcmp(test2, "0.0.0") == 0)
{
MessageBox(NULL, "", "", MB_OK);
}
LPCSTR test3 = n.ApplicationVersion().toString();
if (test3 == "10.50.136")
{
MessageBox(NULL, "", "", MB_OK);
}
while (true);
return 0;
}
My issue is that test2 initializes as "0.0.0" and the first MessageBox is shown. But after I call ApplicationVersion("10.50.136") it changes test2 to "10.50.136" and the second MessageBox is not shown.
Can someone please explain why this happens/how to fix it?
EDIT: I was testing a function that could operate as both a get/set function. I'm fairly new to this and I learn by failing. I just can't figure out what exactly went wrong here.
EDIT 2: I changed the code as follows...
NCore.h
struct NApplicationVersion
{
int major = 0;
int minor = 0;
int build = 0;
char asString[16];
LPCSTR toString();
};
NCore.cpp
LPCSTR Neat::NCore::NApplicationVersion::toString()
{
memset(this->asString, 0, 15);
sprintf_s(this->asString, 16, "%i.%i.%i", this->major, this->minor, this->build);
return this->asString;
}
Is this viable?
From my understanding, I was putting the variable "str" on the stack. This causes it to not have a set place in memory(?) and when other calls altered the stack they also altered the data the pointer "test2" was trying to read from?
It's pretty easy, actually. toString invokes undefined behavior by returning an array (str) that's allocated locally to the function and goes out of scope with the return:
LPCSTR Neat::NCore::NApplicationVersion::toString()
{
char str[16];
memset(&str, 0, sizeof(str));
sprintf_s(str, sizeof(str), "%i.%i.%i", this->major, this->minor, this->build);
return str;
}
In most common C++ implementations, str will be on the stack. (The C++ standard does not require a unified concept of "stack" where all automatic variables live, but most common implementations work that way.)
So, subsequent functions that modify the stack will also modify the C-style string pointed to by the call to toString(). The subsequent call to n.ApplicationVersion(), for example, would likely trash str. Your second message box won't show as long as the string changed to anything other than "0.0.0", and it won't take much to corrupt the stack in that way.
Based on your subsequent edit: Making the string a member of your class will somewhat work. Any call to toString will rewrite this string, affecting all callers that saved a pointer to this buffer.
Still, this is certainly much safer than saving the string on the stack. Furthermore, as long as only toString writes to this buffer, you have well defined rules for when that string is valid.
LPCSTR is not the string, it is just the pointer to the char array. When you set new version, the char array itself is changing. That's why you observer the change in test2 variable immediately. If you want this string not to be changed, copy and save it in your internal buffer.

ccGridSize in cocos2d

While using ccWave, one of the parameters was grid and it showed that the value should be of type ccGridSize.
I would like to know what a ccGridSize is..
What value should be given for a ccGridSize variable?
The code for ccWaves is as follows...
[CCWaves actionWithWaves:<(int)> amplitude:<(float)>
horizontal:<(BOOL)> vertical:<(BOOL)>
grid:<(ccGridSize)> duration:<(ccTime)>];
What value can be given in the place of the parameter grid???
Cocos2d defines ccGridSize as:
typedef struct _ccGridSize
{
NSInteger x;
NSInteger y;
} ccGridSize;
And provides an inline factory function:
static inline ccGridSize ccg(const NSInteger x, const NSInteger y);
So you can write your call as:
... grid:ccg(gridSizeX, gridSizeY)
Where gridSizeX and gridSizeY define a number of grid columns and rows for your effect.
From cctypes.h:
typedef struct _ccGridSize
{
       NSInteger   x;
        NSInteger   y;
} ccGridSize;
So it's just a couple of ints to state how big every step is of the grid that you are going to animate.