I am implementing a COM component
import "unknwn.idl";
[
uuid(CF86E2E0-B12D-4C6A-9C5A-D7AA65101E91),
]
coclass CClassic
{
[default] interface IClassic;
}
[
object,
uuid(CF86E2E0-B12D-4C6A-9C5A-D7AA65101E90),
pointer_default(unique),
oleautomation
]
interface IClassic : IUnknown
{
HRESULT Hello();
}
and encapsulated it in an in-process dll and an out-of-process exe respectively.
In the dll case , I can call the interface method successfully.
But in the exe case, got the 80040154 error. Following this doc, I registered the proxy and checked the registry, all the needed registry keys/values are there.
How does this happen? I doubt something is missing in the above idl file. Many thanks!!!
Update
comexe.cpp
#include <atlbase.h>
#include <atlcom.h>
/*
cl /nologo /EHsc comexe.cpp comobj.cpp classic/classic_i.c /link /debug
cl /nologo /EHsc /DREGISTER_PROXY_DLL classic/classic_p.c classic/classic_i.c classic/dlldata.c /link /dll /out:comproxy.dll /export:DllGetClassObject /export:DllCanUnloadNow /export:DllRegisterServer /export:DllUnregisterServer /export:GetProxyDllInfo rpcrt4.lib
*/
struct MyModule : CAtlExeModuleT<MyModule>
{
HRESULT RegisterClassObjects(
_In_ DWORD dwClsContext,
_In_ DWORD dwFlags)
{
auto hr = CAtlExeModuleT::RegisterClassObjects(dwClsContext,dwFlags);
printf("RegisterClassObjects 0x%x\n",hr);
return hr;
}
HRESULT RegisterServer(
_In_ BOOL bRegTypeLib = FALSE,
_In_opt_ const CLSID* pCLSID = NULL)
{
auto hr = CAtlExeModuleT::RegisterServer(false, pCLSID);
if(FAILED(hr))
printf("Toaster register failed 0x%x\n",hr);
return hr;
}
};
MyModule mod;
int main(int argc, char *args[])
{
mod.WinMain(SW_HIDE);
}
comobj.cpp
#include <atlbase.h>
#include <atlcom.h>
#include <typeinfo>
//#include "comobj.h"
#include "classic/classic.h"
CComModule _Module;
extern "C" CLSID CLSID_CClassic;
struct Toast : CComObjectRoot,CComCoClass<Toast,&CLSID_CClassic>,IClassic
{
DECLARE_REGISTRY(CLSID_CClassic,"Toaster.1.0","Toaster","Toast Server",THREADFLAGS_BOTH);
DECLARE_CLASSFACTORY();
DECLARE_OBJECT_DESCRIPTION("Toast Server");
HRESULT STDMETHODCALLTYPE Hello( void)
{
printf("Hello\n");
return S_OK;
}
Toast()
{
printf("Toast alive\n");
printf("%s\n",typeid(_ClassFactoryCreatorClass).name());
}
BEGIN_COM_MAP(Toast)
COM_INTERFACE_ENTRY(IClassic)
END_COM_MAP();
};
OBJECT_ENTRY_AUTO(CLSID_CClassic,Toast);
Related
The below program works fine while having functions with primitive return type functions specifically the Pop function defined below works and I'm able to build properly, but when I build the solution with a function having non primitive return type as in PopC like below project doesn't build, but definitions are syntatically correct and I'm able to see the types being referred properly with proper namespace definitions in pch.h file.
Have defined the below code in the StreamSamplePool.idl file,
namespace WinRTComponent
{
[default_interface]
runtimeclass StreamSamplePool
{
StreamSamplePool();
Int32 MyProperty;
// MediaStreamSample PopC();
Int32 Pop();
}
}
And inside the StreamSamplePool.cpp file have defined the respective methods as follows
#include "pch.h"
#include "StreamSamplePool.h"
#include "StreamSamplePool.g.cpp"
#include <stack>
#include <queue>
using namespace winrt::Windows::Storage::Streams;
using namespace winrt::Windows::Foundation;
using namespace std;
//using namespace Platform;
using namespace winrt::Windows::Media::Core;
namespace winrt::WinRTComponent::implementation
{
int32_t StreamSamplePool::MyProperty()
{
throw hresult_not_implemented();
}
int32_t StreamSamplePool::Pop()
{
return int32_t();
}
//MediaStreamSample StreamSamplePool::PopC()
//{
// MediaStreamSample sample = MediaStreamSample::CreateFromBuffer(NULL,
//TimeSpan());
// //sample.Processed += OnSampleProcessed;
// return sample;
//}
void StreamSamplePool::MyProperty(int32_t /* value */)
{
throw hresult_not_implemented();
}
}
And have defined the following code inside StreamSamplePool.h
namespace winrt::WinRTComponent::implementation
{
struct StreamSamplePool : StreamSamplePoolT<StreamSamplePool>
{
StreamSamplePool() = default;
int32_t Pop();
//MediaStreamSample PopC();
int32_t MyProperty();
void MyProperty(int32_t value);
};
}
namespace winrt::WinRTComponent::factory_implementation
{
struct StreamSamplePool : StreamSamplePoolT<StreamSamplePool,
implementation::StreamSamplePool>
{
};
}
Error info
Error MIDL2011 [msg]unresolved type declaration [context]: WinRTComponent.MediaStreamSample [ Procedure 'PopC' ( RuntimeClass
'WinRTComponent.StreamSamplePool' ) ] WinRTComponent D:\Prithvi\Work\WinRTComponent\StreamSamplePool.idl 9
Compiler output
1>D:\...\StreamSamplePool.idl(9): error MIDL2011: [msg]unresolved type declaration [context]: WinRTComponent.MediaStreamSample [ Procedure 'PopC' ( RuntimeClass 'WinRTComponent.StreamSamplePool' ) ]
1>Done building project "WinRTComponent.vcxproj" -- FAILED.
The issue can be reduced to the following IDL file:
namespace WinRTComponent
{
[default_interface]
runtimeclass StreamSamplePool
{
StreamSamplePool();
MediaStreamSample PopC();
}
}
Compiling this using a default-generated C++/WinRT Component project produces the following error:
1>C:\...\StreamSamplePool.idl(7): error MIDL2011: [msg]unresolved type declaration [context]: WinRTComponent.MediaStreamSample [ Procedure 'PopC' ( RuntimeClass 'WinRTComponent.StreamSamplePool' ) ]
It contains all the information required to resolve the issue. In particular it's naming the error ("unresolved type declaration"), and the procedure affected ("PopC"). To solve this you'll have to provide the fully-qualified type name in the IDL file, i.e.
namespace WinRTComponent
{
[default_interface]
runtimeclass StreamSamplePool
{
StreamSamplePool();
Windows.Media.Core.MediaStreamSample PopC();
}
}
With that done, go to the "Generated Files\sources" directory under the project root, and copy the respective parts of the "StreamSamplePool.h" and "StreamSamplePool.cpp" files that the build system generated to your source files.
I created a local server (EXE) COM project with support for ConnectionPoint events.
idl pseudo:
interface IAtlClass : IDispatch{
[id(1)] HRESULT f1();
};
library ComExeLib
{
dispinterface _IAtlClassEvents
{
methods:
[id(1)] HRESULT f2();
};
[
uuid(...
]
coclass AtlClass
{
[default] interface IAtlClass;
[default, source] dispinterface _IAtlClassEvents;
};
};
Server is built in 32 bit configuration. Client code, built in 64 bit:
HRESULT hr = CoInitialize(NULL);
IAtlClass* atlClass;
hr = CoCreateInstance(CLSID_AtlClass, NULL,
CLSCTX_LOCAL_SERVER,
IID_IAtlClass,
reinterpret_cast<void**>(&atlClass));
hr = atlClass->f1();
IConnectionPointContainer* pICPC = NULL;
hr = atlClass->QueryInterface(IID_IConnectionPointContainer, (VOID **)&pICPC);
IConnectionPoint* pICP = NULL;
hr = pICPC->FindConnectionPoint(DIID__IAtlClassEvents, &pICP);
hr = pICP->Advise((_IAtlClassEvents*)&sink, &cookie);
Sink class:
class Sink : public _IAtlClassEvents
{
public:
HRESULT STDMETHODCALLTYPE QueryInterface(
/* [in] */ REFIID riid,
/* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
{
if ((DIID__IAtlClassEvents == riid))
{
*ppvObject = static_cast<_IAtlClassEvents*>(this);
AddRef();
return(S_OK);
}
*ppvObject = NULL;
return(E_NOINTERFACE);
}
ULONG STDMETHODCALLTYPE AddRef(void)
{
return(InterlockedIncrement(&m_iRef));
}
ULONG STDMETHODCALLTYPE Release(void)
{
if (0 == InterlockedDecrement(&m_iRef))
{
delete this;
return(0);
}
return(m_iRef);
}
HRESULT STDMETHODCALLTYPE GetTypeInfoCount()
HRESULT STDMETHODCALLTYPE GetTypeInfo()
HRESULT STDMETHODCALLTYPE GetIDsOfNames()
HRESULT STDMETHODCALLTYPE Invoke()
};
Registered the server with ComExe.exe /RegServer and the proxy with regsvr32 ComExePS.dll, under folder C:\windows\SysWOW\ and under c:\Windows\System32.
Not sure if necessary but tried to compile the proxy stub under 64 bit as well but it will not build since auto-generated ComExe_p.c contains an #if !defined(AMD64).. so the project can only be built in 32 bit (seems related to this post only I use VS2013).
All client code commands except the last (Advise) succeed (They succeed even without registering the ComExePS.dll) . Advise invokes the sink QueryInterface method (and none but it), five time with following iid's:
{00000003-0000-0000-C000-000000000046}
{ECC8691B-C1DB-4DC0-855E-65F6C551AF49}
{00000003-0000-0000-C000-000000000046}
{0000001B-0000-0000-C000-000000000046}
{IID_IUnknown}
None of which are related to IAtlClass (some standard MS iid's - this guy was getting something similar).
Eventually Advise returns E_UNEXPECTED Catastrophic failure and the question is what am I doing wrong?
I've been assigned the task of upgrading an old interop dll into visualstudio2015 with the v140 toolset.
I'm getting an odd access violation now.
Exception thrown at 0x000007fef7d3d95c (mscoreei.dll) in HostApp.exe:
0xC0000005: Access violation reading location 0xffffffffffffffff
Did anything change in cpp/cli from v110 to v140?
I can tell the error occurs when the methods are defined in a separate cpp instead of inline in the Foo.h. This work-around isn't possible since this is where I need to call managed objects.
Here is my attempt at reconstructing the outline of the code:
shared header IFoo.h
#ifdef DLL_EXPORTS
#define __API__ __declspec(dllexport)
#else
#define __API__ __declspec(dllimport)
#endif
class IFoo
{
public:
__API__ static IFoo* Create();
virtual void DoSomething()=0;
};
Foo.h
#include IFoo.h
class Foo : public IFoo
{
public:
Foo() { } // if inline no crash
void DoSomething();
};
Foo.cpp
#include ManagedStuff.h
#include Foo.h
// Foo::Foo() { } // AV if not inline.
void Foo::DoSomething()
{
gcroot<ManagedClass^> stuff = gcnew ManagedClass();
.....
}
FooImpl.cpp
#include Foo.h
IFoo* IFoo::Create()
{
IFoo* f = new Foo(); // CRASH if ctor is NOT inline.
f->DoSomething(); //CRASH
return f;
}
I have a c++ code that needs to be called in c# by a cli wrapper. I am stuck at the operator overloading part.
//this is my code
//Cppclass.h
#ifdef CPP_EXP_EXPORTS
#define CPP_EXP __declspec(dllexport)
#else
#define CPP_EXP __declspec(dllimport)
#endif
class CPP_EXP Cppclass;
CPP_EXP Cppclass operator-(Cppclass const &, Cppclass const &);
class CPP_EXP Cppclass
{
public:
friend CPP_EXP Cppclass operator-(Cppclass const &, Cppclass const &);
};
//this is my managed c++ code.
#include "Cppclass.h"
namespace Wrapper
{
public ref class cppwrapclass
{
public:
static cppwrapclass ^ operator-(cppwrapclass%A,cppwrapclass%B)
{
operator-(A.obj,B.obj);
return gcnew cppwrapclass();
}
private:
Cppclass *obj;
};
}
Its showing an intellisense error and not getting compiled.
You write a wrapper like this:
public ref class cppwrapclass
{
public:
cppwrapclass(Cppclass *obj)
: obj(obj)
{
}
~cppwrapclass()
{
this->!cppwrapclass();
}
!cppwrapclass()
{
if (obj)
{
delete obj;
obj = nullptr;
}
}
static cppwrapclass^ operator-(cppwrapclass% A, cppwrapclass% B)
{
return gcnew cppwrapclass(new Cppclass(*A.obj - *B.obj));
}
private:
Cppclass* obj;
};
A.obj is of type Cppclass*, therefore *A.obj is of type Cppclass, and *A.obj - *B.obj is a temporary Cppclass which needs to be moved to the heap in order to be referenced by the wrapper, hence the copy constructor call: new Cppclass(*A.obj - *B.obj).
The rest is the Dispose pattern and finalizer plumbing code.
I try to create a DLL in Embarcadero C++ Builder XE3, and use it in a test-project in the same environment.
I take example on a tutorial which code does not give a good result for me (!) : http://docwiki.embarcadero.com/RADStudio/XE3/en/Tutorial:_Using_Dynamic_Linked_Libraries_in_C%2B%2BBuilder_Applications
Here is the content of my DLL :
BaseAuth.h file :
#ifndef BaseAuthH
#define BaseAuthH
#include <System.hpp>
class TBaseAuth
{
public:
virtual void TestMessage() = 0;
};
#endif // BaseAuthH
Auth.h file :
//---------------------------------------------------------------------------
#ifndef AuthH
#define AuthH
//---------------------------------------------------------------------------
#include "BaseAuth.h"
class TAuth : public TBaseAuth
{
public:
TAuth();
~TAuth();
void TestMessage();
};
#endif
Auth.cpp file :
//---------------------------------------------------------------------------
#pragma hdrstop
#include "Auth.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
TAuth::TAuth()
{
}
TAuth::~TAuth()
{
}
void TAuth::TestMessage()
{
MessageBox(0, "Test message", "Test", MB_OK);
}
and File1.cpp :
#pragma hdrstop
#pragma argsused
#include "Auth.h"
extern "C" __declspec(dllexport) void* __stdcall GetClassInstance()
{
return static_cast<void*>(new TAuth());
}
extern "C" int _libmain(unsigned long reason)
{
return 1;
}
Now in the test application I have :
the same BaseAuth.h file
a form with a Button :
Test_DLLAuthOrga.h :
#ifndef Test_DLLAuthOrgaH
#define Test_DLLAuthOrgaH
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
//---------------------------------------------------------------------------
#include "BaseAuth.h"
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // Composants gérés par l'EDI
TButton *Button2;
void __fastcall Button2Click(TObject *Sender);
private: // Déclarations utilisateur
TBaseAuth *mpAuth;
public: // Déclarations utilisateur
__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
Test_DLLAuthOrga.cpp :
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Test_DLLAuthOrga.h"
#include "BaseAuth.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
const wchar_t* library = L"DLLAuthOrga.dll";
extern "C" __declspec(dllimport) void* __stdcall GetClassInstance();
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)
{
HINSTANCE load;
try
{ load = LoadLibrary(library); }
catch(Exception &e)
{ ShowMessage(e.Message); }
if (load)
{
ShowMessage("Library Loaded!");
void *myFunc;
myFunc = (void *)GetProcAddress(load, "GetClassInstance");
mpAuth = (AuthParent*)myFunc;
}
else { ShowMessage("Library not loaded!"); }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
if (mpAuth == NULL) return;
try { pRes = mpAuth->TestMessage(); }
catch(Exception &e) { ShowMessage(e.Message); return; }
}
The result is :
the pointer mpAuth has an adress.
But its methods have no adress, and when I call a simple method such as "void TestMessage()", it raises an access violation.
=> It first seemed to be a question of string compatibility (but between "C++ Builder XE3" and "C++ Builder XE3" I would expect the same string format to be used ?!) : Error calling DLL with Unicode Delphi
=> I found a similar issue but with C++ DLL into Delphi, not C++ DLL into C++ ... : Call C++ DLL in Delphi app
=> I tried using "HMODULE" instead of "HINSTANCE load;" : same result.
=> I tried without success using
mpAuth = static_cast<AuthParent*>(myFunc);
instead of :
mpAuth = (AuthParent*)myFunc;
=> I also tried replacing "__stdcall" by "__cdecl" or "" (removing) : the libray loads but GetProcAdress returns NULL.
=> What am I doing wrong in attempting to call the DLL's method "TestMessage()" ?
To correctly bind function from dll you should give it full definition, including calling convention, arguments, return type and __dllexport/__dllimport modifier. The easiest way to do it - using typedef so instead of typing (in Test_DLLAuthOrga.cpp)
void *myFunc;
myFunc = (void *)GetProcAddress(load, "GetClassInstance");
use
typedef __declspec(dllimport) void (__stdcall *MyFuncPointerType)(void);
MyFuncPointerType myFunc;
myFunc = (MyFuncPointerType)GetProcAddress(load, "GetClassInstance");
If you are using __cdecl convention you should also add underscore to the target function name
typedef __declspec(dllimport) void (__cdecl *MyFuncPointerType)(void);
MyFuncPointerType myFunc;
myFunc = (MyFuncPointerType)GetProcAddress(load, "_GetClassInstance");
you can also explicitly define AuthParent* as a return type for your factory function to get rid of uneccessary casts to void* and back to AuthParent* (in File1.cpp and Test_DLLAuthOrga.cpp) so, the final code snippet would look like this:
typedef __declspec(dllimport) AuthParent* (__cdecl *MyFuncPointerType)(void);
MyFuncPointerType myFunc;
myFunc = (MyFuncPointerType)GetProcAddress(load, "_GetClassInstance");
mpAuth = myFunc();