vc++ problem in situation export/import global variables in dlls - visual-c++

Precondition
environment : VC2005
I encountered this problem when discovered circular dependency in my project(two dll references each other), so divide either of one dll to two dll's.
explain with example :
typedef struct { <br>
char myFileName[MAX_PATH];
} MyStructure;
Before :
MyHeader.h
MyStructure globalStruct;
After:
MyCommon.h
#ifdef _MYGLOBAL_
#define API __declspec(dllexport)
#else
#define API __declspec(dllimport)
#endif
API extern MyStructure globalStruct;
MyGlobal.c
API MyStructure globalStruct;
MySpecific.c
API MyStructure globalStruct;
failed code after changed: (this code run in specific dll)
handle = LoadLibrary(globalStruct.myFileName);
I confirmed globalStruct.myFileName values are same(at lease real words).
I can't access the value directly with debugger after changed. so, to see value in debugger, I copyed to temp local char[] variable. And then, I found before value and after value are different in tailing dummy char's.
before:
d:[my path] '0'(char end null) '0' '0' ...
after:
d:[my path] '0'(char end null) '-3' '-3' '-3' ...
thank you for your reading.

self-solved my problem.
This is because dll does not re-compiled after my circular dependency removal work.
So, this problem is not related import/export global variable but dll re-compile issue.
Sorry for my ugly question.

Related

Is the packing of structs passed in COM interfaces defined?

I'm working with a third party COM server with its own custom interface that sets and gets structs as some of its properties. As it happens I'm using C++ for the client. I've posted some representative code from the IDL file below with names changed and GUIDs removed.
Is the packing of the structure defined or is it just good fortune that my client code happens to use the same packing settings that the COM server was built with? Would it be likely to go wrong in projects where the default C++ compiler packing settings had been changed? Is there a pragma pack setting that I could use to make sure the client compiler packing settings are correct?
I can't see any packing pragmas or statements in either the IDL or the header file generated from MIDL. What would happen if the client was in C# or VB instead? Is the packing behaviour more clearly specified if called via the IDispatch mechanism?
struct MyStruct
{
int a, b;
};
[
object,
uuid( /* removed */ ),
dual,
nonextensible,
pointer_default(unique)
]
interface IVideoOutputSettings : IDispatch{
[propget, id(1), HRESULT MyProperty([out, retval] struct MyStruct* pVal);
[propput, id(1), HRESULT MyProperty([in] struct MyStruct newVal);
/* other methods */
};
The default packing is along 8-byte boundaries, according to the MIDL command line switch reference here:
/Zp switch # MSDN (MIDL Language Reference)
Other parts of your code are more likely to break first if the pack value is changed, as the IDL file is usually pre-compiled ahead of time, and it is rare that someone will deliberately alter the command line switches given to MIDL (but not so rare that someone could fiddle with the C-scope #pragma pack and forget to restore the default state).
If you have a good reason to alter the setting, you can explicitly set the packing with a pragma pack statement.
pragma Attribute # MSDN (MIDL Language Reference)
It is pretty good fortune that no party has changed any setting that would interfere with the default packing. Can it go wrong? Yes, if someone goes out of their way to change the defaults.
When using an IDL file, the details are typically compiled into a typelib (.tlb), and it is assumed that the platform are the same for both servers and clients when using the same typelib. This is suggested in the footnotes for the /Zp switch, as certain values will fail against certain non-x86 or 16-bit targets. There can also be 32bit <-> 64bit conversion cases that could cause expectations to break. Unfortunately I don't know if there are even more cases out there, but the defaults do work with minimal fuss.
C# and VB do not have any intrinsic behavior to handle information in a .tlb; instead, a tool like tlbimp is typically used to convert COM definitions into definitions usable from .NET. I can't verify whether all expectations succeed between C#/VB.NET and COM clients and servers; However, I can verify that using a specific pragma setting other than 8 will work if you reference a .tlb that was created from an IDL compiled under that setting. While I wouldn't recommend going against the default pragma pack, here are the steps to perform if you'd like a working example to use as a reference. I created a C++ ATL project and a C# project to check.
Here are the C++ side instructions.
I created an ATL project called SampleATLProject with the default settings in Visual Studio 2010, no fields changed. This should create a dll project for you.
Compiled the project to assure that the proper C-side interface files are being created (SampleATLProject_i.c and SampleATLProject_i.h).
I added an ATL Simple Object called SomeFoo to the project. Again, no defaults were altered. This creates a class called CSomeFoo that is added to your project.
Compile SampleATLProject.
I right-clicked the SampleATLProject.idl file, then under the MIDL settings, set the Struct Member Alignment to 4 bytes (/Zp4).
Compile SampleATLProject.
I altered the IDL to add a struct definition called 'BarStruct'. This entailed adding a C-style struct definition with the MIDL uuid attribute, and an entry in library section referencing the struct definition. See snippet below.
Compile SampleATLProject.
From the Class View, I right-clicked on ISomeFoo and added a method called FooIt, that takes a struct BarStruct as an [in] parameter called theBar.
Compile SampleATLProject.
In SomeFoo.cpp, I added some code to print out the size of the struct and throw up a Message Box containing the details.
Here is my IDL for the ATL project.
import "oaidl.idl";
import "ocidl.idl";
[uuid(D2240D8B-EB97-4ACD-AC96-21F2EAFFE100)]
struct BarStruct
{
byte a;
int b;
byte c;
byte d;
};
[
object,
uuid(E6C3E82D-4376-41CD-A0DF-CB9371C0C467),
dual,
nonextensible,
pointer_default(unique)
]
interface ISomeFoo : IDispatch{
[id(1)] HRESULT FooIt([in] struct BarStruct theBar);
};
[
uuid(F15B6312-7C46-4DDC-8D04-9DEA358BD94B),
version(1.0),
]
library SampleATLProjectLib
{
struct BarStruct;
importlib("stdole2.tlb");
[
uuid(930BC9D6-28DF-4851-9703-AFCD1F23CCEF)
]
coclass SomeFoo
{
[default] interface ISomeFoo;
};
};
Inside the CSomeFoo class, here is the implementation for FooIt().
STDMETHODIMP CSomeFoo::FooIt(struct BarStruct theBar)
{
WCHAR buf[1024];
swprintf(buf, L"Size: %d, Values: %d %d %d %d", sizeof(struct BarStruct),
theBar.a, theBar.b, theBar.c, theBar.d);
::MessageBoxW(0, buf, L"FooIt", MB_OK);
return S_OK;
}
Next, on the C# side:
Go to the debug or desired output directory for SampleATLProject and run tlbimp.exe on the .tlb file generated as part of the C++ project output. The following worked for me:
tlbimp SampleATLProject.tlb /out:Foo.dll /namespace:SampleATL.FooStuff
Next, I created a C# console application, and added a reference to Foo.dll to the project.
In the References folder, go to the Properties for Foo and turn off Embed Interop Types by setting it to false.
I added a using statement to reference the namespace SampleATL.FooStuff as given to tlbimp, added the [STAThread] attribute to Main() (the COM apartment models have to match for in-proc consumption), and added some code to call the COM component.
Tlbimp.exe (Type Library Importer) # MSDN
Here is the source code for that console app.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SampleATL.FooStuff;
namespace SampleATLProjectConsumer
{
class Program
{
[STAThread]
static void Main(string[] args)
{
BarStruct s;
s.a = 1;
s.b = 127;
s.c = 255;
s.d = 128;
ISomeFoo handler = new SomeFooClass();
handler.FooIt(s);
}
}
}
Finally, it runs and I get a modal popup with the following string displayed:
Size: 12, Values: 1 127 255 128
To be sure that a pragma pack change can be made (as 4/8 byte packing are the most common alignments used), I followed these steps to change it to 1:
I returned to the C++ project, went to the properties for SampleATLProject.idl and changed the Struct Member Alignment to 1 (/Zp1).
Recompile SampleATLProject
Run tlbimp again with the updated .tlb file.
A warning icon will appear on the .NET File Reference to Foo, but may disappear if you click on the reference. If it doesn't, you can remove and re-add the reference to the C# console project to be sure it is using the new updated version.
I ran it from here and got this output:
Size: 12, Values: 1 1551957760 129 3
That's weird. But, if we forcefully edit the C-level pragma in SampleATLProject_i.h, we get the correct output.
#pragma pack(push, 1)
/* [uuid] */ struct DECLSPEC_UUID("D2240D8B-EB97-4ACD-AC96-21F2EAFFE100") BarStruct
{
byte a;
int b;
byte c;
byte d;
} ;
#pragma pack(pop)
SampleATLProject is recompiled here, no changes to the .tlb or .NET project, and we get the following:
Size: 7, Values: 1 127 255 128
Regarding IDispatch, it depends on whether your client is late-bound. Late-bound clients have to parse the type information side of IDispatch and discern the proper definitions for non-trivial types. The documentation for ITypeInfo and TYPEATTR suggests that it is possible, given that the cbAlignment field provides the information necessary. I suspect most will never alter or go against the defaults, as this would be tedious to debug if things went wrong or if the pack expectations had to change between versions. Also, structures are not typically supported by many scripting clients that can consume IDispatch. One can frequently expect that only the types governed by the IDL oleautomation keyword are supported.
IDispatch interface # MSDN
IDispatch::GetTypeInfo # MSDN
ITypeInfo interface # MSDN
TYPEATTR structure # MSDN
oleautomation keyword # MSDN
Yes, structs are a problem in COM. If you use IUnknown based interfaces then you'll have to roll the dice with proper compiler settings. Few reasons to change the default.
If you use COM Automation then you have to declare the struct with a typedef in the .IDL. So that the client code can use IRecordInfo to access the structure properly, guided by the type library info. All you have to do is ensure that your compiler's /Zp setting matches midl.exe's /Zp setting. Not hard to do.
You sail around the problem entirely by realizing that any structure can be described by an interface with properties. Now it doesn't matter.

Use a supplied dll in Visual C++ project

I just bought a device that comes with a dll file. I want to use Visual C++ to program the device. How do I load the .dll file into my project?
A DLL is a library file that contains compiled program logic, just like an EXE. You can't execute it alone, but like an EXE file you can't just 'load' it into your project either.
You will need to use functions like Load Library to load the library, and then GetProcAddress to find a function you want to call.
Edit:
After you clarified your question in the comments you are trying to write a windows program instead of a program you run on your device.
I wrote some sample code to show you how to start:
#include <windows.h> // This is a windows header file. The functions I mentioned above are declared here
#include "mpusbapi.h" // This is the header file supplied. It declares the function prototypes that are defined in the DLL
int main(int argc, char* argv)
{
// Try to load the library
HMODULE mpbusDLL = NULL;
mpbusDLL = LoadLibrary(L"mpusbapi.dll");
if (mpbusDLL != NULL) {
// If the library could be loaded, then load the functions using GetProcAddress()
// Load the function 'MPUSBOpen' from the DLL
MPUSBOpen = (HANDLE(*)(DWORD, PCHAR, PCHAR, DWORD, DWORD)) GetProcAddress(mpbusDLL, "_MPUSBOpen");
...
MPUSBOpen(...);
}
}
This C code will load your libary and then attempt to load the function MPUSBOpen, which is implemented in your DLL.
You will need to load the other functions defined in your header file the same way (at least if you want to use them).

VC++: Using DLLs as "subprograms"

So I just began to try my hand at emulation after years of putting it off and not knowing where to start and I have managed to successfully write my first emulator! Now I am organizing my code in so that I can reuse the code to emulate other systems. I've been toying with the idea of having a shared frontend "platform handler" of sorts that I will compile as my executable whereas I will compile my emulated system code into dlls that the platform handler will use to identify what is available and instantiate from. This would allow me to separate my code into different projects and to leave the option open of using a bulkier front-end with more features or a streamlined "game only" and to share the same dlls between them rather than make two different solutions.
I know how to compile dlls vs executables but I don't know how to link the executable to the custom dll in such a way that I can instantiate a class from it. I'm not even sure what I'm trying to do is technically possible. Do the dll classes need to be static? I've never coded anything like this before or even done much with custom dlls so any help or ideas would be appreciated. I'm using Visual C++ 2010 by the way. Thanks in advance for any advice anyone may have.
You don't really have to do much different. Just export your classes from the dll like you do for functions. In your app, include the header and link to the generated lib like you usually do. See this page: http://msdn.microsoft.com/en-us/library/81h27t8c%28v=vs.80%29.aspx
Example.h
#ifdef DLL_EXPORT
#define EXPORT_API __declspec(dllexport)
#else
#define EXPORT_API __declspec(dllimport)
#endif
class EXPORT_API Example
{
public:
Example();
~Example();
int SomeMethod();
};
int EXPORT_API ExampleFuncion();
Example.cpp
#include "Example.h"
Example::Example()
{
// construct stuff
}
Example::~Example()
{
// destruct stuff
}
int Example::SomeMethod()
{
// do stuff
return 0;
}
int EXPORT_API ExampleFunction()
{
return 0;
}
In your dll project, define DLL_EXPORT and build. You will get a .lib and .dll output. In your main project where you will be using the dll you do not have to do anything except include the header and link against the .lib. Do not define the DLL_EXPORT symbol in your main project and be sure the .dll is somewhere your application can find it.
If you really want to get clever, this problem is screaming for the factory design pattern. If you design your interface well enough, you can have your dlls register their implementation with your application when they are loaded. You can extend forever without even rebuilding your main executable.

Will the linker compare the access level when finding a member function at linking time?

Accidently, I encounter a linking error.
The program is somewhat like this:
//a.h
class A
{
int a;
#ifdef AAA
public:
#endif
int getA();
}
//a.cpp
include "a.h"
int A::getA()
{
return a;
}
//test.cpp
#include "a.h"
int main()
{
A a;
a.getA();
return 0;
}
These three files are in two project, a.h and a.cpp in a project A in which the AAA macro is undefined, test.cpp in a project Test in which AAA macro is defined. And project Test denpends on project A.
Then I encounter a link error. I did this test on visual studio 2008.
So my question is this:"Will the link compare the access level when finding a member function symbol at linking time?"
In my previous opinion, the access level only take effect in compilation. But in this case,
it seems that the access level may also make effect in linking time.
The linker is innocent. C++ compilers mangel names and incorporates things as access modifiers, overloads (i.e. return and argument types), template(? not quite sure) etc... in the final to produce something unambigious that also forms whatever the linker considers a valid identifier (at least [a-zA-Z_][a-zA-Z0-9_]*, as C requires no mangling). The linker only sees that mangled name, and it can't report anything except "you call this function but it's not defined anywhere". public A::getA() a different name as private A::getA().
The solution? Don't use the preprocessor for such batshit things. Or convince the VS developers to intercept such error messages and translate them into something more meanignful (but since they didn't in the past and sane code rarely encounters this problem, that's unlikely).

How to disable warnings 4510 and 4610 from std::list class?

I have a bunch of warnings C4510 and C4610 when I use std::list with my class. It is a warning stating that default constructor is not available, and I want to disable them.
When I put:
#pragma warning(disable: 4510)
inside .cpp file that is instantiating this list nothing happens.
I tried placing this pragmas around function where I instantiate lists and even on top of the .cpp file but the results are the same - nothing happens. It only works if I disable warnings in properties dialog of .cpp file. I hate hiding stuff in properties like that because they get overlooked by developers. I would like to have them localized around the function. Is there something I could do about this?
EDIT:
Ok. This is how my code basically looks like. This code generates warnings 4510 and 4610 on warning level 4:
#include <list>
class foo {
public:
foo(int) { }
};
class bar {};
class problem_class {
foo m_foo;
const bar *m_bar;
public:
problem_class(const foo &_foo, const bar *_bar) : m_foo(_foo), m_bar(_bar) { }
};
void problem_fn(std::list<problem_class> &problem_collection) {
foo _foo(3);
problem_collection.clear();
problem_collection.push_back(problem_class(_foo, new bar));
}
int main(int , char **)
{
std::list<problem_class> collection;
problem_fn(collection);
return 0;
}
Instead of hiding the problem by disabling warnings, how about wrapping your class w/o a default constructor in a proxy class that does have a default constructor*. The proxy's default constructor can then do the proper initialization of the wrapped class. Then store the proxy class in the std::list. This would make your intent clear and eliminate the warning.
*assuming you can't for whatever reason actually make the wrapped class have an appropriatte default constructor.
Include #pragma before including <list>
#pragma warning (disable:4510)
#pragma warning (disable:4610)
#include <list>
You need to post some code that illustrates exactly what you are doing. Warning C4510 says:
The compiler cannot generate a default
constructor for the specified class
and no user-defined constructor was
created. You will not be able to
create objects of this type.
This doesn't seem to have anything to do with std::list, so it maybe that there is something wrong with your code.
I know this is not very helpful, but the code you posted looks fine to me and compiled with no warnings with g++ and comeau. I don't use VC++ anymore, so can't reall help further, I'm afraid.
Further Edit: Purely in the spirit of experimentation, what happens if you change:
const bar *m_bar;
to
bar *m_bar;
The MSDN docs for this warning say that:
There are several situations that
prevent the compiler from generating a
default constructor, including:
* A const data member.
Now the m_bar member isn't const (the thing it points to is) but I wonder if the compiler is a little confused about this.
#pragma warning (disable : 4510 4610)
#pragma warning (push, 3)
#include <list>
#pragma warning (pop)
#pragma warning (default : 4510 4610)
Ok, found it.
My project uses precompiled headers so in some header file that is included from StdAfx.h someone included list. When I added #pragma directives on top of the StdAfx.h everything worked. The thing that confused me is that when I added #pragma in .cpp file in front of
#include "StdAfx.h"
nothing worked (warnings were still displayed). Since list was included in precompiled headers, it had the same warning settings no matter what the .cpp file specified later on.
But, the strange thing is that even if I could not override settings in .cpp file, I could override them by specifying compile properties for that same file. How is that any different?

Resources