Can I use Pinvoke for a dll that calls a COM component?

G

Guest

I have a program that originally compiles into a exe file. I changed the
compile option to generate dll file. This program calls a com component.
Can I use pinvoke in C# to call it? The following is the main dll file.

#include "stdafx.h"

#define MAX_ADSPATH_CHARS 2048

//***************************************************************************
// local function prototypes
//***************************************************************************

int LocalToWideChar(LPWSTR pWide, LPCTSTR pLocal, DWORD dwChars);

/***************************************************************************

_tmain()

***************************************************************************/


using namespace std;

__declspec(dllexport) void ShowAdProp(WCHAR* inPath)
{
wstring adPath = inPath;

CoInitialize(NULL);

HRESULT hr;

HINSTANCE hInstance = NULL;
HWND hwndConsole = GetConsoleWindow();
if(hwndConsole)
{
hInstance = (HINSTANCE)(LONG_PTR)GetWindowLongPtr(hwndConsole,
GWLP_HINSTANCE);
}

CPropSheetHost *pHost = new CPropSheetHost(hInstance);

// Hold a reference count for the CPropSheetHost object.
pHost->AddRef();

hr = pHost->SetObject(adPath.c_str());
if(FAILED(hr))
{
goto ExitMain;
}

pHost->Run();

/*
Release the CPropSheetHost object. Other components may still hold a
reference to the object, so this cannot just be deleted here. Let
the object delete itself when all references are released.
*/
pHost->Release();


ExitMain:

CoUninitialize();
}

/**************************************************************************

LocalToWideChar()

**************************************************************************/

int LocalToWideChar(LPWSTR pWide, LPCTSTR pLocal, DWORD dwChars)
{
*pWide = 0;

#ifdef UNICODE
lstrcpyn(pWide, pLocal, dwChars);
#else
MultiByteToWideChar( CP_ACP,
0,
pLocal,
-1,
pWide,
dwChars);
#endif

return lstrlenW(pWide);
}
 
N

Nicholas Paldino [.NET/C# MVP]

Pucca,

You could, but this seems like really messy design. Why not export the
CPropSheetHost class as a COM object?
 
G

Guest

If I do that then do I use COM interop to invoke CPropSheetHost, the COM
object, directly from my C# program?
--
Thanks.


Nicholas Paldino said:
Pucca,

You could, but this seems like really messy design. Why not export the
CPropSheetHost class as a COM object?


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Pucca said:
I have a program that originally compiles into a exe file. I changed the
compile option to generate dll file. This program calls a com component.
Can I use pinvoke in C# to call it? The following is the main dll file.

#include "stdafx.h"

#define MAX_ADSPATH_CHARS 2048

//***************************************************************************
// local function prototypes
//***************************************************************************

int LocalToWideChar(LPWSTR pWide, LPCTSTR pLocal, DWORD dwChars);

/***************************************************************************

_tmain()

***************************************************************************/


using namespace std;

__declspec(dllexport) void ShowAdProp(WCHAR* inPath)
{
wstring adPath = inPath;

CoInitialize(NULL);

HRESULT hr;

HINSTANCE hInstance = NULL;
HWND hwndConsole = GetConsoleWindow();
if(hwndConsole)
{
hInstance = (HINSTANCE)(LONG_PTR)GetWindowLongPtr(hwndConsole,
GWLP_HINSTANCE);
}

CPropSheetHost *pHost = new CPropSheetHost(hInstance);

// Hold a reference count for the CPropSheetHost object.
pHost->AddRef();

hr = pHost->SetObject(adPath.c_str());
if(FAILED(hr))
{
goto ExitMain;
}

pHost->Run();

/*
Release the CPropSheetHost object. Other components may still hold a
reference to the object, so this cannot just be deleted here. Let
the object delete itself when all references are released.
*/
pHost->Release();


ExitMain:

CoUninitialize();
}

/**************************************************************************

LocalToWideChar()

**************************************************************************/

int LocalToWideChar(LPWSTR pWide, LPCTSTR pLocal, DWORD dwChars)
{
*pWide = 0;

#ifdef UNICODE
lstrcpyn(pWide, pLocal, dwChars);
#else
MultiByteToWideChar( CP_ACP,
0,
pLocal,
-1,
pWide,
dwChars);
#endif

return lstrlenW(pWide);
}
 
J

John Duval

Hi Pucca,
Yes, if you create a COM object, you can simply add a reference to it
from your C# program, and then call methods on it directly from C#. No
pinvoke required.
John
If I do that then do I use COM interop to invoke CPropSheetHost, the COM
object, directly from my C# program?
--
Thanks.


Nicholas Paldino said:
Pucca,

You could, but this seems like really messy design. Why not export the
CPropSheetHost class as a COM object?


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Pucca said:
I have a program that originally compiles into a exe file. I changed the
compile option to generate dll file. This program calls a com component.
Can I use pinvoke in C# to call it? The following is the main dll file.

#include "stdafx.h"

#define MAX_ADSPATH_CHARS 2048

//***************************************************************************
// local function prototypes
//***************************************************************************

int LocalToWideChar(LPWSTR pWide, LPCTSTR pLocal, DWORD dwChars);

/***************************************************************************

_tmain()

***************************************************************************/


using namespace std;

__declspec(dllexport) void ShowAdProp(WCHAR* inPath)
{
wstring adPath = inPath;

CoInitialize(NULL);

HRESULT hr;

HINSTANCE hInstance = NULL;
HWND hwndConsole = GetConsoleWindow();
if(hwndConsole)
{
hInstance = (HINSTANCE)(LONG_PTR)GetWindowLongPtr(hwndConsole,
GWLP_HINSTANCE);
}

CPropSheetHost *pHost = new CPropSheetHost(hInstance);

// Hold a reference count for the CPropSheetHost object.
pHost->AddRef();

hr = pHost->SetObject(adPath.c_str());
if(FAILED(hr))
{
goto ExitMain;
}

pHost->Run();

/*
Release the CPropSheetHost object. Other components may still hold a
reference to the object, so this cannot just be deleted here. Let
the object delete itself when all references are released.
*/
pHost->Release();


ExitMain:

CoUninitialize();
}

/**************************************************************************

LocalToWideChar()

**************************************************************************/

int LocalToWideChar(LPWSTR pWide, LPCTSTR pLocal, DWORD dwChars)
{
*pWide = 0;

#ifdef UNICODE
lstrcpyn(pWide, pLocal, dwChars);
#else
MultiByteToWideChar( CP_ACP,
0,
pLocal,
-1,
pWide,
dwChars);
#endif

return lstrlenW(pWide);
}
 
G

Guest

I bought a book on COM and .Net but it looked really complicated and a very
thick book. I thought pinvok would be easier. But from your reply it seems
quite simple. Do you know of any sample code that I can look to see how it's
done?

Thanks.
--
Thanks.


John Duval said:
Hi Pucca,
Yes, if you create a COM object, you can simply add a reference to it
from your C# program, and then call methods on it directly from C#. No
pinvoke required.
John
If I do that then do I use COM interop to invoke CPropSheetHost, the COM
object, directly from my C# program?
--
Thanks.


Nicholas Paldino said:
Pucca,

You could, but this seems like really messy design. Why not export the
CPropSheetHost class as a COM object?


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

I have a program that originally compiles into a exe file. I changed the
compile option to generate dll file. This program calls a com component.
Can I use pinvoke in C# to call it? The following is the main dll file.

#include "stdafx.h"

#define MAX_ADSPATH_CHARS 2048

//***************************************************************************
// local function prototypes
//***************************************************************************

int LocalToWideChar(LPWSTR pWide, LPCTSTR pLocal, DWORD dwChars);

/***************************************************************************

_tmain()

***************************************************************************/


using namespace std;

__declspec(dllexport) void ShowAdProp(WCHAR* inPath)
{
wstring adPath = inPath;

CoInitialize(NULL);

HRESULT hr;

HINSTANCE hInstance = NULL;
HWND hwndConsole = GetConsoleWindow();
if(hwndConsole)
{
hInstance = (HINSTANCE)(LONG_PTR)GetWindowLongPtr(hwndConsole,
GWLP_HINSTANCE);
}

CPropSheetHost *pHost = new CPropSheetHost(hInstance);

// Hold a reference count for the CPropSheetHost object.
pHost->AddRef();

hr = pHost->SetObject(adPath.c_str());
if(FAILED(hr))
{
goto ExitMain;
}

pHost->Run();

/*
Release the CPropSheetHost object. Other components may still hold a
reference to the object, so this cannot just be deleted here. Let
the object delete itself when all references are released.
*/
pHost->Release();


ExitMain:

CoUninitialize();
}

/**************************************************************************

LocalToWideChar()

**************************************************************************/

int LocalToWideChar(LPWSTR pWide, LPCTSTR pLocal, DWORD dwChars)
{
*pWide = 0;

#ifdef UNICODE
lstrcpyn(pWide, pLocal, dwChars);
#else
MultiByteToWideChar( CP_ACP,
0,
pLocal,
-1,
pWide,
dwChars);
#endif

return lstrlenW(pWide);
}
 
J

John Duval

Hi Pucca,
Hopefully you're not starting with Adam Nathan's book. It's a really
good book, mind you, but not for beginners.

Anyway, here are some steps that should get you going. You're going to
create 2 projects -- one that implements a COM object and another that
creates & calls into the object. There's a lot of ways to do this, but
here is one that should work for you.

Hope this helps,
John

To create a sample COM object:

1) In VS2005, pick File -> new project
2) Under project types, select Other Languages -> Visual C++ -> ATL ->
ATL Project
3) Pick a project name like "SampleCOMObject" and click OK
4) When the wizard pops up, just click Finish
(you now have a shell DLL project that you can build)
5) View -> Class View
(this shows you the objects in your project)
6) Right-click on SampleCOMObject in the class view pane and pick Add
-> Class
7) In the Add Class dialog, pick Visual C++ -> ATL -> ATL Simple
Object and click Add
8) In the ATL Simple Object Wizard, fill in the short name like
"MyCOMObject" and click Finish
(you will now see CMyCOMObject in the class view pane)
9) Right-click on the IMyCOMObject **interface** (looks like a
lollipop) in the class view pane, and pick Add -> Add Method
10) In the Add Method Wizard, enter a method name like "MyTestMethod"
11) In the Add Method Wizard, enter a parameter with type BSTR and a
name like "MyParam"
12) Click Add to add the parameter, then finish to add the method
(you could have added more parameters, but let's do one for
simplicity)
12) You can now add your code inside the MyTestFunction method
(I just added a line that says "Beep(440, 500);" so I know it got
there)
13) Build the project
(this step will build and register a type library (TLB) that can be
referenced from your C# program)


To call the COM object from a C# project:

1) In VS2005 pick File -> new project
(you don't need to close the SampleCOMObject C++ project)
2) Pick a project type and name (I chose Visual C# Console
Application, "SampleCOMClient")
3) In the Solution Explorer, go to the SampleCOMClient project,
right-click References -> Add Reference
4) Click on the COM tab, select "SampleCOMObject 1.0 Type Library" and
click OK
5) Now you can just call the method directly from C# like this:

using System;
using System.Collections.Generic;
using System.Text;

using SampleCOMObjectLib;

namespace SampleCOMClient
{
class Program
{
static void Main(string[] args)
{
string theParameter = "hi there";
MyCOMObjectClass test = new MyCOMObjectClass();
test.MyTestMethod(theParameter);
}
}
}

I bought a book on COM and .Net but it looked really complicated and a very
thick book. I thought pinvok would be easier. But from your reply it seems
quite simple. Do you know of any sample code that I can look to see how it's
done?

Thanks.
--
Thanks.


John Duval said:
Hi Pucca,
Yes, if you create a COM object, you can simply add a reference to it
from your C# program, and then call methods on it directly from C#. No
pinvoke required.
John
If I do that then do I use COM interop to invoke CPropSheetHost, the COM
object, directly from my C# program?
--
Thanks.


:

Pucca,

You could, but this seems like really messy design. Why not export the
CPropSheetHost class as a COM object?


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

I have a program that originally compiles into a exe file. I changed the
compile option to generate dll file. This program calls a com component.
Can I use pinvoke in C# to call it? The following is the main dll file.

#include "stdafx.h"

#define MAX_ADSPATH_CHARS 2048

//***************************************************************************
// local function prototypes
//***************************************************************************

int LocalToWideChar(LPWSTR pWide, LPCTSTR pLocal, DWORD dwChars);

/***************************************************************************

_tmain()

***************************************************************************/


using namespace std;

__declspec(dllexport) void ShowAdProp(WCHAR* inPath)
{
wstring adPath = inPath;

CoInitialize(NULL);

HRESULT hr;

HINSTANCE hInstance = NULL;
HWND hwndConsole = GetConsoleWindow();
if(hwndConsole)
{
hInstance = (HINSTANCE)(LONG_PTR)GetWindowLongPtr(hwndConsole,
GWLP_HINSTANCE);
}

CPropSheetHost *pHost = new CPropSheetHost(hInstance);

// Hold a reference count for the CPropSheetHost object.
pHost->AddRef();

hr = pHost->SetObject(adPath.c_str());
if(FAILED(hr))
{
goto ExitMain;
}

pHost->Run();

/*
Release the CPropSheetHost object. Other components may still hold a
reference to the object, so this cannot just be deleted here. Let
the object delete itself when all references are released.
*/
pHost->Release();


ExitMain:

CoUninitialize();
}

/**************************************************************************

LocalToWideChar()

**************************************************************************/

int LocalToWideChar(LPWSTR pWide, LPCTSTR pLocal, DWORD dwChars)
{
*pWide = 0;

#ifdef UNICODE
lstrcpyn(pWide, pLocal, dwChars);
#else
MultiByteToWideChar( CP_ACP,
0,
pLocal,
-1,
pWide,
dwChars);
#endif

return lstrlenW(pWide);
}
 
G

Guest

John, thank you so much. That's what I want to know how to do quickly. I
bouth 2 very thick books on this subject and you have summarize what I need
in 2 pages in simple steps. I can't thank you enough for you help. I
followed the steps and the sample worked great!

I have codes from the SDK that originally complie to an application.exe file
and I need to modify it to a COM dll. I would really appreicate it if you or
someone can help me out with this. The program has 1 .cpp file that calls
the COM object and the rest of the .h and .cpp files all belongs to the COM
object. I execluded that .cpp file and modify the project property option to
output dll file however, it's not putting out the type library that I can add
reference to in my other project so I can do COM interop.

//The file that I execulded
//***************************************************************************
//
//***************************************************************************

//***************************************************************************
//
// File: Main.cpp
//
// Description:
//
//***************************************************************************

//***************************************************************************
// #include statements
//***************************************************************************

#include "stdafx.h"

#define MAX_ADSPATH_CHARS 2048

//***************************************************************************
// local function prototypes
//***************************************************************************

int LocalToWideChar(LPWSTR pWide, LPCTSTR pLocal, DWORD dwChars);

/***************************************************************************

_tmain()

***************************************************************************/


//int _tmain(int argc, _TCHAR* argv[])
//{
// TCHAR szTemp[MAX_ADSPATH_CHARS];
// LPWSTR pwszADsPath = NULL;
//
// CoInitialize(NULL);
//
// if(argc < 2)
// {
// // Prompt the user for the ADsPath.
// _tprintf(TEXT("Enter the ADsPath of the object to display the
property sheet for:\n"));
// _fgetts(szTemp, MAX_ADSPATH_CHARS - 1, stdin);
//
// // Trim the last character, which is the carriage return.
// szTemp[lstrlen(szTemp) - 1] = 0;
// }
// else
// {
// lstrcpyn(szTemp, argv[1], MAX_ADSPATH_CHARS - 1);
// }

using namespace std;

__declspec(dllexport) void ShowAdProp(WCHAR* inPath)
{
wstring adPath = inPath;

CoInitialize(NULL);

HRESULT hr;

HINSTANCE hInstance = NULL;
HWND hwndConsole = GetConsoleWindow();
if(hwndConsole)
{
hInstance = (HINSTANCE)(LONG_PTR)GetWindowLongPtr(hwndConsole,
GWLP_HINSTANCE);
}

CPropSheetHost *pHost = new CPropSheetHost(hInstance);

// Hold a reference count for the CPropSheetHost object.
pHost->AddRef();

hr = pHost->SetObject(adPath.c_str());
if(FAILED(hr))
{
goto ExitMain;
}

pHost->Run();

/*
Release the CPropSheetHost object. Other components may still hold a
reference to the object, so this cannot just be deleted here. Let
the object delete itself when all references are released.
*/
pHost->Release();


ExitMain:

CoUninitialize();
}

/**************************************************************************

LocalToWideChar()

**************************************************************************/

int LocalToWideChar(LPWSTR pWide, LPCTSTR pLocal, DWORD dwChars)
{
*pWide = 0;

#ifdef UNICODE
lstrcpyn(pWide, pLocal, dwChars);
#else
MultiByteToWideChar( CP_ACP,
0,
pLocal,
-1,
pWide,
dwChars);
#endif

return lstrlenW(pWide);
}

//The 2 header files
What do I need to do to get the type librarty COM reference? Thank you.
Also, below is the .cpp file I removed and the 2 .h file that came with the
SDK.


#pragma once

//***************************************************************************
// #include statements
//***************************************************************************

#include "stdafx.h"
#include <string>
#include <objbase.h>

//***************************************************************************
// data type definitions
//***************************************************************************

#define VIEW_POINTER_OFFSET GWLP_USERDATA

#ifndef CFSTR_DS_PARENTHWND
#define CFSTR_DS_PARENTHWND_W L"DsAdminParentHwndClipFormat"
#define CFSTR_DS_PARENTHWND_A "DsAdminParentHwndClipFormat"

#ifdef UNICODE
#define CFSTR_DS_PARENTHWND CFSTR_DS_PARENTHWND_W
#else
#define CFSTR_DS_PARENTHWND CFSTR_DS_PARENTHWND_A
#endif //UNICODE
#endif //CFSTR_DS_PARENTHWND

#ifndef CFSTR_DS_PROPSHEETCONFIG
#define CFSTR_DS_PROPSHEETCONFIG_W L"DsPropSheetCfgClipFormat"
#define CFSTR_DS_PROPSHEETCONFIG_A "DsPropSheetCfgClipFormat"

#ifdef UNICODE
#define CFSTR_DS_PROPSHEETCONFIG CFSTR_DS_PROPSHEETCONFIG_W
#else
#define CFSTR_DS_PROPSHEETCONFIG CFSTR_DS_PROPSHEETCONFIG_A
#endif //UNICODE
#endif //CFSTR_DS_PROPSHEETCONFIG


#ifndef WM_ADSPROP_SHEET_CREATE
#define WM_ADSPROP_SHEET_CREATE (WM_USER + 1108)
#endif


#ifndef WM_DSA_SHEET_CREATE_NOTIFY
#define WM_DSA_SHEET_CREATE_NOTIFY (WM_USER + 6)
#endif


#ifndef WM_DSA_SHEET_CLOSE_NOTIFY
#define WM_DSA_SHEET_CLOSE_NOTIFY (WM_USER + 5)
#endif


#ifndef DSA_SEC_PAGE_INFO
typedef struct _DSA_SEC_PAGE_INFO
{
HWND hwndParentSheet;
DWORD offsetTitle;
DSOBJECTNAMES dsObjectNames;
} DSA_SEC_PAGE_INFO, *PDSA_SEC_PAGE_INFO;
#endif //DSA_SEC_PAGE_INFO

#ifndef PROPSHEETCFG
typedef struct _PROPSHEETCFG
{
LONG_PTR lNotifyHandle;
HWND hwndParentSheet;
HWND hwndHidden;
WPARAM wParamSheetClose;
} PROPSHEETCFG, *PPROPSHEETCFG;
#endif //PROPSHEETCFG

#define PROP_SHEET_HOST_ID 0xCDCDCDCD

#define PROP_SHEET_PREFIX_ADMIN L"admin"
#define PROP_SHEET_PREFIX_SHELL L"shell"

/**************************************************************************

CPropSheetHost class definition

**************************************************************************/

class CPropSheetHost : public IDataObject
{
private:
HWND m_hwndParent;
HWND m_hwndHidden;
DWORD m_ObjRefCount;
CComPtr<IADs> m_spADObject;
ATOM m_cfDSPropSheetConfig;
ATOM m_cfDSObjectNames;
ATOM m_cfDSDispSpecOptions;
CSimpleArray<HPROPSHEETPAGE> m_rgPageHandles;
LPTSTR m_szHiddenWindowClass;
HINSTANCE m_hInst;
LPWSTR m_pwszPrefix;

public:
CPropSheetHost(HINSTANCE hInstance, HWND hwndParent = NULL);
~CPropSheetHost();

public:
HRESULT SetObject(LPCWSTR pwszADsPath);
HRESULT SetObject(IADs *pads);
__declspec(dllexport) void ShowAdProp(WCHAR* inPath);
void Run();

private:
HWND _CreateHiddenWindow();
static LRESULT CALLBACK _HiddenWindowProc(HWND, UINT, WPARAM, LPARAM);
void _CreatePropertySheet();
static BOOL CALLBACK _AddPagesCallback(HPROPSHEETPAGE hPage, LPARAM
lParam);
HRESULT _AddPagesForObject(IADs *padsObject);
void _CreateSecondaryPropertySheet(DSA_SEC_PAGE_INFO *pDSASecPageInfo);
HRESULT _GetDSDispSpecOption(FORMATETC *pFormatEtc, STGMEDIUM
*pStgMedium);
HRESULT _GetDSObjectNames(FORMATETC *pFormatEtc, STGMEDIUM *pStgMedium);
HRESULT _GetDSPropSheetConfig(FORMATETC *pFormatEtc, STGMEDIUM
*pStgMedium);
HRESULT _ExtractSecPageInfo(WPARAM wParam, PDSA_SEC_PAGE_INFO
*ppSecPageInfo);

public:
//IUnknown methods
STDMETHODIMP QueryInterface(REFIID, LPVOID FAR *);
STDMETHODIMP_(DWORD) AddRef();
STDMETHODIMP_(DWORD) Release();

//IDataObject methods
STDMETHODIMP GetData(FORMATETC*, STGMEDIUM*);
STDMETHODIMP GetDataHere(FORMATETC*, STGMEDIUM*);
STDMETHODIMP QueryGetData(FORMATETC*);
STDMETHODIMP GetCanonicalFormatEtc(LPFORMATETC, LPFORMATETC);
STDMETHODIMP SetData(LPFORMATETC, LPSTGMEDIUM, BOOL);
STDMETHODIMP EnumFormatEtc(DWORD, IEnumFORMATETC**);
STDMETHODIMP DAdvise(FORMATETC*, DWORD, IAdviseSink*, LPDWORD);
STDMETHODIMP DUnadvise(DWORD dwConnection);
STDMETHODIMP EnumDAdvise(IEnumSTATDATA** ppEnumAdvise);

};


///////////////////////////////////////

#pragma once
#pragma warning(push,3)

#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files:
#include <windows.h>
// C RunTime Header Files
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>

// TODO: reference additional headers your program requires here
#include <commctrl.h>
#include <ole2.h>
#include <atlbase.h>
#include <shlobj.h>
#include <dsclient.h>
#include <vector>
#include <string>
#include <adsprop.h>
#include "PropSheetHost.h"

--
Thanks.


John Duval said:
Hi Pucca,
Hopefully you're not starting with Adam Nathan's book. It's a really
good book, mind you, but not for beginners.

Anyway, here are some steps that should get you going. You're going to
create 2 projects -- one that implements a COM object and another that
creates & calls into the object. There's a lot of ways to do this, but
here is one that should work for you.

Hope this helps,
John

To create a sample COM object:

1) In VS2005, pick File -> new project
2) Under project types, select Other Languages -> Visual C++ -> ATL ->
ATL Project
3) Pick a project name like "SampleCOMObject" and click OK
4) When the wizard pops up, just click Finish
(you now have a shell DLL project that you can build)
5) View -> Class View
(this shows you the objects in your project)
6) Right-click on SampleCOMObject in the class view pane and pick Add
-> Class
7) In the Add Class dialog, pick Visual C++ -> ATL -> ATL Simple
Object and click Add
8) In the ATL Simple Object Wizard, fill in the short name like
"MyCOMObject" and click Finish
(you will now see CMyCOMObject in the class view pane)
9) Right-click on the IMyCOMObject **interface** (looks like a
lollipop) in the class view pane, and pick Add -> Add Method
10) In the Add Method Wizard, enter a method name like "MyTestMethod"
11) In the Add Method Wizard, enter a parameter with type BSTR and a
name like "MyParam"
12) Click Add to add the parameter, then finish to add the method
(you could have added more parameters, but let's do one for
simplicity)
12) You can now add your code inside the MyTestFunction method
(I just added a line that says "Beep(440, 500);" so I know it got
there)
13) Build the project
(this step will build and register a type library (TLB) that can be
referenced from your C# program)


To call the COM object from a C# project:

1) In VS2005 pick File -> new project
(you don't need to close the SampleCOMObject C++ project)
2) Pick a project type and name (I chose Visual C# Console
Application, "SampleCOMClient")
3) In the Solution Explorer, go to the SampleCOMClient project,
right-click References -> Add Reference
4) Click on the COM tab, select "SampleCOMObject 1.0 Type Library" and
click OK
5) Now you can just call the method directly from C# like this:

using System;
using System.Collections.Generic;
using System.Text;

using SampleCOMObjectLib;

namespace SampleCOMClient
{
class Program
{
static void Main(string[] args)
{
string theParameter = "hi there";
MyCOMObjectClass test = new MyCOMObjectClass();
test.MyTestMethod(theParameter);
}
}
}

I bought a book on COM and .Net but it looked really complicated and a very
thick book. I thought pinvok would be easier. But from your reply it seems
quite simple. Do you know of any sample code that I can look to see how it's
done?

Thanks.
--
Thanks.


John Duval said:
Hi Pucca,
Yes, if you create a COM object, you can simply add a reference to it
from your C# program, and then call methods on it directly from C#. No
pinvoke required.
John

Pucca wrote:
If I do that then do I use COM interop to invoke CPropSheetHost, the COM
object, directly from my C# program?
--
Thanks.


:

Pucca,

You could, but this seems like really messy design. Why not export the
CPropSheetHost class as a COM object?


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

I have a program that originally compiles into a exe file. I changed the
compile option to generate dll file. This program calls a com component.
Can I use pinvoke in C# to call it? The following is the main dll file.

#include "stdafx.h"

#define MAX_ADSPATH_CHARS 2048

//***************************************************************************
// local function prototypes
//***************************************************************************

int LocalToWideChar(LPWSTR pWide, LPCTSTR pLocal, DWORD dwChars);

/***************************************************************************

_tmain()

***************************************************************************/


using namespace std;

__declspec(dllexport) void ShowAdProp(WCHAR* inPath)
{
wstring adPath = inPath;

CoInitialize(NULL);

HRESULT hr;

HINSTANCE hInstance = NULL;
HWND hwndConsole = GetConsoleWindow();
if(hwndConsole)
{
hInstance = (HINSTANCE)(LONG_PTR)GetWindowLongPtr(hwndConsole,
GWLP_HINSTANCE);
}

CPropSheetHost *pHost = new CPropSheetHost(hInstance);

// Hold a reference count for the CPropSheetHost object.
pHost->AddRef();

hr = pHost->SetObject(adPath.c_str());
if(FAILED(hr))
{
goto ExitMain;
}

pHost->Run();

/*
Release the CPropSheetHost object. Other components may still hold a
reference to the object, so this cannot just be deleted here. Let
the object delete itself when all references are released.
*/
pHost->Release();


ExitMain:

CoUninitialize();
}

/**************************************************************************

LocalToWideChar()

**************************************************************************/

int LocalToWideChar(LPWSTR pWide, LPCTSTR pLocal, DWORD dwChars)
{
*pWide = 0;

#ifdef UNICODE
lstrcpyn(pWide, pLocal, dwChars);
#else
MultiByteToWideChar( CP_ACP,
0,
pLocal,
-1,
pWide,
dwChars);
#endif

return lstrlenW(pWide);
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top