Compiling an MFC GUI application as a DLL in VS2012 - c++

Is it possible to compile an MFC GUI EXE project into a DLL and then execute this DLL application from another application?
My progress so far is:
I changed "Configuration properties | General | Configuration type" to DLL
I added an exported function creating and running the application using this code:
theApp.m_hInstance = pModuleState->m_hCurrentInstanceHandle;
theApp.InitInstance();
theApp.Run();
I added code to DLLMain to initialize module state:
if (dwReason == DLL_PROCESS_ATTACH)
{
AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
pModuleState->m_hCurrentInstanceHandle = hInstance;
pModuleState->m_hCurrentResourceHandle = hInstance;
I created a console application that loads the DLL and calls the function creating and running the DLL application.
Yet, I'm still getting various debug assertions as, for example, AfxGetThread returns NULL, etc. And the application fails to run.
Can someone tell me if my idea of making DLL from EXE is realistic?
Thanks in advance.

Related

OCCI app crashes when running in debug mode in Visual Studio 2005

I'm attempting to get a development environment up and running for developing applications with Oracle C++ Call Interface (OCCI) in Visual Studio 2005.
My system specs are:
OS: Windows 7, 64-bit
Oracle: 11g release 11.2.0.2, 32-bit
Instant Client: BasicLite and SDK version 11.2.0.4 32-bit
Visual Studio 2005 Professional Edition version 8.0 with 32-bit tools enabled
I've followed this guide by Mark Williams and I got the example running but only in release mode. When I switch to debug mode the app will build, but when I run it I get the following error:
Problem signature:
Problem Event Name: APPCRASH
Application Name: OCCITest.exe
Application Version: 0.0.0.0
Application Timestamp: 53f5dfdd
Fault Module Name: KERNELBASE.dll
Fault Module Version: 6.1.7601.18229
The small example program that triggers this error is:
#include "employees.h"
using namespace std;
using namespace oracle::occi;
int main (void)
{
Employees *pEmployees = new Employees();
delete pEmployees;
return 0;
}
Employees::Employees()
{
user = "hr";
passwd = "hr";
db = "localhost:1521/service_name";
env = Environment::createEnvironment(Environment::DEFAULT);
try
{
con = env->createConnection(user, passwd, db);
}
catch (SQLException& ex)
{
cout << ex.getMessage();
exit(EXIT_FAILURE);
}
}
Employees::~Employees()
{
env->terminateConnection (con);
Environment::terminateEnvironment (env);
}
If I remove all calls to OCCI functionality the application doesn’t crash. That is, this program runs error-free:
#include "employees.h"
using namespace std;
using namespace oracle::occi;
int main (void)
{
Employees *pEmployees = new Employees();
delete pEmployees;
return 0;
}
Employees::Employees()
{
user = "hr";
passwd = "hr";
db = "localhost:1521/service_name";
cout<<"Look at me, I'm running"<<endl;
}
Employees::~Employees()
{}
In the guide Mark mentions that when running in debug mode, the linker should use the library file oraocci11d.lib. However, this file is not included in the Instant Client SDK version 11.2.0.4, so I’m using the input file oraocci11.lib for both the release and debug version.
I'm running out of ideas about how to proceed in solving this problem, and I would greatly appreciate any and all help.
If the Oracle DLL receives and/or passes objects such as std::string or any other object that either:
Manipulates the heap in any way, or
The objects could have differing internals between app and DLL,
then you have no choice but to use the correct library to link with. Otherwise you wind up with binary or heap incompatible objects being passed, which leads to what you're seeing now.
See here: http://docs.oracle.com/cd/E11882_01/appdev.112/e10764/install.htm#CBHGBBJI
The link above mentions both the debug import library and debug version of the DLL. Also this is stated at the link:
Applications that link to MSVCRTD.DLL, a debug version of Microsoft C-Runtime, /MDd compiler flag, should link with these specific OCCI libraries: oraocci11d.lib and oraocci11d.dll.
Since it took me quite some time to get the debug environment working I figured I'd answer my own question now that I did.
I got a variety of errors throughout the ordeal, but the error that I got most stuck on was an error saying:
'The application was unable to start correctly (0xc0150002).
Click OK to close the application.'
Also, I used http://www.dependencywalker.com which repeatedly told me that either oraocci11d.dll or a the following list of dll's could not be found.
API-MS-WIN-APPMODEL-RUNTIME-L1-1-0.DLL
API-MS-WIN-CORE-WINRT-ERROR-L1-1-0.DLL
API-MS-WIN-CORE-WINRT-L1-1-0.DLL
API-MS-WIN-CORE-WINRT-ROBUFFER-L1-1-0.DLL
API-MS-WIN-CORE-WINRT-STRING-L1-1-0.DLL
API-MS-WIN-SHCORE-SCALING-L1-1-1.DLL
DCOMP.DLL
IESHIMS.DLL
However, what was really missing was for the executable to be able to find oci.dll. I'm just mentioning the errors in case someone else runs into these.
Here is what was needed to make it work:
First of all, the Instant Client does not contain the oraocci11d.lib or oraocci11d.dll, so it is necessary to install the full Oracle Client.
Next, the following must be added to the PATH:
C:\Program Files\Oracle\11.2.0\OCI\lib\MSVC\vc8
C:\Program Files\Oracle\11.2.0\BIN
In Visual Studio, select Tools -> Options, unfold 'Projects and Solutions' and select VC++ Directories. In 'Show directories for' under:
Include Files add C:\Program Files\Oracle\11.2.0\OCI\include
Library files add C:\Program Files\Oracle\11.2.0\OCI\lib\MSVC\vc8
In the property page for your project under Configuration Properties -> Linker select Input and under Additional Dependencies add oraocci11d.lib (or oraocci11.lib for release mode). Then select debug/release mode in the Configuration Manager
I have a related problem in that I am successfully using oraocci12d.dll/msvcr100d.dll, but this in turn is using oci.dll/msvcr100.dll. ie, oci.dll is not using the debug version of msvcr100.
My program seems to run okay, but any memory leak reporting disappears on exit.

HRESULT "Class Not Registered" Implementing simple COM server DLL

I'm following this sites tutorial:
http://progtutorials.tripod.com/COM.htm
Preliminary evidence: Visual Studio 2010, Windows 7 64 bit.
and I'm coding the examples in section 3. (Implementing a server DLL). I've typed out the code exactly as shown and I'm getting a "Class not registered" exception when executing this code on line 12 of the code outlined in section 4.1 (where the tutorial shows you how to access the DLL and I have followed 3.1 to the letter):
hresult hr = CoGetClassObject(CLSID_Car, CLSCTX_SERVER, NULL, IID_IClassFactory, (void **) &pClassFactory);
I tried running:
regsvr32 xyz.dll
with xyz.dll being the path to my dll in order to register the DLL. This resulted in an error trying to find DLLRegisterServer:
I have already run
REGEDIT
HKEY_CLASSES_ROOT\CarDLL.Car\CLSID = {d969084c-b758-43ea-a218-a48763167abd}
HKEY_CLASSES_ROOT\CLSID\{d969084c-b758-43ea-a218-a48763167abd} = CarDLL.Car
HKEY_CLASSES_ROOT\CLSID\{d969084c-b758-43ea-a218-a48763167abd}\InProcServer32 = C:\Users\wiocl2\Documents\Visual Studio 2010\Projects\CarDLL\debug\CarDLL.dll
that I assumed put all the GUIDS I needed in the registry (The GUIDS were generated by me).
I'm assuming that a function is needed to be added to the class that allows it to be registered but I don't know how to do this and how to go about figuring it out. I'm kind of lost, as I haven't been working with COM for very long. If someone could give me a shove in the right direction that would be helpful.
Edit: Oh yes, I moved
#include // contains definition of DEFINE_GUID
to the iid.h file from iid.cpp, otherwise I was getting unresolved external errors on the build.
The most likely explanation: you are building your COM object as a 32-bit DLL, but the registration has been performed as a 64-bit DLL.
The treatment: open an admin privileged command window and navigate to the location of your DLL (C:\Users\wiocl2\Documents\Visual Studio 2010\Projects\CarDLL\debug). Once there, type:
c:\windows\sysWOW64\regedit <filename of .reg file whose contents are displayed above>
This will run the 32-bit version of REGEDIT, ensuring that the registry entries are created in the correct part of the hive. To verify this, you should see an entry for {d969084c-b758-43ea-a218-a48763167abd} in HKLM\Software\Wow6432Node\Classes\CLSID, not HKLM\Software\Classes\CLSID.
DllRegisterServer is a method you can implement in your COM server DLL, and is required if you want to use regsvr32 to perform the same operation you are currently using the .REG approach for. The same caveat applies: for a 32-bit DLL, you'll need to invoke c:\windows\sysWOW64\regsvr32.exe.
And Yes! COM is still mostly alive and well :) At least there is still standard support for it in VS 2012.
Hope that helps.

How to release DotNet Assembly loaded in C++

I have the following code in a C++ DLL. It loads and invokes a method in a DotNet DLL built with C#.
Assembly^ a = Assembly::LoadFrom(gcnew String("MyDotNet.dll"));
Type^ type = a->GetType("MyAssemply.Assembly");
MethodInfo^ method = type->GetMethod("MyMethod");
Object^ obj = Activator::CreateInstance(type);
array<Object^>^ params = gcnew array<Object^>(0) { };
Object^ ret = method->Invoke(obj, params);
The problem is that it does not appear to release the resources or DLL even when I do a FreeLibrary on the C++ DLL. Is there a API or Method I need to call to release the DLLs/resources?
I am using Visual Studio 2010.
Thanks.
You can't unload a managed assembly from an app pool. You can create another app pool and unload that.
This post is related: How to unload an assembly from the primary AppDomain?

OLE/COM Object Viewer reports STG_E_FILENOTFOUND

I have created simple COM DLL using ATL and have added "ATL Simple Object" after that. To be sure server is registering I have placed messagebox:
STDAPI DllRegisterServer(void)
{
MessageBoxA ( NULL, "Hello World!", "Test", MB_OK );
HRESULT hr = _AtlModule.DllRegisterServer();
return hr;
}
Registering does fine. I decided to look how this object looks with OLE-COM Object Viewer that is part of SDK. Viewer reports error:
"LoadTypelib'(c:\pr\ILight.dll) failed.
<No system message defined> STG_E_FILENOTFOUND ($800300002)
Does it means my COM dll corrupted? How to make VIewer to show my dll information?
P.S.
Project RC file contians:
"REGISTRY"
IDR_ILIGHT
HKCR{}
IDR_LIGHT
HKCR
{
AboutiLight.1 = s 'Light Class'
{
CLSID = s '{DBC53EA8-A51E-4374-B104-06A834273B0C}'
}
AboutiLight = s 'Light Class'
{
CurVer = s 'AboutiLight.1'
}
NoRemove CLSID
{
ForceRemove {DBC53EA8-A51E-4374-B104-06A834273B0C} = s 'Light Class'
{
ProgID = s 'AboutiLight.1'
VersionIndependentProgID = s 'AboutiLight'
ForceRemove Programmable
InprocServer32 = s '%MODULE%'
{
val ThreadingModel = s 'Apartment'
}
TypeLib = s '{1D9F859D-10FF-4827-A341-4A8B8E318A61}'
Version = s '1.0'
}
}
}
String table
String table
ID=IDS_PROJNAME Value=100 Caption ILight
Version
VS_VERSION_INFO
FILEVERSION 1,0,0,1
PRODUCTVERSION 1,0,0,1
FILEMASK 0x3fL
FILEFLAGS 0x0L
FILEOS VOS_NT_WINDOWS32
FILETYPE VFT_DLL
FILESUBTYPE VFT2_UNKNOWN
After having received the same error (STG_E_FILENOTFOUND), and seeing Joe Willcoxson's comment about 64-bit and 32-bit, I was able to find a solution.
If you are using OleView.exe, the OLE/COM Object Viewer, there are actually two versions of it: 32-bit, and 64-bit. Ensure that you are launching with the proper version of OleView. The version in the base "BIN" folder of the SDK will be the 32-bit version. The "x64" folder will have the 64-bit version of the application, which is not fully compatible with older binaries and their typelibs (made in a 32-bit world).
On the other hand, if your new DLL is actively being compiled for x64, then it's highly likely 32-bit OleView will not be able to read the data properly, either.
1) Check to make sure that is the right path to your DLL.
2) Open the DLL itself from Visual Studio and check to be sure that a type library is embedded in the resources. If a typelib isn't found, add one.
3) If all that fails, did you register it under an administrator account/shell. If you call regsvr32.exe on it, make sure you are running with elevated privileges.

Starting a hidden C++ program

I am creating a C++ program with Visual Studio 2010 that is supposed to run on the background of my machine.
Therefore when I start it, I shouldn't see the CMD screen while it is running. How can I do this? Do I have to use the Win32 API or a normal C++ program will suffice?
Please note that my program has no GUI at all.
Use WinMain() :
#include <windows.h>
int WINAPI WinMain(HINSTANCE inst,HINSTANCE prev,LPSTR cmd,int show)
{
// program starts here
return 0;
}
// int main() <-- remove main()
Then ake sure your project settings are set so that you build a "Win32" program and not a "Console" program.
Edit: As #Sehe points out, winMain may not be necessary, although I am not quite sure where this option lies.
Run it as a service See here.
Very often a program running under Windows without a "face" (eg, with no user interface at all) is implemented as a Service.
In windows, Daemon programs are implemented as Services.
Simply make it a GUI application instead of a command line application. Right click the project -> Properties -> Configuration Properties -> Linker -> System -> SubSystem -> Windows (/SUBSYSTEM:WINDOWS).
You can run as a Windows process (which doesn't attach to a console), but never create a window. the main difference is the signature of WinMain, and the flags to the compiler.
Go to File -> New Project, select the standard Windows Application, then delete everything except WinMain.