Thread: passing params between managed c++ and unmanaged c++

  1. #1
    Registered User
    Join Date
    Jan 2009
    Posts
    7

    passing params between managed c++ and unmanaged c++

    Hi folks,

    I have a strange problem, seems to be Garbage Collector in managed memory. There is an unmanaged dll which makes a call to my managed dll with giving a structure as a parameter. Managed dll takes this param and sets the values in the struct. when debugging on the managed side, all the values in the struct are meaningfull but when i pas back to unmanaged dll side, some values in the struct became huge or meaningles.

    I have played arround marshalling, pinned pointers etc. but when the DVRSET param is passed to unmanaged c++ dll, values of the struct became abnormal...

    Thanks for your further help...

    Here is the code
    structure defined in both sides...
    Code:
    struct DVRSET
    	{
    
    		//Top Values
    		bool	DoRender;
    
    		//Global Switches
    		bool	GS_Geo_Displacement;
    		bool	GS_Geo_ForceBackFaceCulling;
    		
    		bool	GS_Lighting_Lights;
    		bool	GS_Lighting_DefaultLights;
    		bool	GS_Lighting_HiddenLights;
    		bool	GS_Lighting_Shadows;
    		bool	GS_Lighting_ShowGIOnly;
    		
    		bool	GS_Materials_ReflectionRefraction;
    		bool	GS_Materials_MaxDepth;
    		int		GS_Materials_MaxDepthValue;
    		bool	GS_Materials_Maps;
    		bool	GS_Materials_FilterMaps;
    		bool	GS_Materials_FilterMapsForGUI;
    		int		GS_Materials_MaxTrunspLevel;
    		float	GS_Materials_TrunspCutOff;
    		
    		float	GS_RayTracing_SecondaryRayBias;
    		
    		bool	GS_IndirectIllumination_DontRenderFinalImage;
    		
    		//Environment Settings
    		int		ES_BGColorR;
    		int		ES_BGColorG;
    		int		ES_BGColorB;
    
    		int		ES_ReflectColorR;
    		int		ES_ReflectColorG;
    		int		ES_ReflectColorB;
    
    		int		ES_RefractColorR;
    		int		ES_RefractColorG;
    		int		ES_RefractColorB;
    
    		int		ES_GIColorR;
    		int		ES_GIColorG;
    		int		ES_GIColorB;
    
    		float	ES_BGTexMultiplier;
            float	ES_ReflectTexMultiplier;
            float	ES_RefractTexMultiplier;
            float	ES_GITexMultiplier;
    
    
    		//Color Mapping
    		int		CM_Type;
    		float	CM_DarkMultiplier;
    		float	CM_BrightMultiplier;
    		float	CM_Gama;
    		float	CM_ClampLevel;
    		bool	CM_SubPixelMapping;
    		bool	CM_ClampOutput;
    		bool	CM_AdaptationOnly;
    
    		//Indirect Illumination (GI)
    		bool	GI_On;
    		bool	GI_ReflectCaustics;
            bool	GI_RefractCaustics;
            float	GI_Saturation;
            float	GI_Contrast;
            float	GI_ContrastBase;
    		float	GI_PrimaryMultiplier;
            float	GI_SecondaryMultiplier;
            int		GI_PrimaryEngine;
            int		GI_SecondaryEngine;
    
    		//Irradiance Map
    		int		IM_MinRate;
    		int		IM_MaxRate;
    		int		IM_SubDivs;
    		int		IM_InterpSamples;
    		int		IM_InterpFrames;
    		float	IM_ColorThreshold;
    		float	IM_NormalThreshold;
    		float	IM_DistanceThreshold;
    		bool	IM_DetailEnhancement;
    		float	IM_DetailRadius;
    		float	IM_DetailSubdivsMulti;
    		int		IM_DetailScale;
    		int		IM_InterpolationMode;
    		int		IM_LookupMode;
    		bool	IM_Multipass;
    		bool	IM_RandomizeSamples;
    		bool	IM_CheckSampleVisibility;
            bool	IM_ShowCalcPhase;
            bool	IM_ShowDirectLight;
            bool	IM_ShowSamples;
    		int		IM_Mode;
    		//Light Cache
    		int		LC_SubDivs;
    		float	LC_SampleSize;
    		int		LC_FilterType;
    		int		LC_FilterSamples;
    		float	LC_FilterSize;
    		bool	LC_PreFilter;
    		int		LC_PreFilterSamples;
    		int		LC_Depth;
    		bool	LC_ShowCalcPhase;
    		bool	LC_StoreDirectLight;
    		bool	LC_WorldScale;
    		int		LC_Mode;
    		bool	LC_UseForGlossyRays;
    		bool	LC_AdaptiveSampling;
    		int		LC_NumPasses;
    		//Region Size
    		int		RG_XC;
    		int		RG_YC;
    		//Output Settings
    		int OS_ImageSize;
    	};
    the managed code
    Code:
    extern "C"
    {
    	__declspec(dllexport) bool __cdecl SetStruct(DVRSET* settings) 
    	{
    		bool retVal = false;
    		DinoVRay::TestForm frm;
    		frm.Settings = settings;
    		if(frm.ShowDialog() == System::Windows::Forms::DialogResult::OK)
    			retVal = true;
    		else
    			retVal = false;
    		settings = frm.Settings;
    		return retVal;
    	}
    }
    unmanaged side
    Code:
    	//.NET DLL Bridge cagiriliyor....
    	HINSTANCE hBridgeDLL = LoadLibrary("DinoVRay.dll");
    	FARPROC lpfnGetProcessID = GetProcAddress(HMODULE (hBridgeDLL), "SetStruct");
    	typedef void (__cdecl * pICFUNC)(DVRSET*);
    	pICFUNC MyFunction;
        MyFunction = pICFUNC(lpfnGetProcessID);
    	
    	DVRSET vrset;
    	
    	MyFunction(&vrset); //-> Get The Form Ula

  2. #2
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    I have no idea why this doesn't work, but I can pretty much guarantee that it isn't something about the garbage collector, since the garbage collector really has nothing to do with this operation.

    My only idea is that the declaration of DVRSTRUCT is interpreted differently in the two environments.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  3. #3
    Registered User
    Join Date
    Jan 2009
    Posts
    7
    Yes you are right, GC cannot do anything with it cos this param has been created in the "caller" side. But i could not find any solution "why" the values became abnormal. (for ex. maxdeptvalue should be 1 but it seems to be 327768 on the unmanaged side

  4. #4
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    You can try a few things.

    First, write out sizeof(DVRSTRUCT) on both sides. If the sizes differ, the compiler has interpreted the definition differently the two times.

    Next, don't compare what the debugger or some debug output says about the contents, but instead look at the memory. On the callee side, jump to the address stored in settings in the memory watcher and copy the next sizeof(DVRSTRUCT) bytes to a text editor for safekeeping.
    Then return to the caller and see if the actual memory changes. It really shouldn't. Also, get &vrset and check that it is the same address as before.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  5. #5
    Registered User
    Join Date
    Jan 2009
    Posts
    7
    you were right about the environment interpreting difference, the structure size is 265 bytes in vc++ 6.0 side (unmanaged), and 284 in vc++.net (managed) side. what can we do to avoid this problem now?

    (Also adress of the pointer in the caller side is 0x0012fb7c but the managed side takes the adress as 0x0012f67c when it turnes back to unmanaged side, the adress remain unchanged as 0x0012fb7c)
    Last edited by cechen; 01-24-2009 at 10:36 AM.

  6. #6
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    The unmanaged side packs the struct tightly, the managed side doesn't. To correct this, use #pragma pack (look it up in the docs) to force your desired alignment on both sides.

    As for the address, I wouldn't worry about it for now. Get the other things fixed first and see if it works then.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  7. #7
    Registered User
    Join Date
    Jan 2009
    Posts
    7
    Yes this was the solution. #pragma pack(1) directive made the size of the struct as it was in the unmanaged. Also adress of the pointer is true now... Thanks alot CornedBee!!! You saved me.

    i gotta catch the underlying architecture of managed compiler more

    Quote Originally Posted by CornedBee View Post
    The unmanaged side packs the struct tightly, the managed side doesn't. To correct this, use #pragma pack (look it up in the docs) to force your desired alignment on both sides.

    As for the address, I wouldn't worry about it for now. Get the other things fixed first and see if it works then.

  8. #8
    Registered User
    Join Date
    Jan 2009
    Posts
    7
    CornedBee,

    If you are there, strange things happened to me.... for a couple of days the code ran fine, the values in the structs on both sides were the same after applying #pragma pack(1) directive... until today...

    Nothing changed in the code but now unmanaged c++ code carries the values in the struct with abnormal values again... How can it happen like that??? The struct sizes are same, adress of two structs are same... Very very confused about it...

    thanks your further help

  9. #9
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Huh ... pretty much out of ideas, then.

    Are you sure both sides are really up to date?
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  10. #10
    Registered User
    Join Date
    Jan 2009
    Posts
    7
    this was a quick response

    Hi again, in the both environment output directory is the same. So unmanaged dll and managed dll are written in the same directory.

    when i debug both DLLs in order (one by one) the size of my struct is as same as the other. Also the adresses are...

    But there is one thing. I cannot put the pragma directive on the unmanaged side cos, another external plugin uses this struct that i cannot have any access on its source. when i put this directive on the unmanaged side, the struct values seems ok but the plugin throws an exception (Access Violation) So i used this directive only in managed side...

    But if i dont use this directive on the unmanaged side, even the sizes are the same, values are abnormal.

    Confused about what to do... Should i use a wrapper of a wrapper struct :PP

  11. #11
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    You must be careful about passing variables from C# to another language. Usually the C# memory allocator will move items around here and there for optimization. This will give you problems in the language trying to use the C# variable. For this you will need to use a lock and place this in an unsafe code section. It has been a bit since my classes on C# but I believe there is a way to tell C# don't move the variable from its address under any conditions. If you don't do this your code might work part of the time but other times will not work at all. This will definitely throw an exception when you attempt to access the variable since it's address has been changed and you will at the very least get garbage values.

    However the statements about pack are also true and also need to be used. But this in and of itself will not completely solve the problem.
    Last edited by VirtualAce; 01-30-2009 at 05:18 PM.

  12. #12
    Registered User
    Join Date
    Jan 2009
    Posts
    7
    Hi Bubba,

    The parameter comes from unmanaged c++ to managed memory, so garbage collector should not and would not touch it i guess...

Popular pages Recent additions subscribe to a feed