I want new and at to return the same userdata, please tell me how to do it
example code that I use
struct SCheckpoint {
rage::ICheckpoint* r_Checkpoint;
SCheckpoint(rage::ICheckpoint* checkpoint) {
r_Checkpoint = checkpoint;
}
int GetId() const {
return r_Checkpoint->GetId();
}
}
int createCheckpoint(lua_State* state) {
rage::ICheckpoint* checkpoint = RaluCore::getInstance().getMultiPlayer()->GetCheckpointPool().New(model, vec, vec, radius, color, defaultShow, dimension);
SCheckpoint* scriptCheckpoint = new SCheckpoint(checkpoint);
checkpoint->External(scriptCheckpoint);
push(state, scriptCheckpoint);
return 1;
}
int atCheckpoint(lua_State* state) {
LuaRef ref = LuaRef::fromStack(state, 1);
rage::ICheckpoint* checkpoint = RaluCore::getInstance().getMultiPlayer()->GetCheckpointPool().GetAt(ref);
SCheckpoint* scriptCheckpoint = checkpoint->External<SCheckpoint>();
push (state, scriptCheckpoint);
return 1;
}
getGlobalNamespace(state)
.beginClass<SCheckpoint>("SCheckpoint")
.addProperty("id", &SCheckpoint::GetId)
.endClass()
.addCFunction("at", &atCheckpoint)
.addCFunction("new", &createCheckpoint);
userdata has different addresses, because of this new != at
local createdCheckpoint = mp.checkpoints.new()
print(createdCheckpoint.id)
local gettedCheckpoint = mp.checkpoints.at(0)
print(gettedCheckpoint.id)
print(createdCheckpoint, gettedCheckpoint, createdCheckpoint == gettedCheckpoint)
returned -
0
0
userdata: 0x34a8c320 userdata: 0x34a8d5b0 false
Related
I'm using open62541 to connect to an OPC/UA server and I'm trying to call methods that a certain object on that server provides. Those methods have custom types as input arguments; for example, the following method takes a structure of three booleans:
<opc:Method SymbolicName="SetStatusMethodType" ModellingRule="Mandatory">
<opc:InputArguments>
<opc:Argument Name="Status" DataType="VisionStatusDataType" ValueRank="Scalar"/>
</opc:InputArguments>
<opc:OutputArguments />
</opc:Method>
Here, VisionStatusDataType is the following structure:
<opc:DataType SymbolicName="VisionStatusDataType" BaseType="ua:Structure">
<opc:ClassName>VisionStatus</opc:ClassName>
<opc:Fields>
<opc:Field Name="Camera" DataType="ua:Boolean" ValueRank="Scalar"/>
<opc:Field Name="StrobeController" DataType="ua:Boolean" ValueRank="Scalar"/>
<opc:Field Name="Server" DataType="ua:Boolean" ValueRank="Scalar"/>
</opc:Fields>
</opc:DataType>
Now, when calling the method, I'm encoding the data into an UA_ExtensionObject, and wrap that one as an UA_Variant to provide it to UA_Client_call. The encoding looks like this:
void encode(const QVariantList& vecqVar, size_t& nIdx, const DataType& dt, std::back_insert_iterator<std::vector<UAptr<UA_ByteString>>> itOut)
{
if (dt.isSimple())
{
auto&& qVar = vecqVar.at(nIdx++);
auto&& uaVar = convertToUaVar(qVar, dt.uaType());
auto pOutBuf = create<UA_ByteString>();
auto nStatus = UA_encodeBinary(uaVar.data, dt.uaType(), pOutBuf.get());
statusCheck(nStatus);
itOut = std::move(pOutBuf);
}
else
{
for (auto&& dtMember : dt.members())
encode(vecqVar, nIdx, dtMember, itOut);
}
}
UA_Variant ToUAVariant(const QVariant& qVar, const DataType& dt)
{
if (dt.isSimple())
return convertToUaVar(qVar, dt.uaType());
else
{
std::vector<UAptr<UA_ByteString>> vecByteStr;
auto&& qVarList = qVar.toList();
size_t nIdx = 0UL;
encode(qVarList, nIdx, dt, std::back_inserter(vecByteStr));
auto pExtObj = UA_ExtensionObject_new();
pExtObj->encoding = UA_EXTENSIONOBJECT_ENCODED_BYTESTRING;
auto nSizeAll = std::accumulate(vecByteStr.cbegin(), vecByteStr.cend(), 0ULL, [](size_t nSize, const UAptr<UA_ByteString>& pByteStr) {
return nSize + pByteStr->length;
});
auto&& uaEncoded = pExtObj->content.encoded;
uaEncoded.typeId = dt.uaType()->typeId;
uaEncoded.body.length = nSizeAll;
auto pData = uaEncoded.body.data = new UA_Byte[nSizeAll];
nIdx = 0UL;
for (auto&& pByteStr : vecByteStr)
{
memcpy_s(pData + nIdx, nSizeAll - nIdx, pByteStr->data, pByteStr->length);
nIdx += pByteStr->length;
}
UA_Variant uaVar;
UA_Variant_init(&uaVar);
UA_Variant_setScalar(&uaVar, pExtObj, &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]);
return uaVar;
}
}
The DataType class is a wrapper for the UA_DataType structure; the original open62541 type can be accessed via DataType::uaType().
Now, once a have the variant (containing the extension object), the method call looks like this:
auto uavarInput = ToUAVariant(qvarArg, dtInput);
UA_Variant* pvarOut;
size_t nOutSize = 0UL;
auto nStatus = UA_Client_call(m_pClient, objNode.nodeId(), m_uaNodeId, 1UL, &uavarInput, &nOutSize, &pvarOut);
The status is 2158690304, i.e. BadInvalidArgument according to UA_StatusCode_name.
Is there really something wrong with the method argument? Are we supposed to send ExtensionObjects, or what data type should the variant contain?
Is it possible that the server itself (created using the .NET OPC/UA stack) is not configured correctly?
N.B., the types here are custom types; that is, the encoding is done manually (see above) by storing the byte representation of all members next to each other in an UA_ByteString - just the opposite of what I'm doing when reading variables or output arguments, which works just fine.
The problem is the typeId of the encoded object. For the server in order to understand the received data, it needs to know the NodeId of the encoding, not the actual NodeId of the type itself. That encoding can be found by following the HasEncoding reference (named "Default Binary") of the type:
auto pRequest = create<UA_BrowseRequest>();
auto pDescr = pRequest->nodesToBrowse = UA_BrowseDescription_new();
pRequest->nodesToBrowseSize = 1UL;
pDescr->nodeId = m_uaNodeId;
pDescr->resultMask = UA_BROWSERESULTMASK_ALL;
pDescr->browseDirection = UA_BROWSEDIRECTION_BOTH;
pDescr->referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASENCODING);
auto response = UA_Client_Service_browse(m_pClient, *pRequest);
for (auto k = 0UL; k < response.resultsSize; ++k)
{
auto browseRes = response.results[k];
for (auto n = 0UL; n < browseRes.referencesSize; ++n)
{
auto browseRef = browseRes.references[n];
if (ToQString(browseRef.browseName.name).contains("Binary"))
{
m_nodeBinaryEnc = browseRef.nodeId.nodeId;
break;
}
}
}
Once you have that NodeId, you pass it to UA_ExtensionObject::content::encoded::typeId:
auto pExtObj = UA_ExtensionObject_new();
pExtObj->encoding = UA_EXTENSIONOBJECT_ENCODED_BYTESTRING;
auto nSizeAll = std::accumulate(vecByteStr.cbegin(), vecByteStr.cend(), 0ULL, [](size_t nSize, const UAptr<UA_ByteString>& pByteStr) {
return nSize + pByteStr->length;
});
auto&& uaEncoded = pExtObj->content.encoded;
uaEncoded.typeId = dt.encoding();
uaEncoded.body.length = nSizeAll;
auto pData = uaEncoded.body.data = new UA_Byte[nSizeAll];
nIdx = 0UL;
for (auto&& pByteStr : vecByteStr)
{
memcpy_s(pData + nIdx, nSizeAll - nIdx, pByteStr->data, pByteStr->length);
nIdx += pByteStr->length;
}
I'm trying to manually bind a vector of pointers from C++ to Lua.
I'm limited to a compiler which has partial C++11 support, so can't use one of the existing binding libraries since they all seem to use C++17 now.
For example, I have a class which contains a list of pointers to a child class. The vector of children is read only from the Lua point of view - I don't need add, remove etc. Just read.
class Child
{
public:
std::string name;
};
class Parent
{
public:
std::vector <Child *>children;
};
...
Parent parent;
Child * m = new Child;
m->name = "Mary";
parent.children.push_back(m);
Child * b = new Child;
b->name = "Bob";
parent.children.push_back(b);
...
Child binding.
static int Child_name(lua_State * lua) {
// this should get a point to a Child object and return the name
lua_pushstring(lua, "child name");
return 1;
}
static const struct luaL_Reg Child_FunctionList[] = {
{ "name", Child_name },
{ NULL, NULL }
};
static int Child_tostring(lua_State * lua) {
lua_pushstring(lua, "Child");
return 1;
}
static const struct luaL_Reg Child_MetaList[] = {
{ "__tostring", Child_tostring },
{ NULL, NULL }
};
void Child_Register(lua_State * lua)
{
luaL_newlib(lua, Child_FunctionList);
if(luaL_newmetatable(lua, "ChildMetaTable"))
luaL_setfuncs(lua, Child_MetaList, 0);
lua_setmetatable(lua, -2);
lua_pop(lua, 1);
}
Parent binding.
static int Parent_count(lua_State * lua) {
// used by both the Parent function and metatable __len
lua_pushinteger(lua, parent.children.size());
return 1;
}
static int Parent_children(lua_State * lua)
{
// stack -1=number(1)
int idx = lua_tonumber(lua, -1);
Child ** c = static_cast<Child **>(lua_newuserdata(lua, sizeof(Parent *)));
*c = parent.children[idx];
luaL_getmetatable(lua, "ChildMetaTable"); // [-0, +1, m]
lua_setmetatable(lua, -2);
// return new userdata - does not work
return 1;
}
static const struct luaL_Reg Parent_FunctionList[] = {
{ "count", Parent_count },
{ "children", Parent_children },
{ NULL, NULL }
};
static int Parent_tostring(lua_State * lua) {
lua_pushstring(lua, "Parent");
return 1;
}
static int Parent_index(lua_State * lua) {
// stack -1=number(1) -2=table
int idx = lua_tonumber(lua, -1);
Child * c = parent.children[idx];
// what to return here?
return 0;
}
static const struct luaL_Reg Parent_MetaList[] = {
{ "__tostring", Parent_tostring },
{ "__len", Parent_count },
{ "__index", Parent_index },
{ NULL, NULL }
};
void Parent_Register(lua_State * lua) {
luaL_newlib(lua, Parent_FunctionList);
if(luaL_newmetatable(lua, "ParentMetaTable"))
luaL_setfuncs(lua, Parent_MetaList, 0);
lua_setmetatable(lua, -2);
lua_setglobal(lua, "Parent");
}
The Parent binding results in a global table, which is intentional. Testing the Parent table:
>print(Parent)
Parent
>print(#Parent)
2
>print(Parent.count())
2
But trying to access the children doesn't work as well
>c = Parent[1]
>print(c)
Child
>print(type(c))
userdata
>print(c.name())
[string "main"]:8: attempt to index a ChildMetaTable value (global 'c')
I get lost in Parent_index, where I need a pointer to the C Parent object rather than the Lua table. I understand the method is to use userdata or lightuserdata but can't see how to bind the class to Lua in order to do this. Same for the Child binding, which results in a ChildMetatable but no Lua table.
Edit: I've added in a children function under Parent, but still not working. Also changed some of the indexes for lua_setmetatable from bottom of stack to top of stack (negative)
Edit2: It's because I'm trying to have Parent:children act both as a table and as userdata. So I can return userdata with the C object pointer along with the ChildMetaTable with __index to determine what to do with the child methods.
What I was trying to do was to have both a Lua table and userdata at the same time.
First the parent __index method is best replaced by function in the table that creates new userdata for the child object.
static int Parent_children(lua_State * lua)
{
int idx = luaL_checkinteger(lua, -1);
Parent * p = &parent;
luaL_argcheck(lua, (idx >= 0) && (idx < (int)p->children.size()), 1, "index out of range");
Child ** pc = static_cast<Child **>(lua_newuserdata(lua, sizeof(Child *)));
*pc = parent.children[idx];
luaL_getmetatable(lua, "ChildMetaTable"); // [-0, +1, m]
lua_setmetatable(lua, -2);
return 1;
}
static const struct luaL_Reg Parent_MetaList[] = {
{ "__tostring", Parent_tostring },
{ NULL, NULL }
};
Since the child is not a Lua table, the child functions can be called from the __index method. Child_FunctionList stays the same.
static int Child_index(lua_State * lua)
{
const char * fn_name = luaL_checkstring(lua, -1);
for(const luaL_Reg * fn = Child_FunctionList; fn->name != NULL; fn++)
{
if(strcmp(fn_name, fn->name) == 0)
{
lua_pushcfunction(lua, fn->func);
return 1;
}
}
return 0;
}
static const struct luaL_Reg Child_MetaList[] = {
{ "__tostring", Child_name },
{ "__index", Child_index },
{ NULL, NULL }
};
And the child methods get a C pointer from the userdata.
static int Child_name(lua_State * lua)
{
Child * c = *reinterpret_cast<Child **>(luaL_checkudata(lua, -1, "ChildMetaTable"));
lua_pushstring(lua, c->name.c_str());
return 1;
}
And finally registering tables values for the child doesn't make sense, so can be removed but the metatable needs to be registered.
void Child_Register(lua_State * lua)
{
if(luaL_newmetatable(lua, "ChildMetaTable"))
luaL_setfuncs(lua, Child_MetaList, 0);
lua_pop(lua, 1);
}
This may not be the optimal solution, but it is heading there.
Edit:
The global parent can be passed as an upvalue in the luaL_newlib macro is expanded, rather than using the global parent.
luaL_newlibtable(lua, Parent_FunctionList);
lua_pushlightuserdata(lua, parent);
luaL_setfuncs(lua, Parent_FunctionList, 1);
...
static int Parent_children(lua_State * lua) {
Parent * parent= (Parent *)(lua_topointer(lua, lua_upvalueindex(1)));
...
I am looking for a way to iterate through a mapping in Solidity. For example I have this mapping:
mapping (address => uint) private shares;
And I want to iterate in a function through all addresses and send them ether according to their shares.
Something like:
function giveOutEth() onlyOwner returns (bool success){
for(uint i=0; i < shares.length ; i++){
//get the address and send a value
}
}
How can I achieve this?
Thanks
I recieved an answer by drlecks:
contract Holders{
uint _totalHolders; // you should initialize this to 0 in the constructor
mapping (uint=> address ) private holders;
mapping (address => uint) private shares;
function GetShares(uint shares) public {
...
holders[_totalHolders] = msg.sender;
shares[msg.sender] = shares;
_totalHolders++;
...
}
function PayOut() public {
...
uint shares;
for(uint i = 0 ; i<_totalHolders; i++) {
shares = shares[holders[i]];
...
}
...
}
}
but keep in mind that it will consume gas, and maybe its better that the stake holders withdraw their ETH and pay for gas themselfs.
If you want something more general, you can use a library. I've included one I'm using below. It could probably use some improvements (ie, Element should be changed to an interface) and it may be overkill (plus, TBH I haven't done any gas consumption comparisons yet). Coming from a more object-oriented background, I prefer using reusable libraries like this, but this is the best I could come up with given Solidity's limitations.
Feel free to use it and/or improve on it.
pragma solidity ^0.4.19;
pragma experimental "ABIEncoderV2";
// experimental encoder needed due to https://github.com/ethereum/solidity/issues/3069
library SetLib {
using SetLib for Set;
struct Set {
mapping(address => IndexData) _dataMap;
uint16 _size;
IndexData[] _dataIndex;
}
struct IndexData {
uint16 _index;
bool _isDeleted;
Element _element;
}
struct Element {
address _value;
uint8 _status;
}
function add(Set storage self, Element element) internal returns (bool) {
if (element._value == 0x0 || self.contains(element)) {
return false;
}
IndexData memory data;
data._index = uint16(self._dataIndex.length);
data._element = element;
self._dataMap[element._value] = data;
self._dataIndex.push(data);
self._size++;
return true;
}
function update(Set storage self, Element element) internal {
if (element._value != 0x0) {
IndexData storage data = self._dataMap[element._value];
if (data._element._value == element._value && !data._isDeleted && element._status != data._element._status)
data._element._status = element._status;
}
}
function getByIndex(Set storage self, uint16 index) internal constant returns (Element) {
IndexData storage data = self._dataIndex[index];
if (!data._isDeleted) {
return data._element;
}
}
function get(Set storage self, address addr) internal constant returns (Element) {
IndexData storage data = self._dataMap[addr];
if (!data._isDeleted) {
return data._element;
}
}
function contains(Set storage self, Element element) internal constant returns (bool) {
return self.contains(element._value);
}
function contains(Set storage self, address addr) internal constant returns (bool) {
if (addr != 0x0) {
IndexData storage data = self._dataMap[addr];
return data._index > 0 && !data._isDeleted;
}
return false;
}
function remove(Set storage self, uint16 index) internal returns (Element) {
IndexData storage data = self._dataIndex[index];
if (data._element._value != 0x0 && !data._isDeleted) {
data._isDeleted = true;
self._size--;
return data._element;
}
}
function remove(Set storage self, address addr) internal returns (Element) {
if (addr != 0x0) {
IndexData storage data = self._dataMap[addr];
if (data._element._value != 0x0 && !data._isDeleted) {
data._isDeleted = true;
self._size--;
return data._element;
}
}
}
function size(Set storage self) internal constant returns (uint16) {
return self._size;
}
}
library IteratorLib {
using SetLib for SetLib.Set;
struct Iterator {
bool _started; // using bool instead of making _curIndex int32 for initial state.
uint16 _curIndex;
uint16 _size;
}
function iterator(SetLib.Set storage set) internal constant returns (IteratorLib.Iterator) {
return IteratorLib.Iterator(false, 0, set.size());
}
function hasNext(Iterator self, SetLib.Set storage set) internal constant returns (bool) {
uint16 testIndex = self._curIndex;
while (testIndex < self._size) {
if (set._dataIndex[testIndex]._element._value != 0x0 && !set._dataIndex[testIndex]._isDeleted)
return true;
testIndex++;
}
return false;
}
function next(Iterator self, SetLib.Set storage set) internal constant returns (SetLib.Element) {
SetLib.Element memory element;
do {
if (self._started) {
self._curIndex++;
}
else {
self._started = true;
}
element = set.getByIndex(self._curIndex);
}
while (element._value != 0x0 && self._curIndex < self._size);
return element;
}
}
A similar template recently:
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;
struct IndexValue {
uint256 keyIndex;
uint256 value;
}
struct KeyFlag {
address key;
bool deleted;
}
struct ItMap {
mapping(address => IndexValue) data;
KeyFlag[] keys;
uint256 size;
}
library IterableMapping {
function insert(
ItMap storage self,
address key,
uint256 value
) internal returns (bool replaced) {
uint256 keyIndex = self.data[key].keyIndex;
self.data[key].value = value;
if (keyIndex > 0) return true;
else {
keyIndex = self.keys.length;
self.keys.push();
self.data[key].keyIndex = keyIndex + 1;
self.keys[keyIndex].key = key;
self.size++;
return false;
}
}
function remove(ItMap storage self, address key)
internal
returns (bool success)
{
uint256 keyIndex = self.data[key].keyIndex;
if (keyIndex == 0) return false;
delete self.data[key];
self.keys[keyIndex - 1].deleted = true;
self.size--;
}
function contains(ItMap storage self, address key)
internal
view
returns (bool)
{
return self.data[key].keyIndex > 0;
}
function start(ItMap storage self)
internal
view
returns (uint256 keyIndex)
{
uint256 index = next(self, type(uint256).min);
return index - 1;
}
function valid(ItMap storage self, uint256 keyIndex)
internal
view
returns (bool)
{
return keyIndex < self.keys.length;
}
function next(ItMap storage self, uint256 keyIndex)
internal
view
returns (uint256)
{
keyIndex++;
while (keyIndex < self.keys.length && self.keys[keyIndex].deleted)
keyIndex++;
return keyIndex;
}
function get(ItMap storage self, uint256 keyIndex)
internal
view
returns (address key, uint256 value)
{
key = self.keys[keyIndex].key;
value = self.data[key].value;
}
}
contract Demo {
using IterableMapping for ItMap;
ItMap shares;
function test() public payable {
for (uint256 i = shares.start(); shares.valid(i); i = shares.next(i)) {
(address k, uint256 v) = shares.get(i);
// get the address and send a value
}
}
}
This code keeps returning "SQLITE BUSY : Database is locked" even though I was not accessing it from another external thread or process and how can I resolve this?
The code uses CppSQLite3 C++ wrapper for SQLite.
int DepartmentAccess::SaveOrDeleteAccess(long long iDeptNameID,long long &iUserID,int &iAccessTypeID)
{
char szString[1000];
char chAccessTypeID[1000];
StringCbPrintfA(szString,sizeof(szString),"%d",iAccessTypeID);
EncryptString(szString,chAccessTypeID);
try
{
char szDatabaseFile[1000];
GetDatabaseA(szDatabaseFile,sizeof(szDatabaseFile));
CppSQLite3DB db;
db.open(szDatabaseFile);
CppSQLite3Statement stmt = db.compileStatement("SELECT AccessID FROM DepartmentAccess WHERE (InsututionID = ? AND DeptNameID = ? AND UserID = ? AND AccessType = ?)");
stmt.bind(1,m_iInsututionID);
stmt.bind(2,iDeptNameID);
stmt.bind(3,iUserID);
stmt.bind(4,chAccessTypeID);
CppSQLite3Query q = stmt.execQuery();
if(!q.fieldIsNull(0))
{
if(!m_iMode)
{
return -2;
}
}
if(!m_iMode)
{
StringCbCopyA(szString,sizeof(szString),"INSERT INTO DepartmentAccess(InsututionID,DeptNameID,UserID,AccessType) VALUES(?,?,?,?)");
}
else
{
StringCbCopyA(szString,sizeof(szString),"DELETE FROM DepartmentAccess WHERE (InsututionID = ? AND DeptNameID = ? AND UserID = ? AND AccessType = ?)");
}
CppSQLite3Statement stmt1 = db.compileStatement(szString);
int iPosition = 1;
stmt1.bind(iPosition++, m_iInsututionID);
stmt1.bind(iPosition++, iDeptNameID);
stmt1.bind(iPosition++, iUserID);
stmt1.bind(iPosition++, chAccessTypeID);
//Execution gets to this point
stmt1.execDML();
//Execution fails to get to this point
if(!m_iMode)
{
StringCbPrintfA(szString,sizeof(szString),"DELETE FROM DepartmentAccessRequest WHERE (InsututionID = ? AND DeptNameID = ? AND UserID = ? AND RequestedAccess = ?)");
CppSQLite3Statement stmt2 = db.compileStatement(szString);
int iPosition = 1;
stmt2.bind(iPosition++, m_iInsututionID);
stmt2.bind(iPosition++, iDeptNameID);
stmt2.bind(iPosition++, iUserID);
stmt2.bind(iPosition++, chAccessTypeID);
stmt2.execDML();
}
return 1;
}
catch(CppSQLite3Exception & e)
{
char szString[200];
StringCbPrintfA(szString,sizeof(szString),"Error Code: %d\n Error Mesage: %s",e.errorCode(),e.errorMessage());
MessageBoxA(NULL,szString,"Save Or Delete Access Error(Department Access)",MB_OK);
}
return 0;
}
Good day to all,
Please I need somebody to help me have a look at my codes.I am having this error of** Object reference not set to an instance Of Object**.It appears the error is within this lines of codes
if (_scrollingTimer == null)
{
_scrollingTimer = new Timer()
{
Enabled = false,
Interval = 500,
Tag = (sender as TrackBar).Value
};
but unfortunately I was unable to resolve this error.I would be very glad if somebody could help me out.thank you for the usual support.best regards.
Firstoption.
Below are the remaining part of the codes.
byte[] data = new byte[5];
private Timer _scrollingTimer = null;
private void button3_Click(object sender, EventArgs e)
{
UInt32 numBytesWritten = 0;
data[0] = 1;
myFtdiDevice.Write(data, 1, ref numBytesWritten);
data[0] = 0x6A;
myFtdiDevice.Write(data, 1, ref numBytesWritten);
}
private void trackBar1_Scroll(object sender, EventArgs e)
{
if(!backgroundWorker1.IsBusy)
{
backgroundWorker1.RunWorkerAsync();
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
UInt32 numBytesWritten = 1;
string dataToWrite = "#0";
if (_scrollingTimer == null)
{
_scrollingTimer = new Timer()
{
Enabled = false,
Interval = 500,
Tag = (sender as TrackBar).Value
};
_scrollingTimer.Tick += (s, ea) =>
{
if (trackBar1.Value == (int)_scrollingTimer.Tag)
{
_scrollingTimer.Stop();
myFtdiDevice.Write(dataToWrite, dataToWrite.Length, ref numBytesWritten);
int percent = (int)(((double)trackBar1.Value / (double)trackBar1.Maximum) * 100);
label2.Text = (percent.ToString()) + "%";
data[0] = Convert.ToByte(percent);
data[1] = 0x6A;
myFtdiDevice.Write(data, 2, ref numBytesWritten);
_scrollingTimer.Dispose();
_scrollingTimer = null;
}
else
{
_scrollingTimer.Tag = trackBar1.Value;
}
};
_scrollingTimer.Start();
}
}
sender is not a TrackBar. Looks like it's probably backgroundWorker1.