none
Obtain IRecordInfo pointer for struct defined in same DLL

    Question

  • I am passing information back and forth between C# and an unmanaged DLL written in VC++. I have the C#->C++ interface code working well passing SAFEARRAYs of UDTs with no problem.

    I am struggling with the creation of SAFEARRAYs to go the other way. I can see that I need to use CreateSafeArrayEx but I cannot work out how to get the IRecordInfo pointers for a structs that are defined in the current DLL. All the examples I can find expect that UDT type information to be imported from an external type library file.

    Please can someone point me at an example for creating SAFEARRAYs of UDTs where the UDT (in my case structs) are declared in the same project in VSS.

    Thanks.



    Phil

    Monday, December 3, 2018 5:39 PM

All replies

  • On 12/3/2018 12:39 PM, Phil_Unity wrote:

    I am struggling with the creation of SAFEARRAYs to go the other way. I can see that I need to use CreateSafeArrayEx but I cannot work out how to get the IRecordInfo pointers for a structs that are defined in the current DLL. All the examples I can find expect that UDT type information to be imported from an external type library file.

    You do need a type library, but it doesn't have to be in a separate file. It's common for it to be embedded into the DLL as a resource. Chances are your DLL already contains one. Functions like LoadTypeLibEx accept an executable file (EXE or DLL) and look for type library in its resources.

    You would then use GetRecordInfoFromGuids or GetRecordInfoFromTypeInfo to obtain IRecordInfo pointer. The former requires that the TLB be registered; the latter does not.

    Monday, December 3, 2018 10:34 PM
  • Hello Phil_Unity,

    Is your structure defined in C# or in C++ ?

    - Bio.


    Please visit my blog : http://limbioliong.wordpress.com/

    Tuesday, December 4, 2018 1:25 PM
  • Hi Bio,

    My structs is defined in C++. Trying to follow up on from Igor's answer I am having real difficulty finding examples or documentation as to how I can include the type definitions in the native DLL. Is there another way to access IRecordInfo pointer for a struct defined in the same project as the code building the SAFEARRAY? Having to create and register a type library seems overkill. I am using PInvoke to call the native methods from C# and also to handle callbacks from C++ to C# (having previous registered a callback handler via a call from C#). I am at the stage now though where the EventArgs struct used by the call backs needs to pass back a SAFEARRAY of UDTs.

    The call back typedef, eventargs and UDT examples are shown below:

    typedef void(__stdcall *MODELEVENTCB)(int notifyCode, ModelEventArgs* notifyInfo);
    
    struct ModelEventArgs {	
       GUID event_id;	
       int event_code;	
       BSTR message;	
       double time;	
       double progress = 0.0;	
       FacadeModel model;
    };
    
    [uuid("6E695905-F30F-4677-A44E-8572A763786A")]
    typedef struct FacadeModel
    {	
       GUID id;	
       FacadeRunParameters run_parameters;	
       FacadeStateSolution solution;	
       SAFEARRAY*	basis;		// vector<FacadeBasis>
    } FacadeModel;
    
    [uuid("82D5D544-A555-4830-B604-D197EE3F465E")]
    typedef struct FacadeBasis
    {
    	BSTR	name;
    	BSTR	eos;
    	EOSType	eostype;
    	double	c;					// selects cubic type c = 0 is RKS c = 1 is PR
    	SAFEARRAY*	phase_order;		// vector<long>
    	SAFEARRAY*	phases;				// vector<BSTR>
    	SAFEARRAY*	component_order;	// vector<int>
    } FacadeBasis;
    

    What I need to do is correctly generate a SAFEARRAY* of FacadeBasis, which itself will contain a SAFEARRAY* to another UDT (the full definition of FacadeBasis is not shown above).



    Phil

    Tuesday, December 4, 2018 1:53 PM
  • Assuming that the type library is not registered -

    Load the type library with LoadTypeLib to obtain an ITypeLib interface pointer.

    Then you can call ITypeLib::GetTypeInfoOfGuid method to obtain an ITypeInfo interface pointer. Pass the uuid of the UDT.

    Finally, call GetRecordInfoFromTypeInfo function to obtain the IRecordInfo interface.



    Tuesday, December 4, 2018 3:58 PM
  • I have tried that and it just returns "Error loading type library/DLL". Is there something I must do to get the compiler to put the type info into the DLL. The VS project is a 64bit Dynamic Library (DLL). I did not choose to use ATL or .NET/CLR when the project was created.

    I am also a bit concerned about having to put a hard coded path to the DLL in my code too. In C# I could use reflection to get the path to the current assembly but this is not possible in unmanaged C++.

    Happy to read documentation if anyone can point me at some.


    Phil


    • Edited by Phil_Unity Tuesday, December 4, 2018 4:25 PM
    Tuesday, December 4, 2018 4:23 PM
  • You can also load the tlb directly if it is not a resource in the dll.  Make sure to pass the full path to the tlb if you don't want it to be registered.
    Tuesday, December 4, 2018 4:26 PM
  • There is no type library. The structs are declared in the same VS DLL project as the code that creates the SAFEARRAYs.

    Is that the step I am missing? Do I need to do something to create a TypeLibrary tlb file from the compiled DLL?


    Phil


    • Edited by Phil_Unity Tuesday, December 4, 2018 4:30 PM
    Tuesday, December 4, 2018 4:30 PM
  • There is no type library. The structs are declared in the same VS DLL project as the code that creates the SAFEARRAYs.

    Is that the step I am missing? Do I need to do something to create a TypeLibrary tlb file from the compiled DLL?

    The type library is needed.  This was mentioned by Igor Tandetnik in the initial response to your question.

    Ordinarily you would have an IDL file in your project that is compiled by MIDL into a type library.  The DLL project's .rc file would have a TYPELIB resource statement so that the generated type library is included as a resource.

    Also, MIDL would create header files from which you can reference the struct.

    If you use ATL to create your DLL all of this stuff is set up for you automatically.


    • Edited by RLWA32 Tuesday, December 4, 2018 4:38 PM
    Tuesday, December 4, 2018 4:36 PM
  • Thanks, I am going to create a simple ATL project and see if I can see the differences between that and my existing DLL project. Failing that I guess I need to recreate my Facade DLL :(.


    Phil

    Tuesday, December 4, 2018 4:55 PM
  • Thanks, I am going to create a simple ATL project and see if I can see the differences between that and my existing DLL project. Failing that I guess I need to recreate my Facade DLL :(.


    Phil


    Don't jump the gun.  You can add an MIDL file to your existing project so that a type library is created.  Then it's just a matter of tweaking other settings so that type library is added as a resource.
    Tuesday, December 4, 2018 5:03 PM
  • BTW, if I remember correctly the ATL wizard will set the Linker->General->Register Output property to "Yes".  You'll probably want to change that to "No".
    Tuesday, December 4, 2018 5:40 PM
  • I have finally managed to get my dll to include a type library. I created an idl file defining for the structs. Compiled it and then updated my code to use the struct definitions from the _i.h file instead of my original header.

    I can see the type library of I open the dll with View Typelib in oleview.

    Problem now is that although LoadTypeLib returns success the ITypeLib* parameter just says "<Information not available, no symbol loaded for oleaut32.dll>".

    Thanks for your patience but does anyone have any pointers as to where I go from here?


    Phil


    • Edited by Phil_Unity Thursday, December 6, 2018 8:13 PM
    Thursday, December 6, 2018 8:13 PM

  • Problem now is that although LoadTypeLib returns success the ITypeLib* parameter just says "<Information not available, no symbol loaded for oleaut32.dll>".


    This sounds like the debugger is telling you that it has not loaded a symbol file for oleaut32.dll. This is informational only.

    However, if LoadTypeLib completed successfully it should have returned a valid ITypeLIb interface pointer for you to use.


    • Edited by RLWA32 Thursday, December 6, 2018 11:12 PM
    Thursday, December 6, 2018 11:09 PM
  • A week later and I am still stuck on this!

    All the examples I have found create an object in the IDL file with methods.

    My IDL only contains definitions for enums and structs.

    The methods within the DLL are accessed via PInvoke not OLE Automation. Basically the public methods are declared with __declspec(dllexport).

    Does it matter that I only have enums and structs in the IDL file? Could this be reason why I cannot access the IRecordInfo information for the structs?



    Phil

    12 hours 6 minutes ago
  • A week later and I am still stuck on this!

    All the examples I have found create an object in the IDL file with methods.

    My IDL only contains definitions for enums and structs.

    The methods within the DLL are accessed via PInvoke not OLE Automation. Basically the public methods are declared with __declspec(dllexport).

    Does it matter that I only have enums and structs in the IDL file? Could this be reason why I cannot access the IRecordInfo information for the structs?



    Phil

    Circling back to the beginning, you needed an IRecordInfo interface pointer because you wanted to create a SAFEARRAY of UDTs.

    You should be able to use MIDL to create a type library for structs  without needing to include any interfaces or coclasses.

    • Edited by RLWA32 10 hours 19 minutes ago
    10 hours 23 minutes ago
  • I cobbled together a sample using VS2015.  The solution contains 3 projects.  Of course error checking is minimal and I can't say that it was extensively tested.

    A native Win32 dll that exports one function to return a safearray of nested UDTs.

    Another Win32 console project to exercise the dll.

    Finally, a C# console project using p/invoke to retrieve the UDT arrays.

    You can get the sample from RecLib.zip

    6 hours 53 minutes ago