SHFileOperation/SHFILEOPSTRUCT - c++

Im trying to copy a directory to a new location. So I am using SHFileOperation/SHFILEOPSTRUCT as follows:
SHFILEOPSTRUCT sf;
memset(&sf,0,sizeof(sf));
sf.hwnd = 0;
sf.wFunc = FO_COPY;
dirName += "\\*.*";
sf.pFrom = dirName.c_str();
string copyDir = homeDir + "\\CopyDir";
sf.pTo = copyDir.c_str();
sf.fFlags = FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR | FOF_NOERRORUI;
int n = SHFileOperation(&sf);
if(n != 0)
{
int x = 0;
}
So I set the values as above. There is a file I created in the folder (I have closed the Handle so it should be fine to move). The SHFileOperation call is returning 2, but I cant find anywhere where these error codes are explained. Does anyone know where I can find out what 2 means, or does anyone have any ideas why it might not be working? Cheers

Error code 2 means The system cannot find the file specified.
See Windows System Error Codes for full listing of error descriptions, or write a function that will obtain the description for the error code:
std::string error_to_string(const DWORD a_error_code)
{
// Get the last windows error message.
char msg_buf[1025] = { 0 };
// Get the error message for our os code.
if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
0,
a_error_code,
0,
msg_buf,
sizeof(msg_buf) - 1,
0))
{
// Remove trailing newline character.
char* nl_ptr = 0;
if (0 != (nl_ptr = strchr(msg_buf, '\n')))
{
*nl_ptr = '\0';
}
if (0 != (nl_ptr = strchr(msg_buf, '\r')))
{
*nl_ptr = '\0';
}
return std::string(msg_buf);
}
return std::string("Failed to get error message");
}
From reading the documentation for SHFileOperation the strings specified for pTo and pFrom must be double null terminated: yours are only singly null terminated. Try the following:
dirName.append(1, '\0');
sf.pFrom = dirName.c_str();
string copyDir = homeDir + "\\CopyDir";
copyDir.append(1, '\0');
sf.pTo = copyDir.c_str();

Related

Getting error 23 in HikvisionDevicel Integrartion

Using Hikvision sdk some commands of API(NET_ECMS_XMLConfig) are working but some commands are showing error 23(device does not support this funtion).
I want to know what this message mean either my device really does not support or I am doing something wrong?.
NET_EHOME_XML_CFG devStatus={0};
DWORD dwConfigSize=sizeof(devStatus);
FILE *req_file = NULL;
string filename_req="./xml/GetDevAbility_input.xml";
req_file = fopen(filename_req.c_str(),"rb");
fseek(req_file,0,SEEK_END);
int size_req = ftell(req_file);
fseek(req_file, 0, SEEK_SET);
char *req = (char *)malloc(size_req + 1);
fread(req, size_req, 1, req_file);
fclose(req_file);
req[size_req] = 0;
FILE *resp_file = NULL;
string filename_resp="./xml/GetDevAbility_output.xml";
resp_file = fopen(filename_resp.c_str(),"rb");
fseek(resp_file,0,SEEK_END);
int size_resp = ftell(resp_file);
char cmd[]="GETDEVICECONFIG";
devStatus.pCmdBuf=&cmd;
devStatus.dwCmdLen=sizeof(cmd);
devStatus.pInBuf=req;
devStatus.dwInSize=size_req;
char message[size_resp];
devStatus.pOutBuf=&message;
devStatus.dwOutSize=size_resp;
devStatus.dwRecvTimeOut=30 * 1000;
if(NET_ECMS_XMLConfig(lUserID,&devStatus,dwConfigSize)) printf("xml resp %s\n",message);
else printf("error getting device info CMS: %d\n",NET_ECMS_GetLastError());
GetDevAbility_input.xml:
<Params>
<ConfigCmd>GetServerInfoParaCapabilities</ConfigCmd>
<ConfigParam1>0</ConfigParam1>
<ConfigParam1>0</ConfigParam1>
<ConfigParam1>0</ConfigParam1>
<ConfigParam1>0</ConfigParam1>
</Params>

Pass Byte Array as std::vector<char> from Node.js to C++ Addon

I have some constraints where the addon is built with nan.h and v8 (not the new node-addon-api).
The end function is a part of a library. It accepts std::vector<char> that represents the bytes of an image.
I tried creating an image buffer from Node.js:
const img = fs.readFileSync('./myImage.png');
myAddonFunction(Buffer.from(img));
I am not really sure how to continue from here. I tried creating a new vector with a buffer, like so:
std::vector<char> buffer(data);
But it seems like I need to give it a size, which I am unsure how to get. Regardless, even when I use the initial buffer size (from Node.js), the image fails to go through.
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
[1] 16021 abort (core dumped)
However, when I read the image directly from C++, it all works fine:
std::ifstream ifs ("./myImage.png", std::ios::binary|std::ios::ate);
std::ifstream::pos_type pos = ifs.tellg();
std::vector<char> buffer(pos);
ifs.seekg(0, std::ios::beg);
ifs.read(&buffer[0], pos);
// further below, I pass "buffer" to the function and it works just fine.
But of course, I need the image to come from Node.js. Maybe Buffer is not what I am looking for?
Here is an example based on N-API; I would also encourage you to take a look similar implementation based on node-addon-api (it is an easy to use C++ wrapper on top of N-API)
https://github.com/nodejs/node-addon-examples/tree/master/array_buffer_to_native/node-addon-api
#include <assert.h>
#include "addon_api.h"
#include "stdio.h"
napi_value CArrayBuffSum(napi_env env, napi_callback_info info)
{
napi_status status;
const size_t MaxArgExpected = 1;
napi_value args[MaxArgExpected];
size_t argc = sizeof(args) / sizeof(napi_value);
status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
assert(status == napi_ok);
if (argc < 1)
napi_throw_error(env, "EINVAL", "Too few arguments");
napi_value buff = args[0];
napi_valuetype valuetype;
status = napi_typeof(env, buff, &valuetype);
assert(status == napi_ok);
if (valuetype == napi_object)
{
bool isArrayBuff = 0;
status = napi_is_arraybuffer(env, buff, &isArrayBuff);
assert(status == napi_ok);
if (isArrayBuff != true)
napi_throw_error(env, "EINVAL", "Expected an ArrayBuffer");
}
int32_t *buff_data = NULL;
size_t byte_length = 0;
int32_t sum = 0;
napi_get_arraybuffer_info(env, buff, (void **)&buff_data, &byte_length);
assert(status == napi_ok);
printf("\nC: Int32Array size = %d, (ie: bytes=%d)",
(int)(byte_length / sizeof(int32_t)), (int)byte_length);
for (int i = 0; i < byte_length / sizeof(int32_t); ++i)
{
sum += *(buff_data + i);
printf("\nC: Int32ArrayBuff[%d] = %d", i, *(buff_data + i));
}
napi_value rcValue;
napi_create_int32(env, sum, &rcValue);
return (rcValue);
}
The JavaScript code to call the addon
'use strict'
const myaddon = require('bindings')('mync1');
function test1() {
const array = new Int32Array(10);
for (let i = 0; i < 10; ++i)
array[i] = i * 5;
const sum = myaddon.ArrayBuffSum(array.buffer);
console.log();
console.log(`js: Sum of the array = ${sum}`);
}
test1();
The Output of the code execution:
C: Int32Array size = 10, (ie: bytes=40)
C: Int32ArrayBuff[0] = 0
C: Int32ArrayBuff[1] = 5
C: Int32ArrayBuff[2] = 10
C: Int32ArrayBuff[3] = 15
C: Int32ArrayBuff[4] = 20
C: Int32ArrayBuff[5] = 25
C: Int32ArrayBuff[6] = 30
C: Int32ArrayBuff[7] = 35
C: Int32ArrayBuff[8] = 40
C: Int32ArrayBuff[9] = 45
js: Sum of the array = 225

What wrong I have done? The function of GetDiskFreeSpaceExA didn't work at all

I tried to use GetDiskFreeSpaceExA function, but it doesn't work:
int drvNbr = PathGetDriveNumber(db7zfolderw);
if (drvNbr == -1) // fn returns -1 on error
{
const char * errmsg = "error occured during get drive number";
strcpy_s(retmsg, strlen(errmsg) + 1, errmsg);
return -3;
}
char driverletter = (char)(65 + drvNbr);
string driverstr(1, driverletter);
driverstr = driverstr + ":";
PULARGE_INTEGER freespace = 0;
PULARGE_INTEGER totalnumbtype = 0;
PULARGE_INTEGER totalnumberfreebyte = 0;
fileSize = SzArEx_GetFileSize(&db, i);
BOOL myresult=GetDiskFreeSpaceExA(
driverstr.c_str(),
freespace,
totalnumbtype,
totalnumberfreebyte
);
The value of variable freespace is 0. I have no idea why it didn't work if the value of variable which is driverstr.c_str() was D:?
Thanks for your help.
You need to supply pointers to variables that will hold the value returned. Right now you a re supplying null pointers so nothing is retured:
::ULARGE_INTEGER freespace{};
::ULARGE_INTEGER totalnumbtype{};
::ULARGE_INTEGER totalnumberfreebyte{};
::BOOL myresult
{
::GetDiskFreeSpaceExA
(
driverstr.c_str()
, &freespace
, &totalnumbtype
, &totalnumberfreebyte
)
};
It would also be a good idea to use wide char versions of these functions.

std::list copy to std::vector skipping elements

I've run across a rather bizarre exception while running C++ code in my objective-C application. I'm using libxml2 to read an XSD file. I then store the relevant tags as instances of the Tag class in an std::list. I then copy this list into an std::vector using an iterator on the list. However, every now and then some elements of the list aren't copied to the vector. Any help would be greatly appreciated.
printf("\n length list = %lu, length vector = %lu\n",XSDFile::tagsList.size(), XSDFile::tags.size() );
std::list<Tag>::iterator it = XSDFile::tagsList.begin();
//result: length list = 94, length vector = 0
/*
for(;it!=XSDFile::tagsList.end();++it)
{
XSDFile::tags.push_back(*it); //BAD_ACCESS code 1 . . very bizarre . . . . 25
}
*/
std::copy (XSDFile::tagsList.begin(), XSDFile::tagsList.end(), std::back_inserter (XSDFile::tags));
printf("\n Num tags in vector = %lu\n", XSDFile::tags.size());
if (XSDFile::tagsList.size() != XSDFile::tags.size())
{
printf("\n length list = %lu, length vector = %lu\n",XSDFile::tagsList.size(), XSDFile::tags.size() );
//result: length list = 94, length vector = 83
}
I've found the problem. The memory was corrupted causing the std::list to become corrupted during the parsing of the XSD. I parse the XSD using a function start_element.
xmlSAXHandler handler = {0};
handler.startElement = start_element;
I used malloc guard in xcode to locate the use of freed memory. It pointed to the line:
std::strcpy(message, (char*)name);
So I removed the malloc (actually commented in the code) and it worked. The std::vector now consistently copies all 94 entries of the list. If anyone has an explanation as to why this worked that would be great.
static void start_element(void * ctx, const xmlChar *name, const xmlChar **atts)
{
// int len = strlen((char*)name);
// char *message = (char*)malloc(len*sizeof(char));
// std::strcpy(message, (char*)name);
if (atts != NULL)
{
// atts[0] = type
// atts[1] = value
// len = strlen((char*)atts[1]);
// char *firstAttr = (char*)malloc(len*sizeof(char));
// std::strcpy(firstAttr, (char*)atts[1]);
if(strcmp((char*)name, "xs:include")==0)
{
XSDFile xsd;
xsd.ReadXSDTypes((char*)atts[1]);
}
else if(strcmp((char*)name, "xs:element")==0)
{
doElement(atts);
}
else if(strcmp((char*)name, "xs:sequence")==0)
{
//set the default values
XSDFile::sequenceMin = XSDFile::sequenceMax = 1;
if (sizeof(atts) == 4)
{
if(strcmp((char*)atts[3],"unbounded")==0)
XSDFile::sequenceMax = -1;
int i = 0;
while(atts[i] != NULL)
{
//atts[i] = name
//atts[i+i] = value
std::string name((char*)atts[i]);
std::string value((char*)atts[i+1]);
if(name=="minOccurs")
XSDFile::sequenceMin = (atoi(value.c_str()));
else if(name=="maxOccurs")
XSDFile::sequenceMax = (atoi(value.c_str()));
i += 2;
}
}
}
}
//free(message);
}

c++ cli comparing hexadecimal bytes from a file not working

I have this file called ab.exe it contains this in hexadecimal
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000BBAAE8CAFDFFFF83C408000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000054AAE8CAFDFFFF83C40800000000000000000000000000000000000000000000000000000000000000000000000000AAE8CAFDFFFF83C4088D000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
I have this code in c++ that is suppose to detect if a string of hexadecimal is in a file or not and if it is add it to the list box.
array<Byte>^ target1 = { 0xAA,0xE8,0xCA,0xFD,0xFF,0xFF,0x83,0xC4,0x08,0x8D };
array<Byte>^ target2 = { 0x54,0xAA,0xE8,0xCA,0xFD,0xFF,0xFF,0x83,0xC4,0x08 };
array<Byte>^ target3 = { 0xBB,0xAA,0xE8,0xCA,0xFD,0xFF,0xFF,0x83,0xC4,0x08 };
int matched1 = 0;
int matched2 = 0;
int matched3 = 0;
FileStream^ fs2 = gcnew FileStream(line, FileMode::Open, FileAccess::Read, FileShare::ReadWrite);
int value;
do
{
value = fs2->ReadByte();
if (value == target1[matched1]) {
matched1++;
}
else
matched1 = 0;
if (value == target2[matched2]) {
matched2++;
}
else
matched2 = 0;
if (value == target3[matched3]) {
matched3++;
}
else
matched3 = 0;
if(matched1 == target1->Length)
{
listBox1->Items->Add(line + "1");
}
if(matched2 == target2->Length)
{
listBox1->Items->Add(line + "2");
}
if(matched3 == target3->Length)
{
listBox1->Items->Add(line + "3");
}
} while (value != -1);
fs2->Close();
the problem is that it only adds line + 3 to the list box and not line + 1 or line + 2 to the list box
I do not know why that is because all 3 of the strings are in the file so they all should be added to the list box. for some reason only the last one is being added because I tried just having 2 and the second one got added.can someone show me why they are not all being added to the list box.
thanks
Update1
after playing around with it some more it is not the last target that gets added each time, It is the first string that appears in the file that gets added. I stepped through the program using message boxes and what is happening is lets say 54AAE8CAFDFFFF83C408 is the first string to appear in the file then line + 2 will be added, but then for some reason the matched integer for all 3 stop counting they just = 0 the rest of the file. can someone explain to me why that is and how to fix it.
Update2
here is the answer to the problem. all I needed to do was just add a matched = 0; after each add to list box command.
listBox1->Items->Add(line + "1");
matched1 = 0;
listBox1->Items->Add(line + "2");
matched2 = 0;
listBox1->Items->Add(line + "3");
matched3 = 0;
It seems to me that after the first matching of one pattern (here target3) you read beyond last byte of target3 (because of matched3++), this may cause undesired behavior.
Update1:
if(matched1 == target1->Length)
{
matched1 = 0; // pattern matched so reset counter
...
}