Data of struct lose after passed from OCX to dll as a parameter of function - dll

In my MFC ActiveX program, there is a calling of function offered by a dll file. And there is a struct type parameter in the function. The strange thing I met is after calling the function, the data in struct is not complete. I am a newer of ActiveX and DLL, and really can't understand how can this happened... The main codes are below:
The defination of struct:
typedef struct{
WORD m_protocol;
WORD m_playstart;
...
char url[128];
char username[MAX_USER_NAME_LEN+1];
char password[MAX_PASSWORD_LEN+1];
}CHANNEL_CLIENTINFO;
The ActiveX codes:
CHANNEL_CLIENTINFO channelInfo;
...
...
GSNET_ClientStart(&channelInfo);
The dll codes:
GSNET_ClientStart(CHANNEL_CLIENTINFO *m_pChaninfo)
{
...
...
}
Can anyone help me? Thanks all.
for more details:
In ActiveX program, before call the GSNET_ClientStart, I initialize the struct with some date. Such as the 'url':
sprintf(channelInfo.url, "192.168.121.122");
And after the calling, in dll function GSNET_ClientStart, I get out the url, it turns out to be "168.121.122", the "192." is missing.
I can make sure that I did't make any mistake in basic grammar.

There is a layout mismatch between the struct definitions in your two modules. It seems that the offset to the url member in your DLL has an offset of 4 more than the offset to that field in your ActiveX.
Make sure that the struct definitions match in both modules. Make sure that the compiler options relating to struct layout are the same in both modules.
I cannot give a definitive fix because there are so many ways in which this mismatch could occur, but for sure the root problem is a mismatch.

Related

NSErrorDomain + NS_ERROR_ENUM makes type lookup ambiguous. Why?

I have an error that used to look like this in Objective-C
NSString * const JKConfigurationErrorDomain;
typedef NS_ENUM(NSInteger, JKConfigurationCode) {
JKConfigurationCodeUnknown,
JKConfigurationCodeSomethingBad,
JKConfigurationCodeParsing,
};
Now, this is ugly to use in Swift. But since Swift 4, we can use NSErrorDomain and NS_ERROR_ENUM to make the imported error much nicer in Swift:
NSErrorDomain const JKConfigurationErrorDomain;
typedef NS_ERROR_ENUM(JKConfigurationErrorDomain, JKConfigurationCode) {
JKConfigurationCodeUnknown,
JKConfigurationErrorSomethingBad,
JKConfigurationErrorParsing,
};
This means I can now do stuff in Swift like this:
if let myError = error as? JKConfigurationError, myError.code = .somethingBad {
// handle it
}
instead of having to cast error to NSError, then check its .domain then look at the .code which is an integer, etc.
So far, so good. But my library is called JKConfiguration and there is already a JKConfiguration object (the center piece of the library) in there and as soon as I start using JKConfiguration anywhere in the library code I get an error:
'JKConfiguration' is ambiguous for type lookup in this context
I don't get it, why? What does NSErrorDomain or NS_ERROR_ENUM do such that the type lookup becomes ambiguous and how can I fix it?
What I tried already:
use NS_SWIFT_NAME on the NS_ERROR_ENUM typedef and rename it to something else. Looking at the generated Swift header, the rename works, but doesn't solve the issue
Change the name of the error domain (and thus of the generated error type in Swift). Seems to work according to the generated Swift header, but the issue still persists. Why is that?
The issue is not, as I initially thought, in the name of the error domain. Nor is it a problem with the library name. It’s a problem of the error enum‘s name, in the example above: JKConfigurationCode.
What the Compiler does for the enum cases of an NS_ERROR_ENUM is two-fold:
use the name of the enum and remove that prefix from all enum cases before importing them to swift
create an enum with the given name to hold those cases. If the given name ends with Code remove that suffix.
So that last part is the issue. It means that NS_ERROR_ENUM(AnyDomainName, JKConfigurationCode) generates an enum in Swift to hold the error codes with the name JKConfiguration (without the Code) prefix. But that type already exists in my example, which leads to the ambiguity.
So the solution is to change
NS_ERROR_ENUM(JKConfigurationErrorDomain, JKConfigurationCode)
to
NS_ERROR_ENUM(JKConfigurationErrorDomain, JKConfigurationSomethingCode)
Or similar.
Don’t forget to update all the prefixes of your enum cases though, as it seems the compiler won’t find them if the prefixes don’t match the enum name.
Why doesn’t NS_SWIFT_NAME work to rename the enum?
Best I can tell, NS_SWIFT_NAME causes the type to be renamed but not the cases. This leads to an empty type (Swift chooses a struct in that case) being generated for the error code as Swift doesn’t seem to find the cases. And the original container for the enum cases still has the offending name.

C++/CLI Console::WriteLine with Vector of User Defined Objects

I have a vector of User Defined Objects and I want to simply output some of the class members (fields?) to the console, but when I try, the program crashes. I have tried to display the 'EmployeeID' directly (it's an Int), as well as converting it to a System::String, and a std::string, using several methods for each (marshalling, converting to char array, etc).
std::vector<Employee> employee;
System::Console::WriteLine("Employee ID: " + employee.at(i).getEmployeeId());
I am at a loss as to why I can not simply print to the console, but I'm quite new to CLI, so maybe it's an easy fix and a simple mistake? I have the same issue with other variables stored in the employee object, those other items are std::string type.
I would prefer to use System::String instead of std::string for those other members, but when I do that I get a weird error message ("A member of a non-managed class cannot have a ref class type or interface class type"). Any help with either issue would be great, but this post is specifically for the Console::WriteLine problem.
as per #Ben Voight's suggestions:
Changing my class to a "ref" class and all of my std::string items to System::String^ items has worked.
(It did cause other issues with my code, but that's a different problem and is not related to the the fact that his answer/solution fixed this specific question/problem.)

Casting System::IO::FileStream^ to FILE*

I am working on refactoring a large amount of code from an unmanaged C++ assembly into a C# assembly. There is currently a mixed-mode assembly going between the two with, of course, a mix of managed and unmanaged code. There is a function I am trying to call in the unmanaged C++ which relies on FILE*s (as defined in stdio.h). This function ties into a much larger process which cannot be refactored into the C# code yet, but which now needs to be called from the managed code.
I have searched but cannot find a definitive answer to what kind of underlying system pointer the System::IO::FileStream class uses. Is this just applied on top of a FILE*? Or is there some other way to convert a FileStream^ to a FILE*? I found FileStream::SafeFileHandle, on which I can call DangerousGetHandle().ToPointer() to get a native void*, but I'm just trying to be certain that if I cast this to FILE* that I'm doing the right thing...?
void Write(FILE *out)
{
Data->Write(out); // huge bulk of code, writing the data
}
virtual void __clrcall Write(System::IO::FileStream ^out)
{
// is this right??
FILE *pout = (FILE*)out->SafeFileHandle->DangerousGetHandle().ToPointer();
Write(pout);
}
You'll need _open_osfhandle followed by _fdopen.
Casting is not magic. Just because the input and types output are right for your situation doesn't mean the values are.

How to pass a struct parameter using TCOM in Tcl

I've inherited a piece of custom test equipment with a control library built in a COM object, and I'm trying to connect it to our Tcl test script library. I can connect to the DLL using TCOM, and do some simple control operations with single int parameters. However, certain features are controlled by passing in a C/C++ struct that contains the control blocks, and attempting to use them in TCOM is giving me an error 0x80020005 {Type mismatch.}. The struct is defined in the .idl file, so it's available to TCOM to use.
The simplest example is a particular call as follows:
C++ .idl file:
struct SourceScaleRange
{
float MinVoltage;
float MaxVoltage;
};
interface IAnalogIn : IDispatch{
...
[id(4), helpstring("method GetAdcScaleRange")] HRESULT GetAdcScaleRange(
[out] struct SourceScaleRange *scaleRange);
...
}
Tcl wrapper:
::tcom::import [file join $::libDir "PulseMeas.tlb"] ::char
set ::characterizer(AnalogIn) [::char::AnalogIn]
set scaleRange ""
set response [$::characterizer(AnalogIn) GetAdcScaleRange scaleRange]
Resulting error:
0x80020005 {Type mismatch.}
while executing
"$::characterizer(AnalogIn) GetAdcScaleRange scaleRange"
(procedure "charGetAdcScaleRange" line 4)
When I dump TCOM's methods, it knows of the name of the struct, at least, but it seems to have dropped the struct keyword. Some introspection code
set ifhandle [::tcom::info interface $::characterizer(AnalogIn)]
puts "methods: [$ifhandle methods]"
returns
methods: ... {4 VOID GetAdcScaleRange {{out {SourceScaleRange *} scaleRange}}} ...
I don't know if this is meaningful or not.
At this point, I'd be happy to get any ideas on where to look next. Is this a known TCOM limitation (undocumented, but known)? Is there a way to pre-process the parameter into an appropriate format using tcom? Do I need to force it into a correctly sized block of memory via binary format by manual construction? Do I need to take the DLL back to the original developer and have him pull out all the struct parameters? (Not likely to happen, in this reality.) Any input is good input.

function in dll doesn't receive CString argument value

Hi everyone.
I have to work with old utility: which converts xls into txt.
There was a small problem in logic of the utility, but the problem is in other thing...
The utility consists of two parts: exe module and dll module, and uses MFC.
In exe project we have
pInit = (t_bXR_Init)GetProcAddress(hExcel, _T("bXR_Init"));
and
pInit("logfiles",false);
In dll project we have
typedef bool (*t_bXR_Init) (CString const &strlogfilespath, bool btxtfile);
XLSREADER_API bool bXR_Init(CString const &strlogfilespath, bool btxtfile);
The problem is when we send argument "logfiles" into the function it doesn't get it. It's strange, 'cause all other parameters are send properly.
The reason is somehow connected with using of CString. But I don't know how...
XLSREADER_API is defined as:
#define XLSREADER_API extern "C" __declspec(dllimport)
Also I've added
AFX_MANAGE_STATE(AfxGetStaticModuleState());
in the beginning of function's body (for bXR_Init). But it didn't help.
Also I tried to change some settings for these two projects, all settings are the same (e.g. calling conversion is __cldecl(/Gd); I build either debug versions exe and dll or release version of exe and dll simultaneously).
Also I tried to use CString instead of CString& - the same situation. It works properly if use char*, but boss says to find what the origin of the problem is at first.
What may lead to the problem (the function doesn't get CString parameter)?
To pass a complex type such as a CString across a DLL boundary you have to make sure that both the DLL and the exe are using the exact same DLL libraries. Set "Runtime Library" to multi-threaded DLL and set "Use of MFC" to Use MFC in a Shared DLL. Also, don't mix debug and release modules: Both must be the same.
Without these conditions you get two different heaps, and you can't keep the allocations/deletions compatible with two heaps.
Try passing an actual CString parameter to the call:
CString sPath = "logfiles";
pInit(sPath,false);
wtfigo! (what the f is going on)
the problem is solved.
I discovered, that exe project had "character set" = "use multibyte character set"
and dll project had "character set" = "use unicode character set".
So, dll function got CString with char* inside, but considered it as CString with wchat_t* inside. And it looked as garbage (as complete garbage on my pc and as chinese symbols on my workmate's pc).
I changed "character set" for exe project to "use unicode character set" and discovered about 60 errors.
Then I read an article http://habrahabr.ru/post/164193/ (in russian; or in english: http://www.codeproject.com/Articles/76252/What-are-TCHAR-WCHAR-LPSTR-LPWSTR-LPCTSTR-etc).
And fixed all errors, widely used macroses from TCHAR.h (MSDN helped me).
Thanks everybody for your help.