Call library with struct as parameter - several problems

Hi everyone,
I'm trying to send a MIDI sysex message to a midi device through winmm.dll using MidiOutLongMsg. I have trouble figuring out how to pass the parameters right.
I need to call three functions (midiOutPrepareHeader, midiOutLongMsg, midiOutUnprepareHeader), all of them having the same form
MMRESULT midiOutPrepareHeader(
HMIDIOUT hmo,
LPMIDIHDR lpMidiOutHdr,
UINT cbMidiOutHdr
where HMIDIOUT hmo is a handle that I have already. Troubling me are the other two parameters. cbMidiOutHdr is the size (in bytes) of the struct lpMidiOutHdr. This is a struct of the form
typedef struct {
LPSTR lpData;
DWORD dwBufferLength;
DWORD dwBytesRecorded;
DWORD_PTR dwUser;
DWORD dwFlags;
struct midihdr_tag far * lpNext;
DWORD_PTR reserved;
DWORD dwOffset;
DWORD_PTR dwReserved[4];
} MIDIHDR;
(Struct: http://msdn2.microsoft.com/en-us/library/ms711592.aspx
PrepareHeader http://msdn2.microsoft.com/en-us/library/ms711634.aspx
SendMessage http://msdn2.microsoft.com/en-us/library/ms711629.aspx
UnprepareHeader http://msdn2.microsoft.com/en-us/library/ms711641.aspx)
[Note: The full code for what I want to do can be found here http://www.borg.com/~jglatt/tech/lowmidi.htm (section "outputting system exclusive MIDI messages) - basically I need a translation of this code to LabView.]
The following are my problems:
a) How do I emulate a struct in LabView? (other threads suggest that this is done by clusters)
b) How do I pass a pointer to a struct (cluster?) to a DLL?
c) If I can use a cluster for this struct, how do I represent the LPSTR lpData in the cluster, i.e., a pointer to my data?
d) how do I get the struct size for cbMidiOutHdr?
This is how far I got, lots of it with the help of several threads in this forum:
a) use a LabView cluster
b) use "adapt to type" in the dll call (couldn't get this to work)
c) I use a type cast on my string in the hope that what it returns is the register address (and I'm probably superwrong here)
d) my cluster consists of 9 elements of 4 byte datatypes, so I just use 36 for cbMidiOutHdr
The dll seems to be happy with the way I pass the cluster - I get error codes of 0 in both the PrepareHeader and UnprepareHeader functions. However, sending doesn't work (error code 7). Guessing that the type cast returns a pointer, I have also cast the cluster to an Int32 and passed that parameter as pointer to numeric value. Interestingly, the PrepareHeader and UnprepareHeader functions are still happy, but I get a different error code from the sending (code 11)
Most of what I've done so far is guesswork, and I'm out of guesses now. I've attached the code to this post (it uses VIs from the NI MIDI example library ftp://ftp.ni.com/pub/devzone/epd/midi-example.llb ). I'd appreciate any help with this. Thanks!
Attachments:
Write MIDI SysEx Message.vi ‏21 KB

First off, this problem doesn't have anything to do with control references; those have meaning only inside of the LabView environment.
My first suggestion is to look for a higher-level library that will do whatever MIDI function you are trying to call. If you can find an ActiveX or .NET object that will control the MIDI subsystem, I recommend that you use it instead since it will be a lot easier.
If calling the DLL directly is the best option (and calling DLLs is absolutely the way to go when you need high performance) then you need to understand how LabView passes data to library functions. That is described here:
http://zone.ni.com/reference/en-XX/help/371361D-01/lvexcodeconcepts/configuring_the_clf_node/
As you can see there are a lot of ways to pass data, but they boil down to this: LabView can pass, via various levels of dereferencing, a pointer to some [mostly] flat data. Things are easiest when your DLL mimics LabView's own data storage methods. For example, wiring a cluster into a node set with Adapt to Type passes a handle (struct**, pointer to pointer to [mostly] flat data). So if you are writing your own DLL, it's pretty easy to write something that works nicely with LabView data (e.g., strings with 4-byte length headers, self-describing arrays) and in fact the result is cleaner looking than its "pure C" variant because of the self-describing arrays and string length prefixes. (I say "mostly" flat because LabView clusters with variable-length elements aren't stored in a flat format.)
When it comes to matching someone else's API things get harder, and in this case you are out of luck; you are going to have to write a LabView-callable wrapper function in C because LabView can't mimic the exact data structure needed. The problem is not the struct; there is a sneaky way to pass a pointer (vs a handle) to a struct, which is to do this:
Generate a cluster in LabView representing the struct (atomic numeric data only! no strings arrays etc!)
Flatten to string using native byte order.
Convert string to byte array.
Configure the call library function note to accept a pointer to an unsigned byte array. (NOT a C-string as suggested at the bottom of the page in the link above; your data may have internal 0x00s, and it certainly doesn't need an extra 0x00 at the end!)
The reason this works is that a pointer is just an address; as long as all the right bytes are in memory in the right order starting at that address, all is well. The DLL doesn't know that LabView thinks it is passing a pointer to an array of bytes, it just gets the pointer to the first byte and it reads and interprets those bytes according to its own struct def. Reverse the process cooming back from the DLL (convert byte array to string, unflatten from string against the LV cluster.) This method will work for any flat struct.
In LabView 8.5 there may be a less bogus way of doing this, which is to pass the cluster in with Adapt to Type and select "Array Data Pointer" as the format. This is new and I haven't tried it.
But in your case, you want to point to a struct that contains a pointer to a string plus some numeric data and another pointer, and this you can't do directly. LabView does not expose the location of a string to you anywhere outside the Call Library Function node, so there's no way to "find the pointer" to a LabView string from outside the DLL. What you need to do in this case is write a wrapper function in C that takes your LabView data. Only then will LabView "tell you where the bytes are" and promise not to fiddle with them until the library call is complete. Once you are in C-land, you can throw pointers around to your heart's content. As long as you do it all perfectly, all will be well. (If you write one byte too many on output, boom! :-)
There are a few ways to do this. You could make a cluster that has meaning in LabView, e.g. replace lpData with a LabView string, then pass the cluster in to your wrapper function set to "Adapt to Type"; that will pass a handle to the cluster. You can generate the .c file from the Call Lib Fuction, and it will outline where the data is.
Complications: In this case it's your job to convert the handle to the labview string (which has 4 bytes of length as a prefix and no trailing 0x00) to a C-string by malloc()'ing a new buffer and memcopying the string out. There might be something in the LV CIN tools that does this, I'm not sure. Make sure you release the new string after the MIDI call.
The lazy route (which is what I would do) is pass the string as the first arg and all of the numeric stuff as the second arg, leaving the space for lpData as you have now. (I don't know what struct "midihdr_tag" is, but if that's not something you were passed in a previous call, you'll need to add a third argument for that cluster and treat it similarly.) Then you can tell LabView that it should pass the string arg as a C-string pointer. Inside your wrapper, extract the pointers and stuff them into the data structure as needed. Dereference once (to go from handle to pointer) and make the MIDI call. To be clean, put everything back where it was before in the cluster; in particular don't believe you can pass out lpData* and do whatever you want with it in LabView; LabView will release/change that address as soon as you leave the output string unwired or do anything to it (e.g. concatenate.) You'll be creating a new string buffer and a new pointer on your next MIDI call.
All of this complication is a result of a) LabView's hiding the details of memory allocation/deallocation from you and b) LabView's internal data structures being a bit different from C conventions (e.g. LabView strings vs. C strings). The second means that even when LabView is using non-flat data structures (e.g. cluster containing an array), you can't just blindly pass them along to a C function and expect it to work right. It would be nice if NI would write a little mini-compiler into the Call Library Function that would do what our wrapper function is going to do, but that's probably a fairly significant project. 
Still, each function wrapper is only going to have about 10 lines of C. You can put wrappers for all the MIDI functions you want to call into a single DLL, then ship that DLL with your app.
(Now you see why I suggested you look for an ActiveX MIDI control!)
-Rob Calhoun

Similar Messages

  • Call DLL with byte** input parameter type

    Hi All,
    Have anyone knows how to get output parameter from a Call Library Fuction with having the input prameter type is BYTE**. Please see the code below :
    void getMsgBuffFromQueue(BYTE**& p_msgBuff)
    if(m_QueueBuffMsg.GetSize() > 0)
    p_msgBuff = m_QueueBuffMsgForEqp.DeQueue();
    return ;
    I did the test this fuction of the DLL on VC++ 6 with successful. but when I tranfer it to LabView, I cannot get the parameter output data after call this fuction., I donn't know to use which control to get approriate data return.
    I define the function call on Labview like that:
    void getMsgBuffFromQueueForEqp(Array1DLong **msgBuff);
    Is it correct ? If anyone have the solutions, please give me your solution.
    Thanks in advance.

    The problem is that Array1DLong is not a C++ array, but a structure definition for a LV array. If you generate the c code from the Call Library Node, you'll notice the structure that contains the array size as part of it. In addition, there are a lot of rules about how memory should be allocated for the array elements - it is all covered in the "Using External Code in LabVIEW" manual.
    I'll also point out that your definition does not match the code. A BYTE**& is actually a BYTE*** - the C++ concept of a reference is really a pointer under the covers - it is just that the C++ language provides special support for it. However, for anyone calling the method from the outside, it needs to know that it is really a pointer. Also, if I remember correctly, you can't expose a C++ method with a reference in the definition with an extern "C" statement, which is what you probably want to do in order to easily hook it up to LV...otherwise you'll have to deal with the C++ name-mangled version.
    There are two ways I would recommend going here.
    1. Don't use a Call Library Node but a CIN instead. The manual will walk you through the work necessary to marshall the two different data types in and out of LV.
    2. Return the buffer to LV as a void*. In this case what are you saying to LV is "here is a handle I want you to hold onto...just give it back to me when I need it". Then you create some additional C functions that take the void* and do the data manipulation with it.
    Which one you pick depends a lot of what you want. If you want to manipulate the data within LV with LV constructs, you need to go with #1. If you just need to pass the buffer to another C function, then #2 is the way to go.
    Did that make any sense?
    Brian Tyler
    http://detritus.blogs.com/lycangeek

  • Call library node in builded exe - path problem

    Hi!
    I have builded an EXE with the App. Builder. In my application I use the Call Library Node, and call functions from a DLL.
    I give the path of the dll with the "Current VI path", than strip the path, and add the DLL-s name. So in the CallLibNode I check the "specify path on diagram" option.
    It works when I run my application on a PC that has the LV 8.5 installed.
    But when I install my app on a PC that does not have it, just my setup installs the Runtime Engine onto it, it does not work, and I get errors.
    Which is the proper way to give the DLL-s path, if I want my app run on any PC that does not have LV installed?
    Thanks:
    Waszil

    Does the executable run correctly on the development machine? If not I would imagine it is a problem with how you are referencing the dll.
    Have you installed all necessary support libraries you may be using throughout the program on the target machine? Are you able to confirm that the error messages are referencing to the dll not being found?
    It sounds like you are referencing the dll correctly. When compiled, the dll is put into the 'data' directory within the root directory, so make sure that is there on the target pc
    Message Edited by yenknip on 08-04-2008 10:42 AM
    - Cheers, Ed

  • Call dll with 1D array parameter

    Hi, I am trying to interface a Keyence laser displacement sensor controller with labview. Keyence has a dll API and I wrote a wrapper in C with DEV-C++. The wrapper is compiled into another DLL so I can call in my application. (Keyence DLL cannot be called directly for some reason)
    These are tested in Matlab and worked well. The problem is when I try to use the "Call Library Function Node " in Labview, it always report me errors. The C code is pasted as below. The arrays are 1-D and not been resized in the function call.
    Any input is highly appreciated.
    Bo 
     DLLIMPORT int AcqData(float *DataA, float *DataB)
      typedef int (_stdcall *DataStorageStartPtr) (void);
      typedef int (_stdcall *DataStorageStopPtr) (void);
      typedef int (_stdcall *DataStorageInitPtr) (void);
      typedef int (_stdcall *DataStorageGetDataPtr) (int OutNo,int NumOutBuffer, LKIF_FLOATVALUE *OutBuffer, int *NumReceived);
      typedef int (_stdcall *DataStorageGetStatusPtr) (int OutNo, int *IsStorage, int *NumStorageData);
      DataStorageStartPtr DataStorageStart;
      DataStorageStopPtr DataStorageStop;
      DataStorageInitPtr DataStorageInit;
      DataStorageGetDataPtr DataStorageGetData;
      DataStorageGetStatusPtr DataStorageGetStatus;
      HINSTANCE hLib;
      int feedback;
      int OutNo;
      int NumOutBuffer = MAX_NUM_DATA;
      int IsStorageA, IsStorageB;
      int NumStorageData;
      int NumReceivedA, NumReceivedB;
      LKIF_FLOATVALUE OutBufferA[NumOutBuffer];
      LKIF_FLOATVALUE OutBufferB[NumOutBuffer];
      //---------------- Import the DLL --------------------//
      hLib = LoadLibrary("LkIF.dll");
      if(!hLib)
       return -1;
      //---------------- Get the addresses of functions ---------------//
      DataStorageStart = (DataStorageStartPtr)GetProcAddress(hLib, "LKIF_DataStorageStart");
      if(DataStorageStart == NULL)
       return -2;
      DataStorageStop = (DataStorageStopPtr)GetProcAddress(hLib, "LKIF_DataStorageStop");
      if(DataStorageStop == NULL)
       return -3;
      DataStorageInit = (DataStorageInitPtr)GetProcAddress(hLib, "LKIF_DataStorageInit");
      if(DataStorageInit == NULL)
       return -4;
      DataStorageGetData = (DataStorageGetDataPtr)GetProcAddress(hLib, "LKIF_DataStorageGetData");
      if(DataStorageGetData == NULL)
       return -5;
      DataStorageGetStatus = (DataStorageGetStatusPtr)GetProcAddress(hLib, "LKIF_DataStorageGetStatus");
      if(DataStorageGetStatus == NULL)
       return -6;
      //---------------------------- Data Acqusition --------------------------//
      feedback = (DataStorageInit)();
      if(!feedback)
        return -7;
      feedback = (DataStorageStart)();
      if(!feedback)
        return -8;
      sleep(10000);
      sleep(500);
      OutNo = 0;
      feedback = (DataStorageGetStatus)(OutNo, &IsStorageA, &NumStorageData);
      if(!feedback)
       return -9;
      OutNo = 1;
      feedback = (DataStorageGetStatus)(OutNo, &IsStorageB, &NumStorageData);
      if(!feedback)
       return -10;
      while(IsStorageA || IsStorageB)
       sleep(500);
       OutNo = 0;
       feedback = (DataStorageGetStatus)(OutNo, &IsStorageA, &NumStorageData);
       if(!feedback)
        return -9;
       OutNo = 1;
       feedback = (DataStorageGetStatus)(OutNo, &IsStorageB, &NumStorageData);
       if(!feedback)
        return -10;
      feedback = (DataStorageStop)();
      if(!feedback)
       return -11;
      OutNo = 0;
      feedback = (DataStorageGetData)(OutNo,NumOutBuffer,&OutBufferA[0],&NumReceivedA);
      if(!feedback)
       return -12;
      OutNo = 1;
      feedback = (DataStorageGetData)(OutNo,NumOutBuffer,&OutBufferB[0],&NumReceivedB);
      if(!feedback)
       return -13;
      int i;
      for(i = 0; i < NumReceivedA; i++)
        DataA[i] = OutBufferA[i].Value;
      for(i = 0; i < NumReceivedB; i++)
        DataB[i] = OutBufferB[i].Value;
      return 0;
    Attachments:
    program.JPG ‏49 KB
    error.JPG ‏15 KB

    I notice you have corrections dot on the input side. Check the type used then building the array at the input side. Then you build a array on the input side, you do this to reserve memory for the dll. If you have not reserved the correct amount of memory before you call the function an erreor or a crash might happend. A float in C is 4 byte wide, equal to SGL in labview. A double is 8 byte wide, equal to DBL
    Besides which, my opinion is that Express VIs Carthage must be destroyed deleted
    (Sorry no Labview "brag list" so far)

  • Probel with call library function: I have a dll based on a complicated struct data type. How can I pass this structure?

    The data type is
    typedef enum {false, true} bool;
    typedef float flt4;
    typedef double flt8;
    typedef int i32s;
    typedef unsigned int i32u;
    typedef short int i16s;
    typedef unsigned short i16u;
    typedef signed char i08s;
    typedef unsigned char i08u;
    struct t_UnwrapData {
    struct {
    i08u flags;
    i16u unwrap_m;
    i08u weight_m;
    } status;
    flt4 *ph2pi;
    flt4 *weight;
    flt4 *gamma;
    flt4 *phase;
    i08u *flags;
    i08u *neigh;
    i32s neighOfst[8];
    i32s r,c;
    i32s x0,y0,xSz,ySz;
    flt8 unwTime;
    flt4 binCut;
    Please Could someone help me suggesting how I pass this dat
    a type to call library function?

    Hi Setu,
    Here is a solution that I have been playing to return back an array of clusters
    typedef struct
    int32 dimSize;
    uInt8 array[1];
    } LVU8;
    typedef LVU8 **LVU8Hdl;
    typedef struct
    U32 DeviceId;
    U32 VendorId;
    U32 BusNumber;
    U32 SlotNumber;
    LVU8Hdl SerialNumber;
    } LVDEVICE_LOCATION;
    typedef LVDEVICE_LOCATION **LVDEV_LOC_HANDLE;
    typedef struct
    int32 dimSize;
    LVDEVICE_LOCATION cluster_array[1];
    } LVDEV_LOC_ARRAY;
    typedef LVDEV_LOC_ARRAY **LVDEV_LOC_ARRAY_HANDLE;
    LVPLX_API void GetAllDevices(LVDEV_LOC_ARRAY_HANDLE cluster_array)
    int i,j;
    int numDevices = 3;
    DSSetHandleSize(cluster_array, sizeof(int32)+3*(sizeof(LVDEV_LOC_ARRAY)+(sizeof(int32)+16*sizeof(L
    VU8))));
    (*cluster_array)->dimSize = 3;
    (*((*cluster_array)->cluster_array[0]).SerialNumber)->dimSize =16;
    (*((*cluster_array)->cluster_array[1]).SerialNumber)->dimSize =16;
    (*((*cluster_array)->cluster_array[2]).SerialNumber)->dimSize =16;
    for(i=0; i<3; i++)
    ((*cluster_array)->cluster_array[i]).BusNumber = i;
    ((*cluster_array)->cluster_array[i]).VendorId = i*5;
    for(j=0;j<16;j++)
    (*((*cluster_array)->cluster_array[i]).SerialNumber)->array[j] = (10*j)+i;
    The code doesnt do much but returns back 3*cluster which the array in my cluster is sized for 16. The problem I've been having , was ensuring I have allocated enough memory to handle the complete structure. This works for me, now all I have to do is put the real code in which get my array of data from the instruments.
    Hope it helps
    Regards
    Ray Farmer
    Regards
    Ray Farmer

  • Problem with Call Library Function. Want to pass a string and return a string, but my compiler does not recognize "CStr" and Labview does not recognize my "char *function()" callout

    Hi, I'm trying to use a .DLL I wrote in Visual C++ .NET. The Call Library Function generates a function prototype of "CStr Parser(CStr arg_raw)"
    but my compiler won't accept this. So I change it to how C normally deals with strings "char *Parser(char *arg_raw). Now the Call Librafy Function does not find "Parser" in my .DLL though it is definitely there!
    Help!
    -Fong

    Hello
    You will need to include extcode.h in your C file. You can find this under ..\LabVIEW\cintools folder.
    The include has all the defines you will need.
    Bilal Durrani
    NI
    Bilal Durrani
    NI

  • Call library node - using a structure with dll

    Hi folks.
    I was hoping to recieve some help or advice on solving this problem I am having in labview:
    Some background info - I am trying to use the 'call library node' to allow me to use a .dll to allow for control of a remote power supply over RS-232.
    I have been doing fine up till now, however I am now trying to use the following:
    int TC4GetFnBlockSettings(struct T_FnBlock *p_fnblock, unsigned int type)
    int TC4SetFnBlockSettings(struct T_FnBlock *p_fnblock, unsigned int type)
    where
    struct T_FnBlock
    unsigned int BaseFunction;
    double Amplitude;
    double Offset;
    double Symmetry;
    double Frequency;
    int BipolarAmplitude;
    int RectifyAmplitude;
    double ExpTimeConstant;
    unsigned int NumPeriods;
    unsigned int UserDefAmplitude;
    unsigned int UserDefTimePrescaler;
    double UserDefPeriodLength;
    unsigned int UserDefNumPoints;
    unsigned int InactiveLevelType;
    double InactiveLevel;
    unsigned int AAPInputType;
    unsigned int AAPInputFilterKoeff;
    unsigned int AAPFlags;
    double AAPInputScaling;};  
    Obviously there is no such thing as a structure in Labview; I had hoped to use a cluster in it's place however the CLN does not allow for input or output of a cluster.
    Any help would be appreciated!
    Thanks
    Solved!
    Go to Solution.

    Akiel wrote:
    unfortunalty the call library node doesnt map labview types to c types very well. It can be done but took me a lot of time and effort (and overworking google) to manage it. In the end i abandoned the cln and write a c# code that interfaces between my dll and labview. 
    sorry cant be of much more help.
    I think NI need to improve this functionality as the CLN could be useful but hard to get working on anything beyond a simple dll interface
    That is not true!
    The Call Library Node does a tremendous job in providing configuration options to map LabVIEW data to most C datatypes. In most cases the two match directly except when arrays and strings are concerned. Those two are very different in LabVIEW than in C but the Call Library Node allows to configure parameters to map LabVIEW strings and arrays to according C string and array pointers.
    A structure in C is directly equivalent to a LabVIEW cluster unless it contains strings or arrays. Also there is the potential of structure element alignment which you have to take care of explicitedly but that is hardly the fault of LabVIEW but rather a direct consequence of the rather low level character of the C language.
    Since the OPs C struct only contains scalar datatypes you can directly create a LabVIEW cluster with the same elements and the same order of elements and pass that cluster to the Call Library Node parameter configured as Adapt to Type.
    The reason that you might have to get google overworked for such things is not because LabVIEWs support for interfacing to C code is bad, but because interfacing to C code is such a complex topic in itself. Without a lot of low level knowledge about what a C compiler really does when creating functions you are bound to do a lot of trial and error and googling. You get the same issue when trying to interface unmanaged code in C# (.Net).
    Rolf Kalbermatter
    CIT Engineering Netherlands
    a division of Test & Measurement Solutions

  • Call a Borland Delphi DLL with Structs from LabView

    Hello,
    I have a problem to build an equivalent Struct in Labview to the following Struct which I want to retrieve from a DLL.
    type
    TM2DScanline=record
    YWert:double;
    XWert:array[0..raster] of double;
    ZWert:array[0..raster] of double;
    IWert:array[0..raster] of byte;
    end;
    M2DScanArea =array[0..maxScans] of TM2DScanline;
    PointerToScanArea=^M2DScanArea;
    PointerToScanArea is the parameter I want to retrieve.
    If anybody knows a way for doing this, help would be very appreciated
    Thanks
    Peter

    Are raster and maxScans both constant? If I recall correctly, many dialects of Pascal just lay the elements of a fixed-size array out in memory with no size parameter; if this is the case with Delphi, then you may be able to do the following (in my example, I'll assume "raster" is a constant set to 40, and maxScans is a constant set to 5):
    Create a cluster called XWert with 40 Numeric elements (representation: DBL).
    Copy XWert and name the copy ZWert.
    Create a cluster called IWert with 40 Numeric elements (representation: U8).
    Create a cluster called TM2DScanline.
    Create a Numeric inside TM2DScanline called YWert (representation: DBL).
    Drag XWert, then ZWert, then IWert into TMD2Scanline.
    Create a cluster called ScanArea and drag 5 copies of TMD2Scanline into it.
    Create a Call Library node on your block diagram, give it your DLL and function name, and set the return value to whatever your Delphi function returns. You probably want the WINAPI calling convention.
    Add a parameter and make it "Adapt to Type: Pointers to Handles". Close the node and wire the ScanArea cluster to the input.
    Right-click on the Call Library Node and select "Create .c file...." Read through the C file to make sure its structure is similar to your Delphi record: you should see five copies of the TM2DScanline structure, each of which contains a double followed by two fixed 40-element structures of double and a fixed 40-element structure of unsigned char. You should see no reference to the word "Hdl" anywhere in the code.
    This strategy will only work if the arrays in your records are fixed at a constant size, and if Delphi lays out the arrays in memory as described above. Instead of doing all this work, you may want to write a small C or Pascal wrapper around your Delphi function. This wrapper could take simpler parameter types (which are easier to use from LabVIEW) and bundle them into the cluster before calling your Delphi function.

  • Calling external C-functions in DLLs with struct as parameters

    Hi all PL/SQL Gurus !
    Is it possible to call external functions in a DLL written in C
    wich has pointers to C-structs as parameter. Can you point me to
    an example or extended documentation about this. I had a look at
    the Oracle doc's but found no examples about structs.
    Thank you very much,
    Stefan.
    P.S.: Konfiguration: Oracle 8.1.7.0.0 Client and Server on W2K-
    SP2 machines.

    Hi,
    I have the same problem with you.Now,have you resolve the problem?
    I want to know how to do.if you resolve it ,could you give me a example.
    thanks .
    best regards!
    Liyf

  • Call library function node with array of clusters using array data pointer

    Hello all.
    I am writing a LabVIEW wrapper for an existing DLL function.
    The function has, as one of its parameters, an array of structs.  The struct is very simple, containing two integers.  I am using the call library function node to access it.
    In Labview I created an array of clusters, where the cluster has two 32-bit integers as its members.  So far, so good.
    Now I have to pass this in to the Call Library Function Node.  Here I am running into trouble.
    I have used The topic in LAVA and The topic in the knowledge base as my primary sources of information, though I have read a bunch of forum topics on the subject too.
    I do understand that I could write a new function which takes as a parameter a struct with the size as the first member and an array as the second, and I might just do this and have it call the regular function, but I was hoping to do it more simply.
    According to the C file which LabVIEW generates for me from the CLFN when I choose "Adapt to Type" and "Array Data Pointer", the prototype it is expecting is:
    int32_t myFunc(uint32_t handle, uint16_t channel,
    int32_t FIFOnumber, void data[], int32_t numWords, int32_t *actualLoaded,
    int32_t *actualStartIndex);
    And the prototype of the function in my DLL is
    int borland_dll myFunc(DWORD handle, usint channel,
    int FIFOnumber, struct mStruct *data, int numWords, int *actualLoaded, int *actualStartIndex);
    This looks like a match to me, but it doesn't work (I get garbage in data).  From the topic in LAVA referenced above, I understood that it would work.  It does not.
    If I cast data to the pointer-to-pointer I get when I generate c code by wiring my struct to a CIN and generating, then I seem to get what I expect. But this seems to work when I choose "pointers to handles" too, and I would expect array data pointer to give a different result.
    Is there any way to get this to work directly, or will I have to create a wrapper?  (I am currently using LabVIEW 2011, but we have customers using 2009 and 2012, if not other versions as well).
    Thank you.
    Batya
    Solved!
    Go to Solution.

    OK, here is more detailed information.
    I have attached the VI.
    This is the code from the  "C" file created by right-clicking the CLN and creating a "C" file. 
    When the parameter in the CLN is set to "array data pointer":
    /* Call Library source file */
    #include "extcode.h"
    int32_t Load_Transmit_FIFO_RTx(uint32_t handle, uint16_t channel,
    int32_t FIFOnumber, void data[], int32_t numWords, int32_t *actualLoaded,
    int32_t *actualStartIndex);
    int32_t Load_Transmit_FIFO_RTx(uint32_t handle, uint16_t channel,
    int32_t FIFOnumber, void data[], int32_t numWords, int32_t *actualLoaded,
    int32_t *actualStartIndex)
    /* Insert code here */
     When the parameter is "pointers to handles":
    /* Call Library source file */
    #include "extcode.h"
    /* lv_prolog.h and lv_epilog.h set up the correct alignment for LabVIEW data. */
    #include "lv_prolog.h"
    /* Typedefs */
    typedef struct {
    int32_t control;
    int32_t data;
    } TD2;
    typedef struct {
    int32_t dimSize;
    TD2 data[1];
    } TD1;
    typedef TD1 **TD1Hdl;
    #include "lv_epilog.h"
    int32_t Load_Transmit_FIFO_RTx(uint32_t handle, uint16_t channel,
    int32_t FIFOnumber, TD1Hdl *data, int32_t numWords, int32_t *actualLoaded,
    int32_t *actualStartIndex);
    int32_t Load_Transmit_FIFO_RTx(uint32_t handle, uint16_t channel,
    int32_t FIFOnumber, TD1Hdl *data, int32_t numWords, int32_t *actualLoaded,
    int32_t *actualStartIndex)
    /* Insert code here */
     When the parameter is set to "handles by value":
    /* Call Library source file */
    #include "extcode.h"
    /* lv_prolog.h and lv_epilog.h set up the correct alignment for LabVIEW data. */
    #include "lv_prolog.h"
    /* Typedefs */
    typedef struct {
    int32_t control;
    int32_t data;
    } TD2;
    typedef struct {
    int32_t dimSize;
    TD2 data[1];
    } TD1;
    typedef TD1 **TD1Hdl;
    #include "lv_epilog.h"
    int32_t Load_Transmit_FIFO_RTx(uint32_t handle, uint16_t channel,
    int32_t FIFOnumber, TD1Hdl *data, int32_t numWords, int32_t *actualLoaded,
    int32_t *actualStartIndex);
    int32_t Load_Transmit_FIFO_RTx(uint32_t handle, uint16_t channel,
    int32_t FIFOnumber, TD1Hdl *data, int32_t numWords, int32_t *actualLoaded,
    int32_t *actualStartIndex)
    /* Insert code here */
    As to the DLL function, it is a bit more complicated than I explained above, in the current case.  My VI calls the function by this name in one DLL, and that DLL loads a DLL and calls a function (with the same name) in the second DLL, which does the work. (Thanks Rolfk, for helping me with that one some time back!)
    Here is the code in the first ("dispatcher") DLL:
    int borland_dll Load_Transmit_FIFO_RTx(DWORD handle, usint channel, int FIFOnumber, struct FIFO_DATA_CONTROL *data, int numWords, int *actualLoaded, int *actualStartIndex)
    t_DispatchTable *pDispatchTable = (t_DispatchTable *) handle;
    int retStat = 0;
    retStat = mCheckDispatchTable(pDispatchTable);
    if (retStat < 0)
    return retStat;
    if (pDispatchTable->pLoad_Transmit_FIFO_RTx == NULL)
    return edispatchercantfindfunction;
    return pDispatchTable->pLoad_Transmit_FIFO_RTx(pDispatchT​able->handlertx, channel, FIFOnumber, data, numWords, actualLoaded, actualStartIndex);
    borland_dll is just "__declspec(dllexport)"
    The current code in the DLL that does the work is:
    // TEMP
    typedef struct {
    int control;
    int data;
    } TD2;
    typedef struct {
    int dimSize;
    TD2 data[1];
    } TD1;
    typedef TD1 **TD1Hdl;
    // END TEMP
    int borland_dll Load_Transmit_FIFO_RTx(int handlertx, usint channel, int FIFOnumber, struct FIFO_DATA_CONTROL *data, int numWords, int *actualLoaded, int *actualStartIndex){
    struct TRANSMIT_FIFO *ptxFIFO; //pointer to transmit FIFO structure
    usint *pFIFOlist; //pointer to array of FIFO pointers to FIFO structures
    int FIFOentry, numLoaded;
    usint *lclData;
    usint nextEntryToTransmit;
    // TEMP
    FILE *pFile;
    int i;
    TD1** ppTD = (TD1**) data;
    TD1 *pTD = *ppTD;
    pFile = fopen("LoadFIFOLog.txt", "w");
    fprintf(pFile, "Starting Load FIFO with %d data words, data pointer 0x%x, with the following data&colon; \n", numWords, data);
    for (i = 0; i < numWords; i++) {
    fprintf(pFile, "%d: control--0x%x, data--0x%x \n", i, data[i].control, data[i].data);
    fflush(pFile);
    fprintf(pFile, "OK, using CIN generated structures: dimSize %d, with the following data&colon; \n", pTD->dimSize);
    for (i = 0; i < numWords; i++) {
    fprintf(pFile, "%d: control--0x%x, data--0x%x \n", i, pTD->data[i].control, pTD->data[i].data);
    fflush(pFile);
    // END TEMP
    if ((handlertx) <0 || (handlertx >= NUMCARDS)) return ebadhandle;
    if (cardrtx[handlertx].allocated != 1) return ebadhandle;
    pFIFOlist = (usint *) (cardrtx[handlertx].segaddr + cardrtx[handlertx].glob->dpchn[channel].tr_stk_ptr​);
    pFIFOlist += FIFOnumber;
    ptxFIFO = (struct TRANSMIT_FIFO *)(cardrtx[handlertx].segaddr + *pFIFOlist);
    //use local copy of ptxFIFO->nextEntryToTransmit to simplify algorithm
    nextEntryToTransmit = ptxFIFO->nextEntryToTransmit;
    //on entering this routine nextEntryToLoad is set to the entry following the last entry loaded
    //this is what we need to load now unless it's at the end of the FIFO in which case we need to wrap around
    if ( ptxFIFO->nextEntryToLoad >= ptxFIFO->numEntries)
    *actualStartIndex = 0;
    else
    *actualStartIndex = ptxFIFO->nextEntryToLoad;
    //if nextEntryToLoad points to the last entry in the FIFO and nextEntryToTransmit points to the first, the FIFO is full
    //also if nextEntryToLoad == nextEntryToTransmit the FIFO is full and we exit without loading anything
    if (( (( ptxFIFO->nextEntryToLoad >= ptxFIFO->numEntries) && (nextEntryToTransmit == 0)) ||
    ( ptxFIFO->nextEntryToLoad == nextEntryToTransmit)) && (ptxFIFO->nextEntryToLoad != INITIAL_ENTRY)){
    *actualLoaded = 0; //FIFO is full already, we can't add anything
    return 0; //this is not a failure, we just have nothing to do, this is indicated in actualLoaded
    numLoaded = 0;
    lclData = (usint *)data; //must use 16 bit writes to the module
    //conditions are dealt with inside the for loop rather than in the for statement itself
    for (FIFOentry = *actualStartIndex; ; FIFOentry++) {
    //if we reached the end of the FIFO
    //if the module is about to transmit the first element of the FIFO, the FIFO is full and we're done
    //OR if the module is about to transmit the element we're about to fill in, we're done - the
    //exception is if this is the first element we're filling in which means the FIFO is empty
    if ((( FIFOentry >= ptxFIFO->numEntries) && (nextEntryToTransmit == 0)) ||
    ((FIFOentry == nextEntryToTransmit) && (FIFOentry != *actualStartIndex) )){
    *actualLoaded = numLoaded;
    //set nextEntryToLoad to the end of the FIFO, we'll set it to the beginning next time
    //this allows us to distinguish between full and empty: nextEntryToLoad == nextEntryToTransmit means empty
    ptxFIFO->nextEntryToLoad = FIFOentry;
    return 0;
    //we reached the end but can continue loading from the top of the FIFO
    if ( FIFOentry >= ptxFIFO->numEntries)
    FIFOentry = 0;
    //load the control word
    ptxFIFO->FifoData[FIFOentry * 3] = *lclData++;
    //skip the high of the control word, the module only has a 16 bit field for control
    lclData++;
    //now put in the data
    ptxFIFO->FifoData[(FIFOentry * 3) + 2] = *lclData++;
    ptxFIFO->FifoData[(FIFOentry * 3) + 1] = *lclData++;
    numLoaded++;
    //we're done because we loaded everything the user asked for
    if (numLoaded >= numWords) {
    *actualLoaded = numLoaded;
    ptxFIFO->nextEntryToLoad = FIFOentry+1;
    return 0;
    //if we reached here, we're done because the FIFO is full
    *actualLoaded = numLoaded;
    ptxFIFO->nextEntryToLoad = FIFOentry;
    fclose (pFile);
    return 0;
     As you can see, I added a temporary diagnostic with the structures that were created in the "Handles by value" case, and print out the data.  I see what is expected, whichever of the options I pick in the CLN!  
    I understood (from the information in the two links I mentioned in my original post, and from the name of the option itself) that "array data pointer" should pass the array of data itself, without the dimSize field.  But that does not seem to be what is happening.
    Batya
    Attachments:
    ExcM4k Load Transmit FIFO.vi ‏15 KB

  • Call multiple functions from same dll with call library function

    hi,
    i am working on a project in wich we need to make a UI to read out a sensor network.
    the UI should be usable in any project, but every node needs a different piece of code depending on the type of sensor with wich it is equipt.
    so i need to be able to call different pieces of code when i need them, and still be able to use the UI in future projects with possibly new types of node we now don't have.
    so someone told me to use DLL's, cause then i would be able to call the code i need the moment i need it.
    but i have never worked with DLL's (just learned about this option 3 day's ago) so i have a question.
    i know i can dynamicly change the DLL i call with the call library function, but can i dynamicly change the function i call from that DLL ?
    or do i have to put a new call library function for each function i want to call, even if its from the same DLL ?
    kind regards,
    stijn

    nazarim wrote:
    ok so there is no (easy and ubderstandable) way for me to dynamicly change wich function i want to call from a certain DLL.
    but now i started wondering, the path on the call library function is not ment to dynamicly change a DLL
    but it does work so, if i am carefull, can i use it for that purpose or will labview give me a series of problems once i start using it in larger programs ?
    Thepath on the Call Library Node can be used to load a different DLL. Obviously since you can't change the function name your other DLL would have to export exactly the same function name and of course with the same parameters. This is seldom the case so it is not the main use of the path input to the Call Library Node. It's main use is as indicated to load DLLs at runtime rather than at load time of a VI. So that an application can run even when the DLL is missing, until the moment the functionality from that DLL is needed.
    If you can make sure that all your DLLs export the same function name with the same parameter you can use the Call Library Node to call into different DLLs through the path input. If however you would need to call different function names you would have to resolve to some DLL which does do the dispatching and invocation using LoadLibrary() and GetProcAddress(). But unless you need to go with DLLs for some reason using the Call By Reference Node can give you an even more flexible approach. 
    Rolf Kalbermatter
    CIT Engineering Netherlands
    a division of Test & Measurement Solutions

  • How to use structure pointer with « Call Library Function node » in LabVIEW

    I use GetTimeZoneInformation from kernel32.dll. It definition is :
    DWORD GetTimeZoneInformation( LPTIME_ZONE_INFORMATION lpTimeZoneInformation );
    Where
    lpTimeZoneInformation
    [out] Pointer to a TIME_ZONE_INFORMATION structure to receive the current time-zone parameters.
    http://msdn.microsoft.com/library/default.asp?url=​/library/en-us/sysinfo/base/gettimezoneinformation​...
    I don't know how to set this parameter with my cluster based on the TIME_ZONE_INFORMATION structure.
    Your help will be appreciate
    Thanks
    INKSPEC

    INKSPEC wrote:
    I use GetTimeZoneInformation from kernel32.dll. It definition is :
    DWORD GetTimeZoneInformation( LPTIME_ZONE_INFORMATION lpTimeZoneInformation );
    Where
    lpTimeZoneInformation
    [out] Pointer to a TIME_ZONE_INFORMATION structure to receive the current time-zone parameters.
    http://msdn.microsoft.com/library/default.asp?url=​/library/en-us/sysinfo/base/gettimezoneinformation​...
    I don't know how to set this parameter with my cluster based on the TIME_ZONE_INFORMATION structure.
    Your help will be appreciate
    Thanks
    INKSPEC
    If creating a wrapper DLL which does the conversion for you is not an option (I think it won't since that would require C programming and if you knew C programming you wouldn't ask this here) then you will have to create a byte array of appropriate length and just configure the Call Library Node to pass this array as an Array of unsigned bytes and as C pointer.
    On return you will have to copy out the interesting data at the right position.
    First the length of this structure would be:
    typedef struct _TIME_ZONE_INFORMATION {
    LONG Bias; 4
    WCHAR StandardName[32]; 32 * 2
    SYSTEMTIME StandardDate; 8 * 2
    LONG StandardBias; 4
    WCHAR DaylightName[32]; 32 * 2
    SYSTEMTIME DaylightDate; 8 * 2
    LONG DaylightBias; 4
    } TIME_ZONE_INFORMATION
    Total 172 bytes
    Now the fun part will be to actually get out the information. There are a number of difficulties.
    First the strings are 16 bit Unicode so if you are interested in them you will have to call a different Windows API function WideCharToMultiByte function to convert the 16bit Unicode string into an ASCII string. For this part there has been a post here:
    http://forums.ni.com/ni/board/message?board.id=170​&message.id=123821&requireLogin=False
    For the LONG values you would pick 4 bytes at the appropriate offset from the array through the Array Subset function and then typecast it into an int32 and pass that through the Swap Bytes and Swap Words functions to reverse the LabVIEW Big Endian byte swapping in the Typecast function.
    The SYSTEMTIME is a structure with eight 2 byte integers so it would be best to use Array Subset again to extract 16 bytes at the correct offset, typecast this into a cluster with eight int16 numerics and pass it through Swap Bytes too.
    You see accessing such API functions in LabVIEW directly can get easily quite a mess and that is the reason why creating a wrapper DLL to convert properly between LabVIEW datatypes and C datatypes gets soon the easier solution if you need to interface with more than one or two functions taking such complicated data structures.
    Rolf Kalbermatter
    Rolf Kalbermatter
    CIT Engineering Netherlands
    a division of Test & Measurement Solutions

  • The call library function require us to define the type of parameter that w are using.The type of parameter in cludes numeric, array, string,wav​eform and adapt to type.I would like to know more about waveform and adapt to type.

    In the labview manual, there is very little mention about the use of waveform.How is this waveform being called and can i have an example to see how this work.
    Also in the adapt to type paramete, what does this parameter do and in what circumstances do we need to use it.The manual say something about the use of this parametr.It says that scalar elements in arrays or clusters are in line.For example a cluster containing anumeric is passed as pointer to a structure containing a numeric. What does this statement mean?
    Can i imply t
    hat if my input is a struct, can i use a adapt to type parameter to overcome this incompatibility?Can i also have an example to let me have a better idea.thank you

    I'm going to share my experience with the "Adapt to Type" parameter.
    Attached to this message is an example. The attachment is a zip file with three files: a dll, a c file and a vi written in LabVIEW 6. The dll contains a function that return a structure with 3 values (like the coordinates of a point in space, that is, (x, y, z)). You can see how the function was constructed by looking at the c file.
    In LabVIEW, I created a cluster with the same three parameters. Then, I configured the call library function following the function prototype as in the c file. For the point variable I use "Adapt to Type".
    I hope this can give you a head star.
    Best regards;
    E. Vargas
    www.vartortech.com
    Attachments:
    pointexample.zip ‏63 KB

  • Xdk: calling java function with a CharSequence parameter

    When using xdk version 10.1.0.2.0_production, you can not call a javamethod with a CharSequence parameter.
    Sun documentation:
    Interface CharSequence
    All Known Implementing Classes:
    CharBuffer, String, StringBuffer
    This prevents us from calling a method like
    java.util.regex.Pattern.matches(String, CharSequence)
    Converting the parameter to a normal string would solve the problem.
    Example to illustrate the issue:
    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xdt="http://www.w3.org/2005/02/xpath-datatypes" xmlns:Pattern="http://www.oracle.com/XSL/Transform/java/java.util.regex.Pattern">
         <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:template match="/">
    <xsl:if test="Pattern:matches('...','123')">
    <xsl:text>MATCH</xsl:text>
    </xsl:if>
    </xsl:template>
    </xsl:stylesheet>
    results in the following stacktrace:
    oracle.xml.parser.v2.XPathException: Extension function error: Error invoking 'matches':'java.lang.NullPointerException'
         at oracle.xml.parser.v2.XSLExtFunctions.callStaticMethod(XSLExtFunctions.java:113)
         at oracle.xml.parser.v2.XPathExtFunction.evaluateMethod(XPathExtFunction.java:296)
         at oracle.xml.parser.v2.XPathExtFunction.evaluate(XPathExtFunction.java:223)
         at oracle.xml.parser.v2.XSLCondition.testCondition(XSLCondition.java:185)
         at oracle.xml.parser.v2.XSLCondition.processAction(XSLCondition.java:165)
         at oracle.xml.parser.v2.XSLNode.processChildren(XSLNode.java:403)
         at oracle.xml.parser.v2.XSLTemplate.processAction(XSLTemplate.java:191)
         at oracle.xml.parser.v2.XSLStylesheet.execute(XSLStylesheet.java:507)
         at oracle.xml.parser.v2.XSLStylesheet.execute(XSLStylesheet.java:484)
         at oracle.xml.parser.v2.XSLProcessor.processXSL(XSLProcessor.java:256)
         at oracle.xml.parser.v2.XSLProcessor.processXSL(XSLProcessor.java:146)
         at oracle.xml.parser.v2.XSLProcessor.processXSL(XSLProcessor.java:218)
         at XSLSample.main(XSLSample.java:75)
    Message was edited by:
    user449717

    Hi Grarup,
    I took a stab at getting this to run and compile and this is what I came up with.  Let me know if this helps at all.
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    namespace ConsoleApplication1
    class Program
    static void Main(string[] args)
    Console.WriteLine("\"True\" or \"False\"?");
    bool boolVal = bool.Parse(Console.ReadLine());
    Functions f = new Functions();
    TestStruct t = new TestStruct() { Value = boolVal };
    f.Flip(ref t);
    Console.WriteLine(string.Format("Flipped value = {0}: ", t.Value));
    Console.ReadLine();
    public struct TestStruct
    public bool Value;
    public class Functions
    public void Flip(ref TestStruct testStruct)
    testStruct.Value = !testStruct.Value;
    Best of luck.

  • Passing arrays with Call Library Function does not work after application builder

    Calling a DLL with Call Library Function which requires an array of data works correctly in Labview, but after building an exe with application builder, the call no longer works.  Dereferecing the pointer in the DLL retuns all 0s and not the actual values.
    Solved!
    Go to Solution.
    Attachments:
    TEST.zip ‏28 KB

    I did not run your code because it is a little unclear to me what it does.
    Two things:
    First, is the DLL you are calling the DLL-ified version of PopUpNames.vi? Then the problem is likely that the panel is not being built into the DLL.
    When LabView builds an application / dll, it strips the front panel and block diagram from all VIs that it doesn't think need to show a panel at run time. This reduces file size and increases code security. The App Builder's panel inclusion logic can be overridden by Build Specifications -> Source File Settings -> Remove front panel. A better method is to put a property node on a control in a window you want to show marking it "visible"; this is sufficient to tell the App Builder it should keep the panel.
    Currently Source File Settings shows "no dependencies" (clearly incorrect---another evil side effect of Express VIs I guess) but if you change the settings as shown below to keep ALL panels, one might hope the App Builder can figure it to keep the panel when it deconstructs the Express VI. (Alternatively convert the Express VI into a regular one.)
    A second comment: I am a bit flummoxed at the larger goal here. You are calling LabView DLL from LabView, which doesn't make a lot of sense, so I assume your larger goal is to call LabView from C or vice-versa. In that case be aware that your DLL is x86 (32-bit) but you are passing 64-bit ints as your pointers. In this case it is 32-bit LabView with 32-bit pointers in embedeed in 64-bit containers calling 32-bit LabView with 32-bit pointers in embedeed in 64-bit containers, so it all works, but if your going to call this from C or whatnot you're going to have to follow that same design.
    When calling C code the LabView Call Library Function does have a "unsigned pointer-sized integer" data type that always appears to be 64 bits in the dev env but which actually passes a 64 or 32-bit int to the DLL depending on the environment. The "pointer sized int" has to be 64 bits in the "LabView" part of the code because LabView's strong typing requires the data type to be determined at compile time. Casting all pointers to the largest data type in LabView makes it possible to write platform-independent code, but down at the Call Library level you still have to put the right number of bytes on the stack.

Maybe you are looking for