C# / C++ Interop, Odd behaviour from marshalled strings
-
Hello, I am trying some Interop in my application. This is the first time I have had to pass arguments with function calls. I am experiencing some odd results.
// C# Function Call
RenderEngine.LoadNewMesh("BasicMesh", "Pyramid3", 1);// Managed C++ Wrapper Function
void RenderEngine::LoadNewMesh(String^ meshType, String^ meshName, int nSubsets)
{
char* cMeshType = (char*)(void*)Marshal::StringToHGlobalAnsi(meshType);
char* cMeshName = (char*)(void*)Marshal::StringToHGlobalAnsi(meshName);m\_engineRoot->LoadMesh.LoadNewMesh(cMeshType, cMeshName, nSubsets);
}
// Native C++ Function
void MeshLoader::LoadNewMesh(char* meshType, char* meshName, UINT nSubsets)
{
//char*
m_meshType = meshType;
//char*
m_meshName = meshName;
m_nSubsets = 0;
m_nTotalSubsets = nSubsets;m\_pMesh = new BasicMesh(); // This message box will display Pyramid3 MessageBox(0, meshName, 0, 0); // This code will not trigger the message box if (meshName == "Pyramid3") MessageBox(0, (char\*)"meshName is Pyramid3", 0, 0); // This code will trigger and m\_meshName is set directly as Pyramid3 // if it is not set directly here the call to GetMeshByName later on returns NULL if (strcmp(meshName,"Pyramid3") == 0) m\_meshName = "Pyramid3";
}
// Object is referenced by name here
MeshManager::CreateMesh(m_pMesh, m_meshName);// Will return NULL if char* is not set directly
MeshManager::GetMeshByName("Pyramid3"); -
Hello, I am trying some Interop in my application. This is the first time I have had to pass arguments with function calls. I am experiencing some odd results.
// C# Function Call
RenderEngine.LoadNewMesh("BasicMesh", "Pyramid3", 1);// Managed C++ Wrapper Function
void RenderEngine::LoadNewMesh(String^ meshType, String^ meshName, int nSubsets)
{
char* cMeshType = (char*)(void*)Marshal::StringToHGlobalAnsi(meshType);
char* cMeshName = (char*)(void*)Marshal::StringToHGlobalAnsi(meshName);m\_engineRoot->LoadMesh.LoadNewMesh(cMeshType, cMeshName, nSubsets);
}
// Native C++ Function
void MeshLoader::LoadNewMesh(char* meshType, char* meshName, UINT nSubsets)
{
//char*
m_meshType = meshType;
//char*
m_meshName = meshName;
m_nSubsets = 0;
m_nTotalSubsets = nSubsets;m\_pMesh = new BasicMesh(); // This message box will display Pyramid3 MessageBox(0, meshName, 0, 0); // This code will not trigger the message box if (meshName == "Pyramid3") MessageBox(0, (char\*)"meshName is Pyramid3", 0, 0); // This code will trigger and m\_meshName is set directly as Pyramid3 // if it is not set directly here the call to GetMeshByName later on returns NULL if (strcmp(meshName,"Pyramid3") == 0) m\_meshName = "Pyramid3";
}
// Object is referenced by name here
MeshManager::CreateMesh(m_pMesh, m_meshName);// Will return NULL if char* is not set directly
MeshManager::GetMeshByName("Pyramid3");Mikey_H wrote:
if (meshName == "Pyramid3")
the value of meshName is the address of the first character of the string. it is not a string itself. in other words, meshName is a pointer, not a string.
-
Mikey_H wrote:
if (meshName == "Pyramid3")
the value of meshName is the address of the first character of the string. it is not a string itself. in other words, meshName is a pointer, not a string.
The third condition here will result true, as does the second
if (meshName == "Pyramid3")
MessageBox(0, (char*)"meshName is Pyramid3", 0, 0);if (strcmp(meshName,"Pyramid3") == 0)
m_meshName = "Pyramid3";if (m_meshName == "Pyramid3")
MessageBox(0, (char*)"m_meshName is Pyramid3", 0, 0);modified on Tuesday, April 14, 2009 12:35 PM
-
The third condition here will result true, as does the second
if (meshName == "Pyramid3")
MessageBox(0, (char*)"meshName is Pyramid3", 0, 0);if (strcmp(meshName,"Pyramid3") == 0)
m_meshName = "Pyramid3";if (m_meshName == "Pyramid3")
MessageBox(0, (char*)"m_meshName is Pyramid3", 0, 0);modified on Tuesday, April 14, 2009 12:35 PM
right, because you've assigned meshName to m_meshName, and i assume m_meshName is a string object of some kind, one with an overloaded "==" operator which knows how to compare a C-style (char*) string to its contents. (CString or std::string?) the problem with the first remains: you cannot compare a pointer to a static string. that's not how C-style strings work. and that's why strcmp exists.
image processing toolkits | batch image processing
modified on Tuesday, April 14, 2009 11:39 AM
-
The third condition here will result true, as does the second
if (meshName == "Pyramid3")
MessageBox(0, (char*)"meshName is Pyramid3", 0, 0);if (strcmp(meshName,"Pyramid3") == 0)
m_meshName = "Pyramid3";if (m_meshName == "Pyramid3")
MessageBox(0, (char*)"m_meshName is Pyramid3", 0, 0);modified on Tuesday, April 14, 2009 12:35 PM
The second comparison is the correct one. Two facts you need to know. 1/ m_meshName is a pointer to character. Underneath, it's an integer holding an address in RAM. 2/ The compiler has seen two constant strings in your code, but only bothers to store one copy of the string "Pyramid3" in it's data segment. So, the strcmp works as intended, and makes m_meshName point to the constant string in your code. The 3rd comparison works by luck, as m_meshName is still pointing to that string. This is because your compiler is being efficient, it is not because your code is correct. You are lucky. If this doesn't sink in (it's hard until you have a lightbulb moment), I can recommend reading The Complete Guide to C++ Strings, Part I - Win32 Character Encodings[^] Iain.
In the process of moving to Sweden for love (awwww). If you're in Scandinavia and want an MVP on the payroll (or happy with a remote worker), give me a job! http://cv.imcsoft.co.uk/[^]
-
right, because you've assigned meshName to m_meshName, and i assume m_meshName is a string object of some kind, one with an overloaded "==" operator which knows how to compare a C-style (char*) string to its contents. (CString or std::string?) the problem with the first remains: you cannot compare a pointer to a static string. that's not how C-style strings work. and that's why strcmp exists.
image processing toolkits | batch image processing
modified on Tuesday, April 14, 2009 11:39 AM
There's no overloading if his comments are right - they're char *'s. So, it's simpler than you thought... See http://www.codeproject.com/script/Forums/View.aspx?fid=1647&msg=3003509[^] for more. Iain.
In the process of moving to Sweden for love (awwww). If you're in Scandinavia and want an MVP on the payroll (or happy with a remote worker), give me a job! http://cv.imcsoft.co.uk/[^]
-
There's no overloading if his comments are right - they're char *'s. So, it's simpler than you thought... See http://www.codeproject.com/script/Forums/View.aspx?fid=1647&msg=3003509[^] for more. Iain.
In the process of moving to Sweden for love (awwww). If you're in Scandinavia and want an MVP on the payroll (or happy with a remote worker), give me a job! http://cv.imcsoft.co.uk/[^]
ah. you're right. i missed that comment.
-
The second comparison is the correct one. Two facts you need to know. 1/ m_meshName is a pointer to character. Underneath, it's an integer holding an address in RAM. 2/ The compiler has seen two constant strings in your code, but only bothers to store one copy of the string "Pyramid3" in it's data segment. So, the strcmp works as intended, and makes m_meshName point to the constant string in your code. The 3rd comparison works by luck, as m_meshName is still pointing to that string. This is because your compiler is being efficient, it is not because your code is correct. You are lucky. If this doesn't sink in (it's hard until you have a lightbulb moment), I can recommend reading The Complete Guide to C++ Strings, Part I - Win32 Character Encodings[^] Iain.
In the process of moving to Sweden for love (awwww). If you're in Scandinavia and want an MVP on the payroll (or happy with a remote worker), give me a job! http://cv.imcsoft.co.uk/[^]
Iain Clarke wrote:
If this doesn't sink in (it's hard until you have a lightbulb moment)
My lightbulb is on a dimmer switch... I think I understand what you are saying in your reply. I have just read Part 1, will follow up with Part 2 tomorrow, as it is 4.26am. If my understanding is correct I will be making a lot of changes to my application once I figure this out. Thank you both for your replies. :thumbsup: