I am currently trying to rewrite the network code of a MFC application to fit it to a new server, (written in c#) later on.
I'm experimenting with protobuf to ensure that all data models are the same.
My problem is, that the Scalar Value Types, protobuf works with is not understood by the MFC type system. It uses DWORD instead of uint32, BYTE instead of byte or bool and so on. That requires custom type mapping/casting and that's not necessarily taking work from my shoulders.
Is there a way to change those datatypes used in protobuf?
A sample protobuf model would be:
syntax = "proto3";
package CInterop;
option csharp_namespace = "CCX.Protobuf.Login";
message LoginAck {
LoginResultStatus Status = 1;
uint32 dwUserID = 2;
uint32 dwCharID = 3;
uint32 dwKEY = 4;
uint32 dwMapIP = 5;
uint32 wPort = 6;
uint32 bCharCreateCount = 7;
bool IsInPcRoom = 8;
uint32 PremiumPcRoomValue = 9;
uint64 dCurrentTime = 10;
uint64 dKey = 11;
string Reason = 12;
uint64 iDuration = 13;
bool bEternal = 14;
}
The current usage would be
CInterop::LoginAck loginAck;
(*pPacket) >> loginAck; // Reads the packet from the buffer
m_dwUserID = (DWORD)loginAck.dwuserid();
m_dwKickID = (DWORD)loginAck.dwcharid();
m_dwKEY = (DWORD)loginAck.dwkey();
vADDR.sin_addr.S_un.S_addr = (ULONG)loginAck.dwmapip();
vADDR.sin_port = (USHORT)loginAck.wport();
m_bCreateCardCnt = (byte)loginAck.bcharcreatecount();
m_bInPCROOM = (BYTE)loginAck.isinpcroom();
m_dwPrmPCROOM = (DWORD)loginAck.premiumpcroomvalue();
But here, i don't want to cast the types, this should happen automatically somehow.
I'm trying to understand the purpose of the LIST_ENTRY structure. It's defined as:
typedef struct _LIST_ENTRY {
struct _LIST_ENTRY *Flink;
struct _LIST_ENTRY *Blink;
} LIST_ENTRY, *PLIST_ENTRY, PRLIST_ENTRY;
I've seen it used for finding import modules of a program:
PEB32* pPeb = GetPEB(pTeb);
LIST_ENTRY* ModuleListTail = &pPeb->Ldr->InMemoryOrderModuleList;
LIST_ENTRY* ModuleList = ModuleListTail->Flink;
do {
unsigned char* ModuleAddr = (unsigned char*)ModuleList - (sizeof(LIST_ENTRY));
_LDR_DATA_TABLE_ENTRY* entry = (_LDR_DATA_TABLE_ENTRY*)ModuleAddr;
wchar_t Name[128];
wmemcpy(Name, (wchar_t*)(void*)entry->BaseDllName.Buffer, 128);
std::wcout << Name << '\n';
ModuleList = ModuleList->Flink;
} while (ModuleList != ModuleListTail);
Why is the ModuleList pointer subtracted by the size of the structure?
unsigned char* ModuleAddr = (unsigned char*)ModuleList - (sizeof(LIST_ENTRY));
How is this structure used if it doesn't hold any data but pointers to other structures?
I'm working with libuv (https://github.com/joyent/libuv) and nodejs v12. I I write native module, in this module i have struct:
struct Work_req
{
const char *data;
size_t data_length;
Isolate* isolate;
unsigned int callback_id;
Persistent<Function> callback;
};
Then i try to pass this structure to work:
Work_req* request = new Work_req;
request->data = buf->base;
request->data_length = (size_t)nread;
request->isolate = env->isolate();
request->callback_id = callback_id->ToNumber()->Value();
uv_work_t *req = new uv_work_t;
req->data = request;
uv_queue_work(env->event_loop(), req, findCallback, after_findCallback);
In the end of this code i passed work to loop and all is ok.
But when i'm trying to read data from uv_work_t *req in findCallback function, i get strange symbols there:
Work_req *s = ((struct Work_req*)req->data);
printf(s>data); //print char array from structure here
I see something like this:
����g�Kack_id":1,"error":null,"response":{"type":"test"}}�����
How i can fix it?
Thanks a lot.
I'm using a third party library which defines this struct:
typedef struct
{
unsigned short nbDetectors;
//! structure of detector status
struct DetectorStatus
{
unsigned int lastError; //< last detector internal error
float temperature; //< detector temperature
detector_state state; //< detector state
unsigned short mode; //< detector mode
struct EnergyStatus
{
power_source powerSource; //< front-end power source
frontend_position frontendPosition; //< front-end position relative to the docking station
struct BatteryStatus
{
bool present; //< battery present or not in the detector
unsigned short charge; //< charge level of the battery (in %)
float voltageLevel; //< battery voltage level
float temperature; //< temperature of the battery
unsigned short chargeCycles; //< number of charge/discharge cycles
unsigned short accuracy; //< Expected accuracy for charge level (in %)
bool needCalibration;
} batteryStatus;
} * energyStatus;
struct GridStatus
{
detector_grid grid;
} * gridStatus;
} * detectorStatus;
} HardwareStatus;
This struct is used by the library as data passed by one of its callbacks. So it's the library which fills it up, I just read it. So far, so good.
But now I'm writing an emulator for the device handled by this library, so now I have to fill up one of these structs and I can't get it right.
I tried this:
HardwareStatus status;
status.detectorStatus->temperature = 20 + rand() % 10;
e.data = &status;
m_pContext->EventCallback( EVT_HARDWARE_STATUS, &e );
When I compiled, I got:
warning C4700: uninitialized local variable 'status' used
Then I realized... The pointers inside the struct are pointing to garbage, nice catch Visual Studio! So then I tried to start by declaring an instance of the innermost struct (BatteryStatus), but that wouldn't compile... because it's not typedef'd (it says the BatteryStatus type is not defined)? So I got stumped... How do I fill the struct up?
if you want to have everything on the stack this should do it:
// Getting structs on the stack initialized to zero
HardwareStatus status = { 0 };
HardwareStatus::DetectorStatus detectorStatus = { 0 };
HardwareStatus::DetectorStatus::EnergyStatus energyStatus = { 0 };
HardwareStatus::DetectorStatus::GridStatus gridStatus = { 0 };
// "Linking" structs
detectorStatus.energyStatus = &energyStatus;
detectorStatus.gridStatus = &gridStatus;
status.detectorStatus = &detectorStatus;
// Now you can fill and use them
status.detectorStatus->temperature = 20 + 3 % 10;
//...
You could value-iniitialize it:
HardwareStatus status = {};
If you want to instantiate a BatteryStatus, you can do that by fully qualifying the name:
HardwareStatus::DetectorStatus::EnergyStatus::BatteryStatus bs;
did you try memset'ing the struct to 0 ?
In C, you sometimes see something like:
struct foobar
{
int size;
int data[1];
};
where the data member doesn't really have just one element; rather it's meant to be variable length.
If you do something like that in D, is it going to let you, for example, read myfoobar.data[4]?
I know D has variable length arrays, e.g. int[] myvarlenintarray;, but what if you're trying to interface with some code that already puts out a data structure in memory like the one above, and possibly much more complex than that? Let's say it's in the first portion of int[3000] buffer;. Is there an easy way to cast it to a usable struct without moving it in memory? If not, is there an easy way to get the data into a similar struct without having to manually parse out each member of the struct?
edit:
I think I need to give a practical example so you see where I'm coming from.
import std.c.windows.windows;
import std.utf;
import std.stdio;
public struct REPARSE_DATA_BUFFER
{
ULONG ReparseTag;
USHORT ReparseDataLength;
USHORT Reserved;
union
{
struct SymbolicLinkReparseBuffer
{
USHORT SubstituteNameOffset;
USHORT SubstituteNameLength;
USHORT PrintNameOffset;
USHORT PrintNameLength;
ULONG Flags;
WCHAR[1] PathBuffer;
}
SymbolicLinkReparseBuffer mySymbolicLinkReparseBuffer;
struct MountPointReparseBuffer
{
USHORT SubstituteNameOffset;
USHORT SubstituteNameLength;
USHORT PrintNameOffset;
USHORT PrintNameLength;
WCHAR[1] PathBuffer;
}
MountPointReparseBuffer myMountPointReparseBuffer;
struct GenericReparseBuffer
{
UCHAR[1] DataBuffer;
}
GenericReparseBuffer myGenericReparseBuffer;
}
}
alias REPARSE_DATA_BUFFER* PREPARSE_DATA_BUFFER;
enum MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 16*1024;
// Values for 'ReparseTag' member of REPARSE_DATA_BUFFER:
enum : DWORD {
IO_REPARSE_TAG_SYMLINK = 0xA000000C,
IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003 // which also defines a Junction Point
}
enum DWORD FSCTL_GET_REPARSE_POINT = 0x000900a8;
enum FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000;
public extern(Windows) BOOL function(HANDLE, DWORD, LPVOID, DWORD, LPVOID, DWORD, LPVOID, OVERLAPPED*) DeviceIoControl;
void main()
{
DeviceIoControl = cast(BOOL function(HANDLE, DWORD, LPVOID, DWORD, LPVOID, DWORD, LPVOID, OVERLAPPED*))GetProcAddress(LoadLibraryA("kernel32.dll"), "DeviceIoControl");
auto RPHandle = CreateFileW((r"J:\Documents and Settings").toUTF16z(), 0, FILE_SHARE_READ, null, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT + FILE_FLAG_BACKUP_SEMANTICS, null);
if (RPHandle == INVALID_HANDLE_VALUE)
{
printf("CreateFileW failed with error code %d.", GetLastError());
return;
}
BYTE[MAXIMUM_REPARSE_DATA_BUFFER_SIZE] reparsebuffer;
uint reparsedatasize;
auto getreparsepointresult = DeviceIoControl(RPHandle, FSCTL_GET_REPARSE_POINT, null, 0, cast(void*) reparsebuffer.ptr, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &reparsedatasize, null);
if (getreparsepointresult == 0)
{
printf("DeviceIoControl with FSCTL_GET_REPARSE_POINT failed with error code %d.", GetLastError());
return;
}
// Now what?
// If I do this:
auto ReparseDataPtr = cast(REPARSE_DATA_BUFFER*) reparsebuffer.ptr;
printf("%d == %d\n", reparsebuffer.ptr, ReparseDataPtr); // Alright, data hasn't been copied.
// But what good is a pointer? Can I use a pointer to a struct to access one of its members apart from dereferencing?
printf("%d == %d\n", &reparsebuffer[0], &(*ReparseDataPtr)); // Here, I dereference ReparseDataPtr, but nothing moves.
printf("%d == %d\n", &reparsebuffer[0], &((*ReparseDataPtr).ReparseTag)); // Same here, so I can access members in a roundabout way.
printf("%d == %d\n", &reparsebuffer[0], &(ReparseDataPtr.ReparseTag)); // And thanks to Jim's comment, here's a less roundabout way.
auto ReparseData = *ReparseDataPtr; // But if I assign a name to the dereferenced ReparseDataPtr,
printf("%d != %d\n", &reparsebuffer[0], &(ReparseData.ReparseTag)); // the data is copied to a new location, leaving most of PathBuffer behind.
REPARSE_DATA_BUFFER ReparseDataFn() {return *ReparseDataPtr;} // Similarly, this way
printf("%d != %d\n", &reparsebuffer[0], &(ReparseDataFn().ReparseTag)); // copies stuff to a new location.
}
Firstly, I don't understand why it's different for the case in which I don't give *ReparseDataPtr a name.
Secondly, is there no way to have a symbol whose type is REPARSE_DATA_BUFFER and whose data is located at reparsebuffer.ptr?
Have you tried doing the exact same thing in D as in C?
struct foobar { int size; int data[1]; };
It works... just use data.ptr instead of data to access the elements, because otherwise it will perform bounds checking with a length of 1.
You could access it via a helper method:
struct foobar
{
public:
int[] Data() { return data.ptr[0..size]; }
private:
int size;
int data[1];
}
You might also want to put int a static foreach over the members of foobar that uses static assert to make sure that the offset of each is less than the offset of data.