Call C++ dll with struct containing char array from Node.js - c++

I'm using the Node.js ffi addon to call a C++ DLL.
The problem I'm having is with the struct I'm supplying - it contains a char array - I don't believe I'm setting this up correctly.
As a result I am unable to access the contents.
Routine's definition from C++ header file:
int GetSysConfig(MyConfig * config);
The MyConfig struct is defined in C++ as follows:
typedef struct{
int attribute;
char path[256];
}MyConfig;
My corresponding Node.js struct definition:
var ffi = require('ffi');
var ref = require('ref');
var StructType = require('ref-struct');
var ArrayType = require('ref-array');
// This seems to be the problematic part?
var charArray = ArrayType('char');
charArray.length = 256;
var MyConfig = StructType({
'attribute' : 'int',
'path' : charArray
})
Note: Below here is where I call the DLL from Node.js - I don't think there's a problem here although I could be wrong.
// Create a pointer to the config - we know we expect to supply this to the C++ routine.
var myConfigPtr = ref.refType(MyConfig);
var lib = ffi.Library('my.dll', {
"GetSysConfig": ["int", [myConfigPtr]]
});
var myConfigObj = new MyConfig();
lib.GetSysConfig.async(myConfigObj.ref(), function(err, res) {
console.log("attribute: " + myConfigObj.attribute);
// This is always empty [] - when it shouldn't be.
console.log("path: " + JSON.Stringify(myConfigObj.path));
});
Does anyone know where I'm going wrong with this?

For structs containing arrays: These should be defined with their size specified as a parameter to ArrayType.
For example:
ArrayType('char', 256)
Therefore the fix for my problem is the following:
var MyConfig = StructType({
'attribute' : 'int',
'path' : ArrayType('char', 256)
})

Related

Convert code of "AudioStreamPacketDescription" into swift3.2

I'm converting Audio Queues Service code into swift3.2 but i got stuck here.i don't know how to write this line of code in swift updated version.
I want to convert below code into swift 3.2
player.packetDescs = UnsafeMutablePointer<AudioStreamPacketDescription>(malloc(sizeof(AudioStreamPacketDescription) * Int(player.numPacketsToRead)))
where player object is :
class Player {
var playbackFile: AudioFileID? = nil
var packetPosition: Int64 = 0
var numPacketsToRead: UInt32 = 0
var packetDescs: UnsafeMutablePointer<AudioStreamPacketDescription>? = nil
var isDone = false
}
I tried this :
let j = MemoryLayout.size(ofValue: AudioStreamPacketDescription.self) * Int(player.numPacketsToRead)
player.packetDescs = UnsafeMutablePointer<AudioStreamPacketDescription>(malloc(j))
But this give me error :
Cannot invoke initializer for type
'UnsafeMutablePointer' with an argument
list of type '(UnsafeMutableRawPointer!)'
ok Try this
let sizeTmp = MemoryLayout.size(ofValue: AudioStreamPacketDescription.self) * Int(player.numPacketsToRead)
let tmpPointer = UnsafeMutablePointer<AudioStreamPacketDescription>.allocate(capacity: sizeTmp)
player.packetDescs = tmpPointer

Element is undefined in a Java object of type class coldfusion.runtime.J2eeSessionScope

I have code that uses precisionEvaluate() on a session variable, but when I call the function, there is this error :
Element emp_nextid_ANE_801 is undefined in a Java object of type class
coldfusion.runtime.J2eeSessionScope.
In the code, there is a condition to check this session variable with structKeyExists(), but it still shows an error. Does anyone know why it still errors?
Here is some of the code :
if( structKeyExists(session,'emp_nextid_#app().getCurrentAgentID()#_#officeID#')
AND val(session['emp_nextid_#app().getCurrentAgentID()#_#officeID#']) GT 0) {
var nextID = precisionEvaluate(session['emp_nextid_#app().getCurrentAgentID()#_#officeID#']);
var qData = new Query();
var sql = "SELECT 1 FROM Employee
WHERE pers_id = :nextid";
qData.addParam(name="nextid", value=nextID, cfsqltype="CF_SQL_BIGINT");
var result = qData.execute(sql=sql).getResult();
}
The call, app().getCurrentAgentID(), might be generating values that are changing dynamically. In any case, you can improve the code snippet to:
var key = 'emp_nextid_' & app().getCurrentAgentID() & '_' & officeID;
if( structKeyExists(session,key) AND val(session[key]) GT 0) {
var nextID = precisionEvaluate(session[key]);
...
etc.
}

define, initialize and use types in js-ctypes

SCardTransmit function is defined in https://msdn.microsoft.com/en-us/library/windows/desktop/aa379804%28v=vs.85%29.aspx
I want to declare and use this function, I have problems with the definition of some arguments in js-ctypes (especially in type casting):
LPCSCARD_IO_REQUEST: A pointer to the protocol header structure
LPCBYTE: A pointer to the actual data to be written to the card
LPBYTE: Pointer to a 32-byte buffer that receives the ATR string from the currently inserted card, if available. (this arg is in the status function)
How Can define, initialize and use them?
Here my code:
//-----------------define types----------------------
Cu.import('resource://gre/modules/ctypes.jsm');
var TYPES = {
ABI: is64bit ? ctypes.default_abi : ctypes.winapi_abi,
DWORD: ctypes.uint32_t,
LONG: ctypes.long,
BYTE: ctypes.unsigned_char //ctypes.uint8_t
};
TYPES.LPDWORD = TYPES.DWORD.ptr;
TYPES.SCARDCONTEXT = TYPES.ULONG_PTR;
TYPES.SCARDHANDLE = TYPES.ULONG_PTR;
TYPES.LPBYTE = TYPES.BYTE.ptr;
var CONST = {
SCARD_PROTOCOL_T0: 0x00000000,
SCARD_PROTOCOL_T1: 0x00000001
}
const SCARD_IO_REQUEST = new ctypes.StructType("myStruct" ,
[{"dwProtocol": TYPES.DWORD},
{"cbPciLength": TYPES.DWORD}]);
//------------------declaration-------------------------
var SCardTransmit = cardLib.declare('SCardTransmit', TYPES.ABI, TYPES.LONG, TYPES.SCARDHANDLE, SCARD_IO_REQUEST.ptr, TYPES.LPBYTE, TYPES.DWORD, SCARD_IO_REQUEST.ptr, TYPES.LPBYTE, TYPES.LPDWORD);
//------------------initializing---------------------
var _SCARD_IO_REQUEST = new SCARD_IO_REQUEST;
_SCARD_IO_REQUEST.dwProtocol = CONST.SCARD_PROTOCOL_T0|CONST.SCARD_PROTOCOL_T1;
_SCARD_IO_REQUEST.cbPciLength = _SCARD_IO_REQUEST.dwProtocol.toString().length;
var command = ctypes.char.array(42)("00a4040010a0000000183003010000000000000000");
var commandLength = command.toString().length;
var response = TYPES.LPBYTE;
var responseLength = TYPES.LPDWORD;
//----------------using-------------------------
var rez_SCT = SCardTransmit(cardHandle, _SCARD_IO_REQUEST, command, commandLength, null, response, responseLength.address());
if(rez_SCT.toString() != CONST.SCARD_S_SUCCESS.toString())
{
console.error('cannot begin transaction, error code was: ' + rez_SCT + ' in other terms it is: 0x' + rez_SCT.toString(16) + ' you can look up this error value here: https://msdn.microsoft.com/en-us/library/windows/desktop/aa374738%28v=vs.85%29.aspx#smart_card_return_values');
throw new Error('failed to begin transactio!');
}

DataSource attribute for unit test method

I try to use CSV data source in Device unit test (WinCE/Pocket PC2003 Emulator)
I have added source in using wizard in Data Connection String property:
using Microsoft.VisualStudio.TestTools.UnitTesting;
....
[TestMethod()]
[DeploymentItem("Options.txt")]
[DeploymentItem("Options_1.txt")]
[DataSource("Microsoft.VisualStudio.TestTools.DataSource.CSV", "C:\\...\\Tests\\Data\\LoadSettingsTest.csv", "LoadSettingsTest#csv", DataAccessMethod.Sequential)]
public void LoadSettingsTest()
{
...
}
I have following compiler error:
Error 1 The type or namespace name 'DataSource' could not be found
(are you missing a using directive or an assembly reference?)
Error 2 The type or namespace name 'DataSourceAttribute' could not be
found (are you missing a using directive or an assembly reference?)
What's? Where DataSource is defined? Is data DataSource attribute supported in device unit tests?
DataSource is not supported by Device Unit Testing Framework, see Unit Testing Framework (Devices).
It looks like you are trying to use a Comma Separated Values (CSV) file as a DataSource.
You should convert your CSV data into something a Data Control is familiar with first.
Here is an example:
private const string FIELD_SEP = "\t";
private const string LINE_BREAK = "\r\n";
private const int ONE_KB = 1024;
private System.Data.DataTable GenerateData(string csvDataFile) {
var sb = new System.Text.StringBuilder();
using (var file = File.Open(csvDataFile, FileMode.Open, FileAccess.Read)) {
byte[] buffer = new byte[ONE_KB];
int len = file.Read(buffer, 0, ONE_KB);
while (-1 < len) {
string oneK = Encoding.UTF8.GetString(buffer, 0, len);
sb.Append(oneK);
len = file.Read(buffer, 0, ONE_KB);
}
}
var table = new System.Data.DataTable();
var col1 = table.Columns.Add("ID", typeof(int));
var col2 = table.Columns.Add("Name", typeof(string));
var col3 = table.Columns.Add("Date", typeof(DateTime));
var col4 = table.Columns.Add("Cost", typeof(decimal));
var lines = sb.ToString().Split(LINE_BREAK.ToArray());
foreach (var line in lines) {
System.Data.DataRow row = table.NewRow();
var fields = line.Split(FIELD_SEP.ToArray());
row[col1] = int.Parse(fields[0]);
row[col2] = fields[1];
row[col3] = DateTime.Parse(fields[2]);
row[col4] = decimal.Parse(fields[3]);
table.Rows.Add(row);
}
return table;
}
Of course, I have no idea what kind of data you are trying to extract from this CSV file, and there is no error checking. If field[3] were an empty string, decimal.Parse(field[3]) would throw an exception.

AS3/Regular Expressions - Replacing segments of a string

I have absolutely no knowledge in Regex whatsoever. Basically what I'm trying to do is have an error class that I can use to call errors (obviously) which looks like this:
package avian.framework.errors
{
public class AvError extends Object
{
// errors
public static const LAYER_WARNING:String = "Warning: {0} is not a valid layer - the default layer _fallback_ has been used as the container for {1}.";
/**
* Constructor
* Places a warning or error into the output console to assist with misuse of the framework
* #param err The error to display
* #param params A list of Objects to use throughout the error message
*/
public function AvError(err:String, ...params)
{
trace(err);
}
}
}
What I want to be able to do is use the LAYER_WARNING like this:
new AvError(AvError.LAYER_WARNING, targetLayer, this);
And have the output be something along the lines of:
Warning: randomLayer is not a valid layer - the default layer _fallback_ has been used as the container for [object AvChild].
The idea is to replace {0} with the first parameter parsed in ...params, {1} with the second, etc.
I've done a bit of research and I think I've worked out that I need to search using this pattern:
var pattern:RegExp = /{\d}/;
You can use StringUtil
var original:String = "Here is my {0} and my {1}!";
var myStr:String = StringUtil.substitute(original, ['first', 'second']);
Using the g flag in RegExp you can create an array containing all of your {x} matches, then loop through this array and replace each of the matches with the appropriate parameter.
Code:
var mystring:String = "{0} went to {1} on {2}";
function replace(str:String, ...params):String
{
var pattern:RegExp = /{\d}/g;
var ar:Array = str.match(pattern);
var i:uint = 0;
for(i; i<ar.length; i++)
{
str = str.split(ar[i]).join(params[i]);
}
return str;
}
trace(replace(mystring, "marty", "work", "friday")); // marty went to work on friday
i'm assuming you want to have several static constants with varying replacement instances ({0}, {1}, {2}, etc.) in each string constant.
something like this should work - sorry, it's untested:
public function AvError(err:String, ...params)
{
var replacementArray:Array = err.match(new RegExp("{\\d}", "g"));
for (var i:int = 0, i < replacementArray.length, i++)
err = err.replace(new RegExp(replacementArray[i], "g"), params[i]);
trace(err);
}
if you do have several static constants with varying replacement instances, you'll want to check for an appropriate matching amount of …params that are passed.