Giving unsigned char** a value in C++ - c++

I'm really rusty with C++ and pointers and can't figure out a solution to my problem.
Here is the context:
I have to write a DLL to replace an old one and for one of the functions i must follow this signature:
int GetText(unsigned char** outBuf, unsigned int* outLen);
In the final piece of software, the value of outBuf is displayed in a textbox.
If i understand correctly, outBuf is a pointer to a pointer, or a pointer to char array.
outLen seems to be the length of the data i provide to this buffer.
To test out this function, i'd like to create from scratch a char array and pass it to outBuf.
What i tried so far:
int GetText(unsigned char** outBuf, unsigned int* outLen){
*outBuf = NULL;
*outLen = 0;
//Create a char array from scratch, just to test...
unsigned char text[] = "Hello";
//outLen is the size of text
*outLen = sizeof(text);
//I allocate size to outBuf
*outBuf = new unsigned char[*outLen];
//I copy value of text into outBuf
memcpy(*outBuf, &text, *outLen);
return OK;
};
Is my code to give value to *outBuf and *outLen correct and what could lead it to not working? Because when i try it with the piece of software i was given to test the dll, it fails. It displays a dialog saying Reading failed with status 0.
The function seems to go through as the return value(status) is taken in account. But it doesn't manage to display anything. As if one of the variables i return is empty or null...
here is an extract from the final software (in VB) calling the function. As i'm not allowed to disclose the real code, i changed some value callings:
'lance la lecture
StatusInt = LectureText(NumText, textStr
If StatusInt = 0 Then
'traitement des sauts de ligne
textStr= Replace(textStr, Chr(&HD) + Chr(&HA), Chr(&HA))
textStr= Replace(textStr, Chr(&HA), Chr(&HD) + Chr(&HA))
'copie dans la textbox
Text1.Text = textStr
Else
MsgBox "Lecture failed with err " & Str(StatusInt)
End If
And the function
Public Function LectureText(ByVal NumText, ByRef Text As String) As Long
Dim AddrText As Long
'Dim TextAs String
Dim LengthText As Long
Dim status As Long
'lecture du text
status = GetText(AddrText, LengthText)
'si lecture ok, copie et lib�re le buffer
If status = 0 And LengthText <> 0 Then
'Alloue l'espace n�cessaire pour le text
Text = String(LengthText, vbNullChar)
'copie du text
CopyMemory ByVal Text, ByVal AddrText, LengthText
End If
'retourne status
LectureText= status
End Function
As you can see, if you provide a status = 0, it should not call the dialog saying there is an error. But in my case, it says "Lecture failed with err 0". How is it even possible...
i'm sure it's not the correct way to make things but i don't usually work with C++ and need to spend as little time as possible on this problem. I already searched for 2 days would need to take many things back from the start about C++. Thing i can't offer now.
Thanks in advance for your kind help

The code i wrote was correct.
The fact is my functions needed to be declared with __stdcall to be compatible with VB.
But when compiling the dll with __stdcall, Visual Studio was adding decoration to function names and the existing software in VB was trying to call them by their undecorated names.
So i added a definition file (.def) to my project so that the function names are exported correctly.

Related

How to convert fetched string data to character array?

I am doing this IoT based project on displaying data to connected display( I've used the MAX7219 module, in this case) with the help of nodeMCU. The idea here is that the string which is stored in my firebase database is to be display on the led display.
I've had no trouble in getting the value from the database to my nodeMCU but there is this little problem with converting that string to char array since the code i am using( Max72xx_Message_serial, which was available as an example with the max72xx library) has used char array but i can only fetch the stored data in string format. I've modified that code so as to connect with firebase but the main issue is to convert the string fetched from the database to char array.
I tried toCharArray() but it still shows conversion error.
void readfromfirebase(void)
{
static uint8_t putIndex = 0;
int n=1;
while (Firebase.available())
{
newMessage[putIndex] = (char)Firebase.getString("Submit Message"); // this line produces the error
if ((newMessage[putIndex] == '\n') || (putIndex >= BUF_SIZE-3)) // end of message character or full buffer
{
// put in a message separator and end the string
newMessage[putIndex++] = ' ';
newMessage[putIndex] = '\0';
// restart the index for next filling spree and flag we have a message waiting
putIndex = 0;
newMessageAvailable = true;
}
else if (newMessage[putIndex] != '\r')
// Just save the next char in next location
{putIndex++;}
n++;
}
}
I think you are confusing the types
getString returns a String object wich can be converted to a char[] using the methods of the String class.
I assume your newMessage is of type char[] or char*.
Then I would advise you to go for the String.c_str() method, because it returns a C style null-terminated string, meaning a char*.
See https://www.arduino.cc/reference/en/language/variables/data-types/string/functions/c_str/ for reference.
It also sets the last character of the string to 0. So methods like strlen, strcmp etc will work.
! be carefull not to modify the array returned by c_str(), if you want to modify it you chould copy the char[] or use string.toCharArray(buf, len).
Your Code might then look like the following.
String msg = Firebase.getString("Submit Message");
newMessage = msg.c_str();
// rest of your code
If newMessage is a buffer storing multiple messages, meaning char* newMessage[3].
String msg = Firebase.getString("Submit Message");
newMessage[putIndex] = msg.c_str();
// rest of your code
Be careful, because you are storing multiple characters in an array, so use strcmp to compare these arrays!
If you are new to C I would recommend reading.
https://www.cprogramming.com/tutorial/c/lesson9.html
https://www.arduino.cc/reference/en/language/variables/data-types/stringobject/ (as pointed out by #gre_gor)

Pass PByte to a DLL from vb..net

I having troubles to calling a function inside a C DLL (dont know if C or C++)
Basically, I m trying to make a wrapper for the SDK DLL of Gigabyte RGB Fusion API.
I m working in VB.NET with Visual Studio 2013 (if you answer in C# is good too)
Declaring functions with DLLImport
for Ex. This function works fine.
C++
int dllexp_GetMaxDivision(void)
VB.NET
<DllImport("GLedApi.dll", SetLastError:=False, callingConvention:=CallingConvention.Cdecl)> _
Public Shared Function dllexp_GetMaxDivision() As UInt32
EndFunction
calling dllexp_GetMaxDivision works like a charm. The trouble starts when i pass parameters:
DWORD dllexp_GetLedLayout(PBYTE bytArray, int arySize)
Parameters
Name / Type / Description
bytArray / Output / Pointer to a buffer that receives the LED layout on motherboard. The values of the elements in the array are as follows:
Value Meaning
0(NA) No implement LED
1(A_LED) Analog LED
2(D_LED_TYPE1) Digital LED Type 1
3(D_LED_TYPE2) Digital LED Type 2
arySize / Input / Size, in byte of the buffer indicated by bytArray. This value must be a dllexp_GetMaxDivision return value.
DWORD dllexp_SetLedData(PBYTE bytArray, int arySize)
Parameters
Name / Type / Description
bytArray / Input / Pointer to a byte array converted from the LEDSETTING
structure array.
arySize / Input / Size, in bytes, of the buffer indicated by bytArray.
typedef struct _LEDSETTING {
BYTE Reserve0;
BYTE LedMode;
BYTE MaxBrightness;
BYTE MinBrightness;
DWORD dwColor;
WORD wTime0;
WORD wTime1;
WORD wTime2;
BYTE CtrlVal0;
BYTE CtrlVal1;
} LEDSETTING, *PLEDSETTING
This is what I try. I dont get to test with dllexp_SetLedData yet, so I will focus in dllexp_GetLedLayout
<DllImport("GLedApi.dll", setLastError:=False, CallingConvention:=CallingConvention.Cdecl)> _
Public Shared Function dllexp_GetLedLayout(ByRef bytArray As IntPtr, arySize As Int32) As UInt32
End Function
Tried with a byte array, but didn't work. And This:
Dim Param(iMaxDivs - 1) As Byte
For A As Integer = 0 To iMaxDivs - 1
Param(A) = CByte(0)
Next
Dim Tama As Integer = Marshal.SizeOf(Param(0)) * Param.Length
Dim buffer As IntPtr = Marshal.AllocHGlobal(Tama)
Marshal.Copy(Param, 0, buffer, Param.Length)
resp2 = GLed.dllexp_GetLedLayout(buffer, Param.Length)
Marshal.Copy(buffer, Param, 0, Param.Length) '<===== AccessViolationException
Marshal.FreeHGlobal(buffer)
The line of code that retrieve the buffer to the array throw an exception:
'System.AccessViolationException' en mscorlib.dll Attempted to read or
write protected memory. This is often an indication that other memory
is corrupt.
In some other tests, i had PinvokeImbalance sort of... , I guess it was a type mismatch.
The weird thing is that sometimes, the code doesnt throw an exception and proceed, but return the zero-filled array. even when the buffer contains data.
I also try with AllocCoTaskMem but the process crash...,
Can somebody please point me in the right way to do this??
Thanks!

Visual Studio 2008 WriteFile

Im using VS2008 for compiling and developing my application. Im required to take Adc input and serial print it through RS232 in a WinCE6 OS over some termianl like putty or hyperterminal. The problem is when I use the WriteFile function it gives me the following error.
Error 3 error C2440: '=' : cannot convert from 'double' to 'char [32]' c:\Users\Sohan\Downloads\uartdemo\uartdemo\src\main.c 137 Sohan_1
I want to take the input from ADC channel and then after converting it to voltage i have to transmitt. I have tried using a constant char string and it works but when i take the input from the channel and then try it doesnt work.
HANDLE portHandle;
DWORD noOfBytesRead = 0;
DWORD bytesTransmitted = 0;
DWORD firstChoice = 0;
BOOL retVal = FALSE;
char c="hello";
char transmit2Buffer[BUFFER_SIZE] = "7.8888v";
char volt[BUFFER_SIZE];
WriteFile(portHandle, transmit2Buffer, strlen(transmit2Buffer), &bytesTransmitted, NULL);
WriteFile(portHandle, volt, strlen(volt), &bytesTransmitted, NULL);
the first write function works but the second doesnt. variable volt will keep on changing so how should i write it.please help..
After searching i have got an answer for my question.
this worked for me..
You can use sprintf() as you have done to convert a double to a string, but I would actually recommend using _snprintf() instead simply because sprintf() has no regard for the fact that strings are fixed length devices in memory and will overflow if you don't watch it. _snprintf() allows you to specify the length of the out string, just be sure to specify the size as one less than the actual allocated memory block, because _snprintf() does not store the terminating null character if it has to cut the output short.
An example us using _snprintf() is:
void ToString(char * outStr, int length, double val)
{
_snprintf(outStr,length,"%f",val);
}
Got this answer on some website!!!

c++ to VB.Net IntPtr Strings

Alright so I have this code, and I pass it to an unmanaged dll, to which I only know the exports, and have some sample code. I'm getting back the correct string, but it's followed by garbage bytes.
I'm basically translating code verbatim from a c++ example program that doesn't have this issue. I'm assume there is something fundamental I am missing here, so if anyone could tell me what that is, I'd appreciate it.
Example C++ Code
void CDUKPT_TESTDlg::OnButton4()
{
// TODO: Add your control notification handler code here
unsigned char dataout[1024],tmp[1024],ksn[20],keyval[20];
int nRet,len;
memset(dataout,0,sizeof(dataout));
memset(ksn,0,sizeof(ksn));
memset(keyval,0,sizeof(keyval));
memset(tmp,0,sizeof(tmp));
UpdateData(TRUE);
two_one((unsigned char *)m_strCURKSN.GetBuffer(m_strCURKSN.GetLength()),m_strCURKSN.GetLength(),ksn);
two_one((unsigned char *)m_strMACK.GetBuffer(m_strMACK.GetLength()),m_strMACK.GetLength(),keyval);
two_one((unsigned char *)m_EncryptDat.GetBuffer(m_EncryptDat.GetLength()),m_EncryptDat.GetLength(),dataout);
len=m_EncryptDat.GetLength()/2;
//extern int __stdcall ExtractDat(unsigned char *input,
//unsigned short len,unsigned char *output,unsigned char *key,
//unsigned char *ksn);
nRet=ExtractDat(dataout,len,tmp,keyval,ksn); //External Call
//Good string+bad trailing data comes back in tmp
m_Result=tmp;
UpdateData(FALSE);
}
This code spits out this ܉Òdÿo 
Here is my VB.Net Code
Public Function Encrypt(ByVal inp As String) As String
Dim tmpSB As New StringBuilder
Dim i As Integer
Dim tKsn As Char() = TwoOne(StrCurKsn)
For i = tKsn.Length To 19
tKsn = tKsn + Chr(0)
Next
Dim tMack As Char() = TwoOne(StrMack)
For i = tMack.Length To 19
tMack = tMack + Chr(0)
Next
Dim tEnc As Char() = TwoOne(inp)
For i = tEnc.Length To 1023
tEnc = tEnc + Chr(0)
Next
Dim len As Integer = tEnc.Length / 2
Dim tmpStr(1023) As Char
Array.Clear(tmpStr, 0, 1024)
Dim tmpPtr = Marshal.StringToHGlobalAnsi(tmpStr)
Dim nRet = ExtractDat(tEnc, len, tmpPtr, tMack, tKsn)
tmpStr = Marshal.PtrToStringAnsi(tmpPtr)
Dim tsl = tmpStr.Length
Encrypt = tmpStr
End Function
This code spits this out
܉Òdÿo ålUäÙålUäÙålUäÙålUäÙålUäÙålUäÙålUäÙ
So I get the right string, but it's followed by a repeating string of garbage characters.
I'm hoping I've done something blatantly wrong here, but I've tried pulling the data as bytes, and chars, and converting in many different methods, and I can't seem to get rid of those characters...Also, ExtractDat doesn't return the length of the string(not a problem, as it's not supposed to, which is really annoying).
Turns out the dll was bad, so after I got a fresh compile from the vendor it seemed to work.

PathCombine function not working correctly

I'm having some difficulties with the PathCombine function. It does not seem to work correctly in conjunction with SHFileOperation(). My code is as follows:
//beginning of method
TCHAR* root = new TCHAR[MAX_PATH];
root = L"C:\\Users\\jhow\\Desktop\\\0";
//later on in the method
TCHAR* t1Dir = new TCHAR[MAX_PATH]; //root
TCHAR* t2Dir = new TCHAR[MAX_PATH]; //temp
PathCombine(t1Dir,root,L"Folder1\\%REPLACE_THIS%\\\0");
PathCombine(t2Dir,root,L"Folder1\\temp\0");
sf.pFrom = t1Dir;
//sf.pFrom = L"C:\\Users\\jhow\\Desktop\\Folder1\\%REPLACE_THIS%";
sf.pTo = temporaryDir;
//Copy files
int n = SHFileOperation(&sf);
When I have it like it is above, the method sees sf.pTo, but for some reason it does not see sf.pFrom (even after playing around with different combinations of the \ and \0 at the end of the path name). n becomes 2, which I think means file not found... But for example, when I comment out.
sf.pFrom = t1Dir;
and replace it with:
sf.pFrom = L"C:\\Users\\jhow\\Desktop\\Folder1\\%REPLACE_THIS%";
SHFileOperation() works... it returns zero and I can see that all the files are copied into the directory. I find this odd seeing as they appear to be the same exact string (even when I debug and hover over the variables)... Anyone happen to know why this is happening? Is there something wrong with my syntax or logic? Because I don't see it. I am using Visual Studio 2008. Thank you very much for your time.
You are allocating a buffer on the heap for your root variable, but then immediately pointing that variable to a read-only string literal instead, leaking the allocated buffer.
More importantly, you are not taking into account that SHFileOperation() operates on double-null-terminated strings, but PathCombine() returns a single-null-terminated string instead. You are trying to include an extra null in your input to PathCombine(), but that will not work since PathCombine() take single-null-terminated strings as input, so it will never see your extra nulls. You ned to allocate enough space in your output buffers to hold the extra null terminators, and then make sure they are set to zeros before passing those buffers to SHFileOperation().
Try this:
LPTSTR root = TEXT("C:\\Users\\jhow\\Desktop\\");
TCHAR t1Dir[MAX_PATH+2] = {0};
TCHAR t2Dir[MAX_PATH+2] = {0};
PathCombine(t1Dir, root, TEXT("Folder1\\%REPLACE_THIS%\\"));
PathCombine(t2Dir, root, TEXT("Folder1\\temp"));
sf.pFrom = t1Dir;
sf.pTo = t2Dir;
int n = SHFileOperation(&sf);