I have number of C++ API's and I want to access them using P\Invoke in VB.Net.Following are the C wrapper written for some of the API's.Can anybody tell me how to use P\Invoke to access these methods in VB.Net.
In wrapper.h:
typedef void * VERIFY_HANDLE;
extern VERIFY_HANDLE Verify_Create();
extern void VERIFY_SetVerified(VERIFY_HANDLE, bool);
extern bool VERIFY_GetVerified(VERIFY_HANDLE);
/* etc, etc */
In wrapper.c:
#include "wrapper.h"
#include "Verify.h"
VERIFY_HANDLE Verify_Create() { return (VERIFY_HANDLE) new Verify(); }
void SetVerified(VERIFY_HANDLE h, bool b) { ((Verify *)h)->SetVerified(b); }
bool GetVerified(VERIFY_HANDLE h) { return ((Verify *)h)->GetVerified(); }
The free P/Invoke Interop Assistant can create Vb.Net P/Invoke code automatically from that C header file.
Related
I have C++/CLI console application that uses direct sound. I am unsure if directsound is a problem or not, but after Windows 10 update application hangs before even launching. To reproduce this problem please create C++/CLI console application, link it against dsound.lib and copy paste this code into main file. You will notice that it unhangs as soon as DirectSoundEnumerate is commented.
#include "stdafx.h"
#include <vector>
#include <Windows.h>
#include <dsound.h>
using namespace System;
using namespace System::Collections::Generic;
static BOOL CALLBACK DSEnumOutputProc(LPGUID lpGUID,
LPCWSTR lpszDesc,
LPCWSTR lpszDrvName,
LPVOID lpContext)
{
return(TRUE);
}
void EnumerateDirectSoundDevices()
{
if (SUCCEEDED(DirectSoundEnumerate(&DSEnumOutputProc, LPVOID(NULL))))
{
printf("output devices enumerated.\n");
}
}
int main(array<System::String ^> ^args)
{
Console::WriteLine(L"Hello World");
return 0;
}
I am doing something pretty ugly but nevertheless there seems to be something what appears to be a bug ..
I have an enum called BasicTypeID which is written in C#:
public enum BasicTypeID
{
//..
FUNCTION,
VOID,
FLOAT,
// ..
}
As I try to assign a value to an array element on position BasicTypeID::VOID like this:
typedef struct TypeInfo {
char * name;
unsigned char size;
unsigned char sign;
unsigned char real;
} TypeInfo;
static const TypeInfo TYPE_VOID = { "void", 0, 0, 0 };
static TypeInfo const **basic_type_info;
CDLLEXPORT void CLIParser_InitializeDebugInformation(char * source_folder_path, char * cdb_file_path)
{
// ..
int enum_size = Enum::GetNames(BasicTypeID::typeid)->Length;
*basic_type_info = new TypeInfo[enum_size];
basic_type_info[(int)BasicTypeID::VOID] = &TYPE_VOID; // Compile error
VOID *dummy1;
FLOAT dummy2;
// ..
}
I am receiving the errors:
error C2589: 'void' : illegal token on right side of '::'
error C2059: syntax error : '::'
whereas it is working if I use e.g. FUNCTION as index:
basic_type_info[(int)BasicTypeID::FUNCTION] = &TYPE_VOID; // Compiles without errors
it is also working for FLOAT:
basic_type_info[(int)BasicTypeID::FLOAT] = &TYPE_VOID; // Compiles without errors
Why is this happening?
The Windows headers have a #define VOID void, which messes up your C++/CLI code.
Why did they do this? Because back in the day when the Windows API was first defined, C compiler support for void wasn't uniform. Since the API has to work with these compilers, it supplied its own version in VOID, which is presumably expanded to void if your compiler supports it, or some other type if it doesn't. Then, they can't do anything about it because of backward compatibility.
Why not a typedef? Because apparently the Microsoft compilers at that time didn't consider typedef void VOID; to be legal C (they now do, I believe). And they had to retain the macro for backward compatibility, because while
#define VOID void
int c(VOID){ return 0; }
is legal,
typedef void VOID;
int c(VOID){ return 0; }
is not (in C89, anyway).
Pretty much all the other Windows API types are typedefs and not preprocessor macros, which is why FLOAT works for you but VOID doesn't.
I have created a GUI using tcl. I want to make some of the core functionalities of the tcl code available to be used by any program which supports dll. For that i have taken a very simple tcl code example, which adds two integer numbers and i have written a c wrapper function to use this functionality. This is working for me. Now how can i create a dll for these two c and tcl files, so that any program can use this addition functionality by simply loading the dll.
Here is my simple tcl code :
/* Filename : simple_addition.tcl */
#!/usr/bin/env tclsh8.5
proc add_two_nos { } {
set a 10
set b 20
set c [expr { $a + $b } ]
puts " c is $c ......."
}
And here is my c wrapper function which uses the above tcl addition functionality :
#include <tcl.h>
#include <tclDecls.h>
#include <tclPlatDecls.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (int argc, char **argv) {
Tcl_Interp *interp;
int code;
char *result;
printf("inside main function \n");
Tcl_FindExecutable(argv[0]);
interp = Tcl_CreateInterp();
code = Tcl_Eval(interp, "source simple_addition.tcl; add_two_nos");
/* Retrieve the result... */
result = Tcl_GetString(Tcl_GetObjResult(interp));
/* Check for error! If an error, message is result. */
if (code == TCL_ERROR) {
fprintf(stderr, "ERROR in script: %s\n", result);
exit(1);
}
/* Print (normal) result if non-empty; we'll skip handling encodings for now */
if (strlen(result)) {
printf("%s\n", result);
}
/* Clean up */
Tcl_DeleteInterp(interp);
exit(0);
}
This c wrapper is working fine for me and gives correct results.
Now I want to create a dll file, so that if i include that dll to any program that supports dll, it should be able to use this addition functionality of the above tcl code. Can anybody please tell me the way i can do it. Please help me. I am new to this dll concept.
In order to create the .dll you'll have to use something like Visual Studio and C or C++ to create the .dll (there are lots of other tools out there that can create .dll files but VS is easy to get hold of and to use.) So in VS create a new project, this needs to be a C++ WIN32 project. Select the DLL application type and the Export Symbols additional option.
VS will create a basic .dll that you can then amend to do what you want. I short I'd look at putting the creating/destruction of the intrepter into the dllmain:
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
Tcl_FindExecutable(NULL);
interp = Tcl_CreateInterp();
}
case DLL_THREAD_ATTACH:
break ;
case DLL_THREAD_DETACH:
break ;
case DLL_PROCESS_DETACH:
{
Tcl_DeleteInterp(interp);
break;
}
}
return TRUE;
}
and then create functions exported by the .dll that make use of the interpreter. If you aren't familiar with the concept of shared libaries then I'd suggest spending a little time reading up on them, try here and here for some background reading.
I'm currently using Visual Studio C++ to generate .dll in order to transmit data between two programs: essentially, one program notifies the other when an event occurs. I'm trying to do this via a TcP client socket.
my header file goes something like this:
#include <string>
using namespace std;
extern "C"
{
__declspec (dllexport) bool trackerConnect( char* ipAddress, int port );
__declspec (dllexport) void sendEvent ( char* ev);
__declspec (dllexport) void disconnect();
}
My .cpp file looks something like this
#define WIN32_LEAN_AND_MEAN
#include "logEvents.h"
#using "system.dll"
using namespace System;
using namespace System::Net;
using namespace System::Net::Sockets;
using namespace System::Text;
TcpClient^ logClient;
NetworkStream^ logStream;
bool trackerConnect( char* ipAddress, int port )
{
/*Connects to server, gets stream, and returns whether the connection was
successful or not*/
}
void sendEvent ( char* ev )
{
/*Converts ev into a Byte array and sends it to the server to notify it
that an event has occurred*/
}
void disconnect ()
{
//closes the connection with the server
}
Given that all three functions need access to the TcPClient, I declared it as a global variable. However, when I compile, I get error C3145: global or static variable may not have managed type. If I can't declare the TcPClient as a global variable, how am I supposed to use it in the three functions?
I'm trying to use WTL within an in-process COM server DLL (an IE BHO), but am struggling with _Module.
My DLL needs CMyModule derived from CAtlDllModuleT<>:
class CMyModule : public CAtlDllModuleT< CMyModule >
{
public:
DECLARE_LIBID(LIBID_MyLib)
DECLARE_REGISTRY_APPID_RESOURCEID(IDR_MYPROJ, "{...}")
};
CMyModule _Module;
extern "C" BOOL WINAPI DllMain(...)
{
hInstance;
return _Module.DllMain(dwReason, lpReserved);
}
...
STDAPI DllUnregisterServer(void)
{
return _Module.DllUnregisterServer();
}
But this conflicts with most WTL examples, which require something like this within stdafx.h:
extern CAppModule _Module; // WTL version of CComModule
No matter which way I do it, I (unsurprisingly) get compile errors. CMyModule derived from CAppModule borks on _Module.DllUnregisterServer(), etc. CMyModule derived from CAtlDllModuleT<> borks on code like _Module.GetMessageLoop().
Any good references on how WTL is supposed to work within a DLL? Google finds lots of questions, with few answers.
I have a project that uses WTL in a DLL. I looked at how my headers are set up and it looks like I hacked around this same problem...
I have my module set up like your sample code inheriting from CAtlDllModuleT<> except the name of the global module variable is _AtlModule rather than _Module. For example:
class CMyModule : public CAtlDllModuleT< CMyModule >
{
public:
DECLARE_LIBID(LIBID_MyLib)
DECLARE_REGISTRY_APPID_RESOURCEID(IDR_MYPROJ, "{...}")
};
CMyModule _AtlModule;
So, all of the DllMain.cpp entry points use _AtlModule. Then in the stdafx.h file it looks like this:
// WTL includes
#define _Module (*_pModule)
#include <atlapp.h>
#include <atlctrls.h>
#include <atldlgs.h>
#undef _Module
That _pModule thing is defined in atlbase.h like:
__declspec(selectany) CComModule* _pModule = NULL;
There must be a better way, but this does work.
Have you considered the option of multiple inheritance? Try inheriting from both CAtlDllModule and CAppModule since you need both.
I use WTL in an Office add-in; the following works for me. (At the bottom of stdafx.h)
class DECLSPEC_UUID("XXXX-...") MyLib;
using namespace ATL;
/*
* Application module
*/
class CAddInModule : public CAtlDllModuleT< CAddInModule >
{
public:
CAddInModule() : m_hInstance(NULL)
{
}
DECLARE_LIBID(__uuidof(MyLib))
HINSTANCE GetResourceInstance()
{
return m_hInstance;
}
void SetResourceInstance(HINSTANCE hInstance)
{
m_hInstance = hInstance;
}
private:
HINSTANCE m_hInstance;
};
extern CAddInModule _AtlModule;
And then the DLL main use _AtlModule:
// DLL Entry Point
extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
_AtlModule.SetResourceInstance(hInstance);
return _AtlModule.DllMain(dwReason, lpReserved);
}
// Used to determine whether the DLL can be unloaded by OLE
STDAPI DllCanUnloadNow(void)
{
return _AtlModule.DllCanUnloadNow();
}
// Returns a class factory to create an object of the requested type
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
{
return _AtlModule.DllGetClassObject(rclsid, riid, ppv);
}
// DllRegisterServer - Adds entries to the system registry
STDAPI DllRegisterServer(void)
{
// registers object, typelib and all interfaces in typelib
HRESULT hr = _AtlModule.DllRegisterServer();
return hr;
}
// DllUnregisterServer - Removes entries from the system registry
STDAPI DllUnregisterServer(void)
{
HRESULT hr = _AtlModule.DllUnregisterServer();
return hr;
}