Hi,
I am continuing to setup a DDS interface using the C# file generators and I have this question:
I have generated the files using the C# option and everything is compiling. I have a DDSTerminal.cs class that instantiates a CreateProductType_publisher. However, when the CreateProductType_publisher is instantiated, it throws System.TypeInitialization runtime exception. One source said this error is sometimes thrown if the class makes reference to an unmanaged library when it is expecting a CLR library.
Here is the DDSTerminal class. This class compiles as part of a CLR project:
using System;
using System.Collections.Generic;
using System.Text;
using Chart.DataAccess.DDSInterface;
namespace Chart.DataAccess
{
public class DDSTerminal
{
public DDSTerminal()
{
createProductRequestTypePublisher = new ProductMissionRequestTypePublisher();
}
public GanttChart.DataAccess.DDSInterface.CreateProductRequestTypePublisher createProductRequestTypePublisher;
}
}
and here is the code for the publisher, which lives in the same CLR build:
using System;
using System.Collections.Generic;
using System.Text;
using UCS.Project;
using DDS;
using Chart.Model;
namespace Chart{
namespace DataAccess{
namespace DDSInterface
{
public class CreateProductRequestTypePublisher
{
public CreateProductRequestTypePublisher()
{
// --- Set domain ID --- //
int domain_id = 0;
/* Uncomment this to turn on additional logging
NDDS.ConfigLogger.get_instance().set_verbosity_by_category(
NDDS.LogCategory.NDDS_CONFIG_LOG_CATEGORY_API,
NDDS.LogVerbosity.NDDS_CONFIG_LOG_VERBOSITY_STATUS_ALL);
*/
// --- Create participant --- //
/* To customize participant QoS, use
the configuration file USER_QOS_PROFILES.xml */
participant =
DDS.DomainParticipantFactory.get_instance().create_participant(
domain_id,
DDS.DomainParticipantFactory.PARTICIPANT_QOS_DEFAULT,
null /* listener */,
DDS.StatusMask.STATUS_MASK_NONE);
if (participant == null)
{
shutdown();
throw new ApplicationException("create_participant error");
}
// --- Create publisher --- //
/* To customize publisher QoS, use
the configuration file USER_QOS_PROFILES.xml */
DDS.Publisher publisher = participant.create_publisher(
DDS.DomainParticipant.PUBLISHER_QOS_DEFAULT,
null /* listener */,
DDS.StatusMask.STATUS_MASK_NONE);
if (publisher == null)
{
shutdown();
throw new ApplicationException("create_publisher error");
}
// --- Create topic --- //
/* Register type before creating topic */
System.String type_name = CreateProductRequestTypeTypeSupport.get_type_name();
try
{
CreateProductRequestTypeTypeSupport.register_type(
participant, type_name);
}
catch (DDS.Exception e)
{
Console.WriteLine("register_type error {0}", e);
shutdown();
throw e;
}
/* To customize topic QoS, use
the configuration file USER_QOS_PROFILES.xml */
DDS.Topic topic = participant.create_topic(
"Example CreateProductRequestType",
type_name,
DDS.DomainParticipant.TOPIC_QOS_DEFAULT,
null /* listener */,
DDS.StatusMask.STATUS_MASK_NONE);
if (topic == null)
{
shutdown();
throw new ApplicationException("create_topic error");
}
// --- Create writer --- //
/* To customize data writer QoS, use
the configuration file USER_QOS_PROFILES.xml */
DDS.DataWriter writer = publisher.create_datawriter(
topic,
DDS.Publisher.DATAWRITER_QOS_DEFAULT,
null /* listener */,
DDS.StatusMask.STATUS_MASK_NONE);
if (writer == null)
{
shutdown();
throw new ApplicationException("create_datawriter error");
}
CreateProductRequestType_writer = (CreateProductRequestTypeDataWriter)writer;
}
public void publish(UCS.Project.CreateProductRequestType instance)
{
/* For a data type that has a key, if the same instance is going to be
written multiple times, initialize the key here
and register the keyed instance prior to writing */
DDS.InstanceHandle_t instance_handle = DDS.InstanceHandle_t.HANDLE_NIL;
//instance_handle = CreateProductRequestType_writer.register_instance(instance);
/* Modify the data to be sent here */
try
{
CreateProductRequestType_writer.write(instance, ref instance_handle);
}
catch (DDS.Exception e)
{
Console.WriteLine("write error {0}", e);
}
System.Threading.Thread.Sleep(4000);
/*
try {
CreateProductRequestType_writer.unregister_instance(
instance, ref instance_handle);
} catch(DDS.Exception e) {
Console.WriteLine("unregister instance error: {0}", e);
}
*/
}
public void shutdown()
{
// --- Shutdown --- //
/* Delete all entities */
if (participant != null)
{
participant.delete_contained_entities();
DDS.DomainParticipantFactory.get_instance().delete_participant(
ref participant);
}
/* RTI Connext provides finalize_instance() method on
domain participant factory for people who want to release memory
used by the participant factory. Uncomment the following block of
code for clean destruction of the singleton. */
/*
try {
DDS.DomainParticipantFactory.finalize_instance();
} catch (DDS.Exception e) {
Console.WriteLine("finalize_instance error: {0}", e);
throw e;
}
*/
}
private DDS.DomainParticipant participant;
private CreateProductRequestTypeDataWriter CreateProductRequestType_writer;
}
} /* namespace DDSInterface */
} /* namespace DataAccess */
} /* namespace Chart */
The generated *.h/cpp,*Plugin.h/cpp, and *Support.h/cpp files are all compiled into a DSS_Access.dll, which is also compiled with CLR. It is linked as a reference in the csharp project that contains the DDSTerminal and ProductRequestType_publisher classes.
So it seems like all parts are compiling CLR. I'm not sure why the type initialization exception is triggered. Any ideas?
Thanks in advance,
Myca
Hello Myca,
One quick question: What is a ProductMissionRequestTypePublisher vs. the CreateProductRequestTypePublisher? I'm trying to create a small reproducer with my own HelloWorld data type, and I'd like it to be close enough to see the behavior you are seeing.
Thank you,
Rose
Hi Rose,
Thank you for your help Rose. That was a cut and paste error on my part. If you change your code to be:
createProductRequestTypePublisher = new ProductRequestTypePublisher();
then it will match what I have.
Thanks again!
Myca
My simple reproducer (based entirely off of hello world) works without throwing an exception.
Some additional questions: Is there any more information in the exception? What happens if you comment out most of the DDS initialization? In other words, call nothing but DDS.DomainParticipantFactory.get_instance()? This may help narrow the problem, since it still calls RTI's shipped DLLs, but does not commonly fail (where creating a DomainParticipant may fail and throw an exception). By doing this, your code will also not be using the type-specific calls in the *Support.cpp/.h, etc. from your generated code project. If this works, I'd be interested to see what happens as you add back in the DomainParticipant creation, and then the code to register your data type, etc.
I am interested in knowing if loading the RTI DLLs is a problem, or the DLLs that are specific to your data type. Also, it will be good to confirm that there aren't any exceptions being thrown directly from the RTI APIs.
Thank you!
Rose
Hi Rose,
It appears to throw the exception on references to either the type generated code OR the nddsdot libraries. I ran a test with 3 cases:
1. I commented out all the method bodies in each CreateProductRequestType_publisher.cs. This case runs without exception.
2. After that, I added the single line "DDS.DomainParticipantFactory.get_instance();" in the publisher's constructor. This throws a System.BadImageFormatException, says it could not load the nddsdotnet library. An attempt was made to load a program with the incorrect format.
3. Then I replaced that line with "System.String type_name = CreateProductRequestTypeTypeSupport.get_type_name();" This gave the same error, saying it couldn't load the library my generated types are stored in because it was in the incorrect format.
So I am thinking that the way I am referencing both libraries from my code is not right, but I'm not sure why. I'm attaching the build files for the PanelChart.csproj (that's where the DDSTerminal and CreateProductRequestType classes are implemented) and the DDS_Access.vjproj, where the generated types are.
Thank you again for looking at this -- I like your signature's joke, too. :)
Myca
You are welcome! And I'm glad you like the joke – you're the first person who has commented on it outside of RTI. :-D
One issue you might be having is that our libraries were built for a 32-bit target, but it looks like your project is targeting any CPU. That can cause a BadImageFormatException. Can you try changing your target platform to 32-bit? (I don't have VS 2008, so I am looking at your project in an editor so VS2010 doesn't modify it).
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
Thank you,
Rose
Thank you Rose! That seemed to clear things up.