I am trying to send CAN Frames with xlCanTransmit method. The problem is that it returns 0 (XL_SUCCESS), but the frame is empty. there are only zeroes in the Frame.
IVxlApi.s_xl_event eventMsg = new IVxlApi.s_xl_event();
...
...
xlStatus = dll.xlCanTransmit(GlobalConfig.g_xlPortHandle, GlobalConfig.g_xlChannelMask[channelIndex],
pEventCount, eventMsg.getPointer());
After Calling the function xlCanTransmit() the frame is sent, but there is no data in it. The function is called from dll file and you can't debug it.
My mapped Structure
public static class s_xl_event extends Structure {
public byte tag;
public byte chanIndex;
public byte[] transId = new byte[SHORT];
public byte[] portHandle = new byte[SHORT];
public byte flags;
public byte reserved;
public byte[] timeStamp = new byte[LONG];
public s_xl_tag_data tagData;
#Override
public void read() {
// read from native memory, populate tag
super.read();
// set union type based on tag
switch (tag) {
case XL_RECEIVE_MSG:
case XL_TRANSMIT_MSG:
tagData.setType(s_xl_can_msg.class);
break;
case XL_CHIP_STATE:
tagData.setType(s_xl_chip_state.class);
break;
case XL_LIN_MSG:
tagData.setType(s_xl_lin_msg_api.class);
break;
case XL_SYNC_PULSE:
tagData.setType(s_xl_sync_pulse.class);
break;
case XL_RECEIVE_DAIO_DATA:
tagData.setType(s_xl_daio_data.class);
break;
case XL_TRANSCEIVER:
tagData.setType(s_xl_transceiver.class);
break;
case XL_RECEIVE_DAIO_PIGGY:
tagData.setType(s_xl_daio_piggy_data.class);
break;
case XL_KLINE_MSG:
tagData.setType(s_xl_kline_data.class);
break;
default:
// add default type or throw exception etc.
tagData.setType(s_xl_can_msg.class);
break;
}
// now read tagData from native memory
tagData.read();
}
#Override
protected List<String> getFieldOrder() {
return Arrays.asList("tag", "chanIndex", "transId", "portHandle", "flags", "reserved", "timeStamp", "tagData");
}
}
CAN Frame in CANoe Trace
enter image description here
The function on the native side looks like this
DECL_STDXL_FUNC(xlCanTransmit, XLCANTRANSMIT, (
XLportHandle portHandle,
XLaccess accessMask,
unsigned int* pEventCount,
void* pEvents)
);
My mapping in java
short xlCanTransmit(long portHandle, long accessMask, IntByReference pEventCount, Pointer pEvents);
I wrote some random data manually and called the xlCanTransmit() function.
But in CANoe trace I see only empty frame with no data and id.
My send function in java
public short send(String txID, String dlc, String[] data, int channelIndex) {
short xlStatus = IVxlApi.XL_ERROR;
IntByReference pEventCount = new IntByReference(1);
IVxlApi.s_xl_event eventMsg = new IVxlApi.s_xl_event();
eventMsg.tag = IVxlApi.XL_TRANSMIT_MSG;
eventMsg.tagData.msg.id[0] = 2;// = Long.parseLong(txID);
eventMsg.tagData.msg.dlc[0] = 8;// = Short.parseShort(dlc);
eventMsg.tagData.msg.flags[0] = 0;
eventMsg.tagData.msg.data[0] = Byte.parseByte(data[0]);
eventMsg.tagData.msg.data[1] = Byte.parseByte(data[1]);
eventMsg.tagData.msg.data[2] = Byte.parseByte(data[2]);
eventMsg.tagData.msg.data[3] = Byte.parseByte(data[3]);
eventMsg.tagData.msg.data[4] = Byte.parseByte(data[4]);
eventMsg.tagData.msg.data[5] = Byte.parseByte(data[5]);
eventMsg.tagData.msg.data[6] = Byte.parseByte(data[6]);
eventMsg.tagData.msg.data[7] = Byte.parseByte(data[7]);
/*if(true){
eventMsg.tagData.msg.id |= IVxlApi.XL_CAN_EXT_MSG_ID;
}*/
eventMsg.write();
xlStatus = dll.xlCanTransmit(GlobalConfig.g_xlPortHandle, GlobalConfig.g_xlChannelMask[channelIndex],
pEventCount, eventMsg.getPointer());
eventMsg.read();
return xlStatus;
}
CAN Frame in CANoe Trace
enter image description here
After calling tagData.read() (line 475) the data initialized with zeroes
enter image description here
The return value of 0 indicates the function preformed properly on the native side, but you haven't copied the native memory back to Java.
This is normally done automatically when you pass a Structure in a function, but you have passed the Pointer to the structure instead. Your last argument is eventMsg.getPointer(). JNA doesn't know how the Pointer maps to your structure until you tell it to do so, and in the current way you're calling it requires using read() to copy the value back to JNA.
You could probably get the results you want by just executing eventMsg.read() after calling the function, but the better solition is to pass the Structure to the function in the first place and let JNA do the conversion to Pointer and auto-read() for you. Change your function call to pass eventMsg as the argument.
Related
I'm trying to use System.IO.Pipelines to parse large text files.
But I can't find no conversion function from ReadOnlySequence to ReadOnlySequence. For example like MemoryMarshal.Cast<byte,char>.
IMHO it is pretty useless having a generic ReadOnlySequence<T> if there is only one particular type (byte) applicable.
static async Task ReadPipeAsync(PipeReader reader, IStringValueFactory factory)
{
while (true)
{
ReadResult result = await reader.ReadAsync();
ReadOnlySequence<byte> buffer = result.Buffer;
//ReadOnlySequence<char> chars = buffer.CastTo<char>(); ???
}
}
You would have to write a conversion operator to achieve this cast. You cannot cast it explicitly. Be aware that a char[] is two bytes, so you need to choose your encoding algorithm.
IMHO it is pretty useless having a generic ReadOnlySequence<T> if
there is only one particular type (byte) applicable.
While it's true that System.IO.Pipelines will only give you a ReadOnlySequence<byte> because of the fact that a PipeReader is attached to a Stream which is just a stream of bytes, there are other use cases for a ReadOnlySequence<T> eg,
ReadOnlySequence<char> roChars = new ReadOnlySequence<char>("some chars".ToCharArray());
ReadOnlySequence<string> roStrings = new ReadOnlySequence<string>(new string[] { "string1", "string2", "Another String" });
Your conversion operator would have similar logic to the below, but you would set your encoding appropriately.
static void Main(string[] args)
{
// create a 64k Readonly sequence of random bytes
var ros = new ReadOnlySequence<byte>(GenerateRandomBytes(64000));
//Optionally extract the section of the ReadOnlySequence we are interested in
var mySlice = ros.Slice(22222, 55555);
char[] charArray;
// Check if the slice is a single segment - not really necessary
// included for explanation only
if(mySlice.IsSingleSegment)
{
charArray = Encoding.ASCII.GetString(mySlice.FirstSpan).ToCharArray();
}
else
// Could only do this and always assume multiple spans
// which is highly likley for a PipeReader stream
{
Span<byte> theSpan = new byte[ros.Length];
mySlice.CopyTo(theSpan);
// ASCII Encoding - one byte of span = 2 bytes of char
charArray = Encoding.ASCII.GetString(theSpan).ToCharArray();
}
// Convert the char array back to a ReadOnlySegment<char>
var rosChar = new ReadOnlySequence<char>(charArray);
}
public static byte[] GenerateRandomBytes(int length)
{
// Create a buffer
byte[] randBytes;
if (length >= 1)
randBytes = new byte[length];
else
randBytes = new byte[1];
// Create a new RNGCryptoServiceProvider.
System.Security.Cryptography.RNGCryptoServiceProvider rand =
new System.Security.Cryptography.RNGCryptoServiceProvider();
// Fill the buffer with random bytes.
rand.GetBytes(randBytes);
// return the bytes.
return randBytes;
}
I have an Arduino sketch that will be working on an Arduino UNO and I am trying to get uno to communicate over the i2c connection with a raspberry pi.
Problem is using wire.h library where method Wire.onRequest is working just fine when I use it like this.
#include <Wire.h>
#define COMM_DELAY 50
#define SLAVE_ADDRESS 0x04
int current_rule = 0;
void initI2c() {
// initialize i2c as slave
Wire.begin(SLAVE_ADDRESS);
// define callbacks for i2c communication
Wire.onReceive(receiveData);
}
// callback for received data
void receiveData(int byteCount) {
while (Wire.available()) {
current_rule = Wire.read();
}
}
but when I try to make this exact result with a class method, I get an error :
invalid use of non-static member function
(with Wire.onRequest(this->receiveData) line gets to be marked red)
Just like this:
void (*funptr)();
typedef void (*Callback)(byte);
class Comm{
public:
int callback_list_size = 0;
bool option_debug;
byte option_address;
int option_comm_delay;
void(*callback_list[256]);
byte *rules;
// function for receiving data. raspberry -> arduino
// Whenever the master sends new data, this method will call the appropriate callback.
void receiveData()
{
byte data;
Serial.println("[INFO] Received new data from master");
while (Wire.available())
{
data = Wire.read();
}
for (int i = 0; i < callback_list_size; i++)
{
if (rules[i] == data){
funptr = callback_list[i];
funptr();
}
}
}
// function for sending data. Called when raspberry request data. arduino -> raspberry
// Whenever the master requests data, this method will be called. For now we don't need this but anyway.
void sendData(int s)
{
if (option_debug)
Serial.println("[INFO] Master requests data!");
}
/* Constructor that takes 3 parameters at max. Only the adress is mandatory others are optional and will be filled with default values
:address - adress of slave(arduino) - Example 0x04
:delay - a delay is needed because I2C clock is quite slow compared to the CPU clock - 50
:debug - for debug purposes if true debug info will be sent to Serial interface - true/false
*/
Comm(byte address, int delay = 50, bool debug = false)
{
option_address = address;
option_comm_delay = delay;
option_debug = debug;
if (debug)
Serial.println("[INFO] Comm Object Created!");
}
// Function needs to be called to initialize the communication channel.
void initI2c()
{
Wire.begin(option_address);
Wire.onReceive(this->sendData);
Wire.onRequest(this->receiveData);
if (option_debug)
Serial.println("[INFO] I2C channel initialized");
}
// Function to add new callback for a rule.
// This function returns id of passed callback
int addCallback(Callback func, byte rule)
{
callback_list_size++;
// Enlarge rules array to keep 1 more byte
byte *temp = new byte[callback_list_size]; // create new bigger array.
for (int i = 0; i + 1 < callback_list_size; i++) // reason fo i+1 is if callback_list_size is 1 than this is the first initializition so we don't need any copying.
{
temp[i] = rules[i]; // copy rules to newer array.
}
delete[] rules; // free old array memory.
rules = temp; // now rules points to new array.
callback_list[callback_list_size - 1] = &func;
rules[callback_list_size - 1] = rule;
return callback_list_size;
}
};
Comm *i2c_comm;
void loop()
{
}
void setup()
{
Serial.begin(9600);
initI2C();
}
void initI2C()
{
i2c_comm = new Comm(0x04, 50, true);
i2c_comm->initI2c();
//Callback Definitions
i2c_comm->addCallback(&rule_1, 0x01);
i2c_comm->addCallback(&rule_2, 0x02);
i2c_comm->addCallback(&rule_3, 0x03);
i2c_comm->addCallback(&rule_4, 0x04);
}
I also tried to make the receiveData method to be static.
But in this case I have an error like this:
invalid use of member Com::callback_list_size in static member function
which makes sense to me as static method won't know which callback_list_size I am talking about.
so I am quite confused about how I can handle such a problem?
You're almost there. Generally speaking in C++ you need to pass a static class method for callback functions.
The error you received after changing your method to static is expected as you're trying to access a member of an instance of the class Comm which cannot be done in a static method in which there is no 'this'.
Here's one of many techniques to consider, but please read over the SO post Using a C++ class member function as a C callback function.
Anyway the approach here is to leverage a static pointer to an instance.
class Comm {
private:
static Comm* pSingletonInstance;
static void OnReceiveHandler() {
if (pSingletonInstance)
pSingletonInstance->receiveData();
}
static void OnSendHandler(int s) {
if (pSingletonInstance)
pSingletonInstance->sendData(s);
}
void initI2c() {
Comm::pSingletonInstance = this; // Assign the static singleton used in the static handlers.
Wire.onReceive(Comm::OnSendHandler);
Wire.onRequest(Comm::OnReceiveHandler);
Wire.begin(option_address);
}
}
// static initializer for the static member.
Comm* Comm::pSingletonInstance = 0;
Again there are many ways to get around this issue but above is an easy one and likely suitable for your project. If you need to manage multiple instances of Comm, you'll have to do something quite different.
Good luck!
I'm encountering a strange problem on an arduino sketch.
I'ts a sketch quite complex so i've decided to write in whith classes.
Basically it recieve some data via TCP connection in JSON format and do some operations according form the decoded data.
I decode the received JSON inside the CLASS "PacketManager", using the library "Arduino Json". Then i pass the JSON object to the class "Bollard" for the execution of the commands (the code will follow). The strange thing is that on the "Bollard" Class in the method "CommandExecutor" I access to the data I passed and I can use them but at some point during the code of the same method that data go to 0.
Ofcourse i've checked that the the data is not overwriten in the method. The sketch does not have any interrupt or multythread. Seems like the variable get de-allocated form memory or the memory block get overwriten.
/// FRAGMENT OF CLASS PACKETMANAGER THAT RECEIVE THE JSON
void PacketManager::readPacket(){
resultRead reads=socket.readSocket(); //get data from soket
if(reads.mainCounter>0){ // if data
delay(150);
StaticJsonBuffer<200> jsonBuffer; //create a static json buffer form the library ArduinoJson.h
JsonObject& incomingFrame = jsonBuffer.parseObject((char*)reads.frame); //craete a JSON oblect
delay(150);
incomingFrame.printTo(Serial); // print the Incoming JSON
Serial.println();
if(incomingFrame.success()){ // check if JSON get decoded correclty
Serial.println("JSON DECODED SUCCESSFULLY");
unsigned int eventType=incomingFrame["eventType"];
unsigned int packetNumber=incomingFrame["packetNumber"];
if(eventType==ACK_STANDARD_MESSAGE){ // ACK standard case
if(this->checkACK(packetNumber)){ // CHECK If the incoming ACK found a corrispondence with the packet sended
#ifdef DEBUG_MODE
Serial.println("ACK RECEIVED");
#endif
bollard.commandExecute(incomingFrame); // if ack is in response of a sended command execute a command form the class bollard.
}
}
................ CODE CONTINUE. THE ERROR IS ON METHOD bollard.commandExecute(incomingFrame)
/////////////// FRAGMENT OF CLASS BOLLARD THAT USE THE JSON OBJECT
commandResult* BikeBollard::commandExecute(JsonObject& incomingFrame){
unsigned int* statusResponse= new unsigned int; // CREATE STATIC POINTER
unsigned int* eventType= new unsigned int;
unsigned int* commandType= new unsigned int;
unsigned int* packetNumber= new unsigned int;
// GET DATA FORM THE JSON OBJECT
unsigned int statusResponse_volatile=(unsigned int)incomingFrame["status"];
unsigned int eventType_volatile=(unsigned int)incomingFrame["eventType"];
unsigned int commandType_volatile=(unsigned int)incomingFrame["commandType"];
unsigned int packetNumber_volatile=(unsigned int)incomingFrame["packetNumber"];
// ASSIGN TO THE STATIC POINTED VALUE
*statusResponse=statusResponse_volatile;
*eventType=eventType_volatile;
*commandType=commandType_volatile;
*packetNumber=packetNumber_volatile;
commandResult* result;
Serial.print("STATUS OF THE RESPONSE ");Serial.println(*statusResponse); // correct value
Serial.print("EVENT TYPE ");Serial.println(*eventType); // correct value
Serial.print("COMMAND TYPE ");Serial.println(*commandType); // correct value
Serial.print("PACKET NUMBER ");Serial.println(*packetNumber); // correct value
///////////////////////////// FROM HERE SOMETIMES THE VALUES *commandType AND *eventType GO TO 0 WITHOUT A REASON ///////////////////////////
if(*eventType==ACK_STANDARD_MESSAGE){ // ACK vase
Serial.print("STATUS OF THE RESPONSE ");Serial.println(*statusResponse); // correct value
*eventType=*commandType;
Serial.print("STATUS OF THE RESPONSE ");Serial.println(*statusResponse); // correct value
result->ackPriority=false;
}
result->type=*eventType;
#ifdef DEBUG_MODE
Serial.print("BOLLARD: EXECUTE COMMAND "); Serial.println(*eventType);
#endif
switch(*eventType){ // wrong value pass form the correct value to 0 sometimes
case MSG_UP:
{
Serial.println("ACK MSG_UP Received");
result=this->executeMessageUp(*eventType, *packetNumber);
break;
}
case MSG_LATCH:
{
Serial.println("ACK MSG_LATCH Received");
this->executeMessageLatch(*eventType, *packetNumber);
break;
}
case MSG_UP_OK:
{
// DO SOMETHING
break;
}
case MSG_UP_ERROR:
{
// DO SOMETHING
break;
}
case MSG_PRESENT:
{
// DO SOMETHING
break;
}
case LOGIN_MESSAGE:
{
Serial.println("NOTICE: Logged IN");
this->loggedIn=true;
break;
}
case MSG_CARD:
{
Serial.println("ACK MSG_CARD Received");
if(*statusResponse==1){
Serial.println("DO EXECUTE MSG-UP");
result=this->executeMessageUp(*eventType, *packetNumber);
}
else {
//DO SOMETHING
}
break;
}
case MSG_BOLLARD_ACTIVATION:
{
Serial.print("STATUS OF THE RESPONSE ");Serial.println(*statusResponse); // 0 ERROR *statusResponse changed it's value.
if(*statusResponse==1) {
if(!this->isActive)checkBollardStatusWaitingTime=CHECK_BOLLARD_STATUS_TIME+1; // set bolard to active
this->isActive=true;
}
else{
if(this->isActive)checkBollardStatusWaitingTime=CHECK_BOLLARD_STATUS_TIME+1; // check againg the status
this->isActive=false;
}
break;
}
default:{
Serial.print("NOT CODED EVENT "); Serial.println(*eventType);
result->type=0;
#ifdef DEBUG_MODE
Serial.println("Default Message Expired");
#endif
break;
}
}
delete statusResponse;
delete eventType;
delete commandType;
delete packetNumber;
return result;
}
Hope someone can help.
Tx for your time.
Following the suggestion of TinyT i've declared commandResult* result as commandResult result = new commandResult; and changed the rest of code of consequence and ofc deleting it at the end to prevent a memory leak.
That was the variable that was creating the memory problems.
Tx TinyT
I am porting the openvr sample to jogl, after we created the binding with jna.
Almost at the end (before rendering the controllers and the tracking base stations), I got stuck trying to translate a char pointer in C to a String in Java.
C++ code here:
//-----------------------------------------------------------------------------
// Purpose: Helper to get a string from a tracked device property and turn it
// into a std::string
//-----------------------------------------------------------------------------
std::string GetTrackedDeviceString( vr::IVRSystem *pHmd, vr::TrackedDeviceIndex_t unDevice, vr::TrackedDeviceProperty prop, vr::TrackedPropertyError *peError = NULL )
{
uint32_t unRequiredBufferLen = pHmd->GetStringTrackedDeviceProperty( unDevice, prop, NULL, 0, peError );
if( unRequiredBufferLen == 0 )
return "";
char *pchBuffer = new char[ unRequiredBufferLen ];
unRequiredBufferLen = pHmd->GetStringTrackedDeviceProperty( unDevice, prop, pchBuffer, unRequiredBufferLen, peError );
std::string sResult = pchBuffer;
delete [] pchBuffer;
return sResult;
}
GetStringTrackedDeviceProperty here:
/** Returns a string property. If the device index is not valid or the property is not a string type this function will
* return 0. Otherwise it returns the length of the number of bytes necessary to hold this string including the trailing
* null. Strings will generally fit in buffers of k_unTrackingStringSize characters. */
virtual uint32_t GetStringTrackedDeviceProperty( vr::TrackedDeviceIndex_t unDeviceIndex, ETrackedDeviceProperty prop, VR_OUT_STRING() char *pchValue, uint32_t unBufferSize, ETrackedPropertyError *pError = 0L ) = 0;
Where VR_OUT_STRING() is defined here as:
# define VR_CLANG_ATTR(ATTR)
#define VR_OUT_STRING() VR_CLANG_ATTR( "out_string: ;" )
I have already done something similar where I had to call a function that expect the pointer to an array of TrackedDevicePose_t structures:
private TrackedDevicePose_t.ByReference trackedDevicePosesReference = new TrackedDevicePose_t.ByReference();
public TrackedDevicePose_t[] trackedDevicePose
= (TrackedDevicePose_t[]) trackedDevicePosesReference.toArray(VR.k_unMaxTrackedDeviceCount);
I created first the reference and then from it the actual array.
But here I can't have a class extending the char array..
private String getTrackedDeviceString(IVRSystem hmd, int device, int prop, IntBuffer propError) {
int requiredBufferLen = hmd.GetStringTrackedDeviceProperty.apply(device, prop, Pointer.NULL, 0, propError);
if(requiredBufferLen == 0) {
return "";
}
CharArray.ByReference charArrayReference = new CharArray.ByReference();
char[] cs = charArrayReference.toArray(requiredBufferLen);
return null;
}
Where apply (here) is:
public interface GetStringTrackedDeviceProperty_callback extends Callback {
int apply(int unDeviceIndex, int prop, Pointer pchValue, int unBufferSize, IntBuffer pError);
};
CharArray class, crap attempt here
Any ideas?
I've done some porting of C and C++ code to Java, and while it's probably horribly hacky, the best I've come up with to solve cases where a pointer to an int primitive or a char*/String is needed for a function call, is to create a small wrapper class with a single property, pass that object into the function, change the property as needed, and retrieve the new value after the function call. So something like:
public class StringPointer {
public String value = "";
}
StringPointer pchBuffer = new StringPointer();
unRequiredBufferLen = pHmd.GetStringTrackedDeviceProperty( unDevice, prop, pchBuffer, unRequiredBufferLen, peError );
String sResult = pchBuffer.value;
and inside GetStringTrackedDeviceProperty()
...
pchValue.value = "some string";
...
In this case, you can use a String, since that's what your code is doing with the char* after the function call, but if it actually really needs to be a char[], you can just create char[] pchBuffer = new char[unRequiredBufferLen]; and pass that into the function. It will be just like you were using a char* in C++, and any changes you make inside the array will be visible after the function ends, and you can even do String sResult = new String(pchBuffer);.
I have a class
class CCfgUserPage : public CPropertyPage
Which also owns various controls, from check boxes to text areas. I would like to add tooltips to each control, and seem to be having issues.
In CCfgUserPage I added this to the message map
ON_NOTIFY_EX(TTN_NEEDTEXT, 0, OnToolTipText )
Which when this object catches that message it calls the function OnToolTipText which looks like this
BOOL CCfgUserPage::OnToolTipText( UINT id, NMHDR * pNMHDR, LRESULT * pResult )
{
TOOLTIPTEXT *pTTT = (TOOLTIPTEXT *)pNMHDR;
UINT nID = pNMHDR->idFrom;
CString ttStr;
int partOrient = GetDlgItem(IDC_PARTORIENT_CHECK)->GetDlgCtrlID();
if (pTTT->uFlags & TTF_IDISHWND)
{
// idFrom is actually the HWND of the tool
nID = ::GetDlgCtrlID((HWND)nID);
if( nID == partOrient ) // Only Display TT for The buttons with these ID's
{
if( nID == partOrient )
ttStr = "Part Orient";
pTTT->lpszText = (LPTSTR)(LPCTSTR)ttStr;
pTTT->hinst = AfxGetResourceHandle();
return TRUE;
}
}
return FALSE;
}
I also enabled tool tips in
CCfgUserPage::OnInitDialog
Whenever OnToolTipText returns TRUE the application crashes and informs me of
Access violation reading location
I am trying to go through the stack frame but it is to far into MFC for me to understand what is going wrong. What might I be missing that would cause this to happen?
Have a look at the hint you have on MSDN:
When you handle the TTN_NEEDTEXT notification message, specify the
string to be displayed in one of the following ways:
Copy the text to the buffer specified by the szText member.
Copy the address of the buffer that contains the text to the lpszText member.
Copy the identifier of a string resource to the lpszText member, and copy the handle of the instance that contains the resource to the
hinst member.
So instead of doing:
CString ttStr;
// ...
if( nID == partOrient )
ttStr = "Part Orient";
// Below is the unsafe part: you initialize lpszText with something
// expected to be valid after you return from the handler
// effectively, this is internal buffer of local ttStr valriable
// which is to be freed and lpszText would keep point to undefined
// memory
pTTT->lpszText = (LPTSTR)(LPCTSTR)ttStr;
pTTT->hinst = AfxGetResourceHandle();
You would rather:
if(nID == partOrient)
{
// NOTE: Here instead you don't create any dynamic instances (strings)
// and the value resides directly in the notification structure
_tcsncpy_s(pTTT->szText, _T("Part Orient"), _TRUNCATE);
pTTT->lpszText = pTTT->szText; // Just a safety, it's already pointing there
}
The issue is that ttStr goes out of scope at the end of the function and you are returning a pointer to it. The pointer is now invalid and the app crashes when trying to reference it.
Use the supplied buffer if the tooltip will always be small (less than 80 characters) or use a member variable to store the tooltip text.