Jump to content

Neil Pate

Members
  • Posts

    1,156
  • Joined

  • Last visited

  • Days Won

    102

Posts posted by Neil Pate

  1. Smashing!

     

    That method does work, but it looks like the FP containing the control should not be open when this occurs, so it does not seem to be like clicking "Apply". Dunno, maybe I am still doing something wrong.

     

    Anyway, although this is a bit of a pain I think I can make this work now. 

     

    Thanks Shaun

     

    post-7375-0-22140300-1455555297.png

  2. Unless I'm misunderstanding something, the type def is doing just what it should and not updating unless the data type of the control changes.  If you are only replacing the pictures in a boolean, but not the actual data type, then an update won't be forced on the instances of the control.  Only a Strict Type Def will apply changes to all instances of the control, even if a cosmetic change is made.

     

    It is a strict typedef.

    You can go through the code, find all instances of the typedef and replace them with itself, this will actually bring them into sync.  I've done this in the past, just make sure to get the Typedef path and then replace the control with it's own typedef (from path).

    Something like this? Does not seem to work for me.

     

    I can get it to work if I open the typedef, change it from strict to plain, apply changes, change back to strict and re-apply changes. Then everything is in sync.

    post-7375-0-16577400-1455551775.png

  3. Hi,

     

    I have created some code to programatically replace the pictures in a boolean. I am applying my logic to a strict typedef and it works nicely. However my changes to this typedef do not seem to be propagated properly to a VI that uses the control.

     

    In my solution the front panel of the VI with the control is open, and I have a reference to the control I wish to modify. From there I get the typedef control, and then update it using the LabVIEW resource functions. After that I update call the Update Typedef method. In the project I sometimes get a message that the file has changed if I then try and open the .ctl, and if I allow that the new skinning is indeed working, however in the original FP the control still contains the existing pictures.

     

    In the typedef I cannot apply changes as this menu operation is disabled. I have tried mass compiling and it to does not seem to pick up the new changes.

     

    Any ideas what I am doing wrong?

    post-7375-0-40837800-1455549739.png

  4. Another neat option depending on the platform (ok everything except vxworks and pharlap) is to use a traditional web service (apache, etc) to host public content and proxy requests to a given url pattern (like /myLVApp/*) over to the LabVIEW web service. That way static http pages are served up in the normal way by a standard, generally pretty fast web server and anything you need to run code for can still be handled by your labview service.

    I kind of vaguely describe this over here: https://lavag.org/topic/19260-dynamic-content-in-other-web-servers/

    I'm sure Neil's way works well but if this option sounds interesting to you I can probably help out a bit or at least get you going in the right direction.

     

    I definitely do not recommend the way I demonstrated. It is a terrible developer experience and I only prototyped it to see if my hunch was correct...

     

    Your method sounds much better  :thumbup1:

  5. Hi Neil,

     

    google brought me here as I bumped to this feature, and I too expected being able to change the behavior just by updating the source HTML.

    I do know it is possible, but haven't found the way just yet.

    Did you find any good solution to what you were doing?

     

    I don't think it is possible to just change the source.

     

    However, as the .lvws is just an zip I was able to create a quick and dirty application (source and build attached) that can be run after any changes have been made to the source files and re-create the .lvws file. I ended up not using the LV web service to host the web pages, so did not use this application it in the end, but I believe it works but don't blame me if your PC bursts into flames.

    Web Service Resource Combiner.zip

  6. Happy new year everybody  :cool:

     

    Now, onto this year's first conundrum. I am trying to get some customer code running on my PC, and am getting a bit unstuck with some strangeness that I cannot explain.

     

    In particular this application reads and writes to files in a directory, lets call it ABCD that lives in  c:\Windows\System32\

    (As an aside, I am well aware this is not exactly a Windows "best practice" to put stuff in System32, but that is how it has been done in the application (which is quite old now), and that is what I have to live with given that I have inherited ownership of the project)

     

    The trouble is, on my Win 10 dev PC LabVIEW cannot even "see" that directory. If I try and open any files in it I get error 7 (File Not Found), and in fact when I browse to the System32 directory from within LabVIEW the ABCD directory is not even visible.

     

    Clearly this some Windows permission problem, but I cannot figure out how to work around it. I have messed about with all the permissions of that directory, and according to Windows my user should have full access to that directory. I have even tried starting LabVIEW as an Administrator but still no joy. Strangely, even from within Windows I can create a new text file in that directory but cannot save it.

     

    Any ideas what is going on?

     

    Edit: perhaps this has something to do with 32-bit/64-bit compatibility? If I open LabVIEW 64-bit I can see the directory if I browse there and the same LabVIEW code then is able to open and read the file contents just fine. I really did not know directories and files could have a "bitness" assigned to them...

  7. Hi All,

     

    I am trying to get a list of files out of a particular build script. I think I am mostly there, but stumbling at the last bit.

     

    Attached is my attempt so far. I can get the source tags for the build, but don't know what to convert the variant to. I know it is a reference of some type, but have tried a few things and none of them seem to work.

     

    Any tips?


    Nevermind, figured it out  :)

     

    The RefNum is type ProjectItem, converting the variant to this then allows the Path to be read

    post-7375-0-82471800-1450432521.png

  8. I still don't really get who you are trying to secure yourself against.

    This seems like a lot of work for very little real reason.

    I suppose in response to your OP, I am in the don't care category. All my systems that have some kind of network comms are on an intranet, and if somebody else on that network is trying to maliciously ruin my day it really is not my problem.

    Where I need to expose things to the Internet I would never use raw tcpip.

    In those circumstances I use Web Services with their built in security features.

  9. Years ago I did some embedded programming with pretty basic micros like the 8051, and they had a hardware stack that you would push to and pop from. Maybe this is where I am getting confused, I do not have any formal CS training so have just cobbled together knowledge over time.

  10. OK, having downloaded that example; the data posted is allocated on the stack, not on the heap. Major difference. That's why that particular example you cite has no memory leak.

     

    Jack, this may be obvious to you, but you say the data is posted on the stack (and not the heap). Is that because 

    interruptStruct_t interruptStruct;
    

    is declated as a local variable in the function and so automatically uses the stack?

     

    I thought the stack was physically a different "type" of memory, more like a L2 cache inside the CPU. A bit of googling tells me not that this is not the case.

     

    Computers are complicated...

  11. It's discussions like this that make me happy that I do not have to deal with these kinds of situations very often. Luckily for me most of these issues raised probably will not affect my project if I am careful (which I definitely will be!).

     

    Really good insight here, I am quite envious of the technical grokking that you fellows have on these quite arcane issues.

  12. Shaun, that is in line with the conclusions I reached from my research, so thanks for also confirming it.

     

    The code I am interfacing with is not going to change. However if it t does we will just have to rebuild my DLL.


    It's unavoidable, unfortunately.

     

    Consider this race condition --

     

    Let's say your wrapper library uses `PostLVUserEvent()` inside the function callback that the main library calls, in order to send the structure represented by `struct tyMessage` (let's ignore alignment and padding for now; do a little hand-wavy thing knowing it's a surmountable prob).

     

    What happens on the LabVIEW side? Let's say this goes into a Register For Events queue and is handled by an event structure. This means, the handling of the event is asynchronous from the callback from the main library.

     

    Feel free to pause the tape now and consider the problem here; press play once you think you have an answer ...

     

     

    .... that's right -- race condition, where if you lose the race, the kernel is very likely going to throw an Access Violation (if you're lucky) or you're going to be accessing valid, but undefined memory space.

     

    Because, my best guess at how the library works is this:

     

    ```

    two malloc's to represent the non-fixed width data in struct tyMessage

    invoke your callback, based on function pointer you had passed in Init()

    on return of function, perform two free's on those two buffers, having expected the callback to eagerly make its own copy, or otherwise perform all processing before not needing it anymore

    ```

     

    So the other option is to instead of using Register for Events, use a Register Event Callback instead. Inside, you could `MoveBlock()` into a preallocated LStrHandle, but this the least performant, least maintainable, least reliable, and most moving parts. That callback would then need to work as a Flaky Delegate in some manner to broker that information back to your application.

     

    The final option (my recommendation, considering information so far) is to create two LStrHandle's (or some other more sensical structure, based on whatever cType and cData actually represent) within your callback, use `PostLVUserEvent()` to get those back into LabVIEW, then destroy the handles, allowing your callback to return control to the main library.

     

    In precisely the same vein as our callback here making its own copies, whatever queueing mechanism within LabVIEW uses to put UHandles into an Event Queue, the LabVIEW Memory Manager ensures that a "copy" is made, such that the original entity calling `PostLVUserEvent()` is able to immediately deallocate all resources it just sent -- conceptually, at least, this maps to the mental model.

     

    `DSDisposeHandle()` is woefully lacking in documentation how/whether the Memory Manager reference counts the underlying buffer pointed to by a UPtr, but anecdotally this is how I observe it behaves. Said another way -- even though your callback is responsible for the initial allocation (ref count == 1), `PostLVUserEvent()` then allows the enqueuer to make another claim on that underlying buffer (ref count == 2), then your callback calling `DSDisposeHandle()` will atomically* decrease the count (ref count == 1) without the Memory Manager actually `free()`ing the buffer. Later, in the Event Structure, once that data has been accessed via the left-hand Event Data node and the frame finishes executing, the data goes out of scope, at which point ref count drops to 0 and an actual `free()` (or at least, a conceptual release of that resource) is done.

     

    Clear as mud?

     

     

    Jack, I have gone through some sample code where the two callbacks are implemented.

     

    In the Receive callback the function calls malloc/memcpy on the data it is passed in.

     

    My plan for my wrapper is to allocate some memory for LabVIEW to use, once in my Init function. Then I will copy the data structure into that memory and PostLVEvent using my copy.

  13. Thanks Rolf,

     

    This project is a one off. One PC, manually installed once, tested on the final hardware etc. So those software bugs would be found very early in the dev lifecycle and once fixed should never present themselves as a problem.

     

    Static linking it is  :beer_mug:

  14. OK experts C experts :-)

     

    My goal is to write my wrapper DLL with as least fuss as possible, as my C skills are not great.

     

    I have access to the .lib files, it seems to me that life would be easier if I statically linked the additional libraries as then I do not need to mess about with loadlibrary, GetProcAddress etc etc. Is this sensible?

     

    Note the code I am going to interface to is quite old, and in all liklihood is not going to change.

  15. Rolf, this is a going to stay a 32-bit application for its entire lifetime. There is exactly zero percent chance this will change. So if ShaunR's method works that sounds like the winner to me. I do this kind of DLL interface stuff rarely, so am always struggling to remember the details of pointers and buffers etc.

     

    I wan't to try and keep things as simple as possible, and having dealt with memory allocations in the DLL before I would like to try and avoid it if possible.

     

    All I need is the data back in LabVIEW via a PostLVUserEvent, I don't think the caller of the callback every expects anything meaningful in return.

     

    Now, I have not actually dug any deeper, I have some sample C code that shows the library in use (although here it uses a .lib rather than the DLL, but I expect the function handling to be the same). At some point I am going to need to go through this.

  16. Hi Jack,

     

    The library I am trying to integrate into my code is a "standard" TCP/IP based message protocol. The only function I need to call that requires the callbacks is the Init.

     

    The Init, which is called only once at the start, defines which two other functions are used in the event of a message being received and an error being detected.

    int Init(LinkType iLinkType, DataProcessingFunc pDataProcessFunc, ErrorProcessingFunc pErrorProcessFunc);
    
    

    As far as I can tell, almost all the other functions in the library are used for configuring the communications or sending data, and all of these are "normal" type calls with no fancy prototypes or crazy structs being passed around. The library itself is cross-platform (I know for a fact it can be compiled to run under Linux), I have access to a "normal" 32-bit Windows DLL (not assembly). I am not sure of the calling convention but I think 

     

    So my plan was just to wrap up the Init and implement a DataProcessingFunc and ErrorProcessFunc in my DLL, those last two would just pass data straight back to LabVIEW using PostLVEvent.

    int Send(tyLinkID iLinkID,tyMessage message);
    

    tyLinkID is just a plain integrer

    typedef struct 
    {
    	tyMessageType		nMsgType;			
    	DWORD					nAddress;			
    	BYTE					*cType;				/
    	WORD					nTypeLength;		
    	BYTE					*cData;				
    	WORD					nDataLength;		
    } 
       tyMessage;
    
    

    I plan on calling the Send function directly from my LabVIEW application.

     

    Any problems that you can see from a cursory glance?

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.