I've been spending way too much time on this problem.
I am developing a project that uses COM in the Visual Studio 2019 Enterprise edition. I have the following interface defined in my IDL file:
// IIOLinkBusMdlExt
[
object,
uuid(1E0C9381-E5F6-4C39-8660-C64A519FDC51),
dual,
nonextensible,
helpstring("IIOLinkBusMdlExt Interface"),
pointer_default(unique)
]
interface IIOLinkBusMdlExt : IDispatch
{
[propget, id(1), helpstring("ChannelMode getter")]
HRESULT ChannelMode(
[in] unsigned short ChannelNumber,
[out, retval] enum IOLinkChannelMode* pChannelMode
);
[propput, id(1), helpstring("ChannelMode setter")]
HRESULT ChannelMode(
[in] unsigned short ChannelNumber,
[in] enum IOLinkChannelMode ChannelMode
);
[propget, id(2), helpstring("method GetChannelModeString")]
HRESULT ChannelModeString(
[in] unsigned short ChannelNumber,
[out, retval] BSTR* pModeString
);
[id(3), helpstring("method Initialize")]
HRESULT Initialize(
[in] SAFEARRAY(IOLinkChannelMode)
);
};
Note that the I in "Initialize" is capitalized.
But the .tlh file contains this:
struct __declspec(uuid("1e0c9381-e5f6-4c39-8660-c64a519fdc51"))
IIOLinkBusMdlExt : IDispatch
{
//
// Raw methods provided by interface
//
virtual HRESULT __stdcall get_ChannelMode (
/*[in]*/ unsigned short ChannelNumber,
/*[out,retval]*/ enum IOLinkChannelMode * pChannelMode ) = 0;
virtual HRESULT __stdcall put_ChannelMode (
/*[in]*/ unsigned short ChannelNumber,
/*[in]*/ enum IOLinkChannelMode pChannelMode ) = 0;
virtual HRESULT __stdcall get_ChannelModeString (
/*[in]*/ unsigned short ChannelNumber,
/*[out,retval]*/ BSTR * pModeString ) = 0;
virtual HRESULT __stdcall initialize (
/*[in]*/ SAFEARRAY * __MIDL__IIOLinkBusMdlExt0000 ) = 0;
};
Now the i in initialize is lower case!
I verified that the .tlh file is getting rebuilt when the IDL changes by removing the declaration of Initialize() from the IDL and then looking at the .tlh file. The method was not there. Then I put the Initialize() declaration, spelled correctly, back into the IDL, rebuilt, and the method reappeared, spelled incorrectly, in the .tlh file.
What is happening?
Related
I have been trying to figure this out for a few days now and cannot figure it out. I am using CCS as the IDE and I am working on windows. I am trying to create an RTOS Kernel on a MSP432 and need to use pthreads. I have been able to use pthreads in other examples but I am trying to do my own program and I get this issue when building :
unresolved symbol pthread_create, first referenced in ./armrtk/src/task.obj
I have included the file path into CCS and I cannot use a .cfg file because I am not using XDCTools. I just need help with this and I greatly appreciate it.
I also get a warning:
in pthread_create in TASK.C: #169-D argument of type "void *" is incompatible with parameter of type "void *(*)(void *)"
TASK.H
#ifndef TASK_H
#define TASK_H
#include <pthread.h>
struct task_t {
pthread_t* thread;
int threadCheck;
int state;
};
void *task1(void);
void *task2(void);
struct task_t *create_task(void* functionptr);
void delete_task(void *task);
#endif
TASK.C
#include <task.h>
#include <stdlib.h>
#include <pthread.h>
#define BLOCKED -1
#define READY 0
#define RUNNING 1
int testValue1 = 0;
int testValue2 = 0;
struct task_t *new_task;
pthread_t pntr;
struct task_t *create_task(void* functionptr) {
new_task = malloc(sizeof(struct task_t));
if(!new_task)
return NULL;
//set State of the new thread to ready
new_task->state = 0;
// check to see if pthread is created
**new_task->threadCheck = pthread_create(new_task->thread, NULL, functionptr, NULL);**
if(new_task->threadCheck!= 0){
//thread failed
return NULL;
}
return new_task;
}
void delete_task(void *task) {
if(task != NULL){
free(task);
pthread_exit(NULL);
}
}
The unresolved symbol error is a linker error, not a compiler error. You have failed to link the pthreads library.
With respect to the warning functionptr is a void* where pthread_create() expects a pointer-to-function with signature void fn(void*).
Your task functions have a different signature in any case: void fn(void), so in any event you will need to cast the function pointer in the call to pthread_create() (although you are loosing a useful means of passing information into a task function by omiting the void* argument).
Modify task.h:
typedef void* (*task_t)(void);
struct task_t *create_task( task_t functionptr);
The in task.cpp
new_task->threadCheck = pthread_create( new_task->thread,
NULL,
(void (*)(void *))functionptr,
NULL ) ;
The cast in the pthread_create() call alone would supress the warning, but it bad form to pass a function pointer as a generic void* since it would prevent the compiler warning you if you were to pass anything other then a function pointer of the expected form to to the create_task()`
https://docs.perl6.org/language/nativecall
"As you may have predicted by now, a NULL pointer
is represented by the type object of the struct type."
https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regqueryvalueexw
C++
LSTATUS RegQueryValueExW(
HKEY hKey,
LPCWSTR lpValueName,
LPDWORD lpReserved,
LPDWORD lpType,
LPBYTE lpData,
LPDWORD lpcbData
);
lpReserved
This parameter is reserved and must be NULL.
With "native", how do I satisfy the "NULL" requirement?
constant WCHAR := uint16;
constant DWORD := int32;
sub RegQueryValueExW( DWORD, WCHARS, DWORD, DWORD, DWORD is rw, DWORD is rw ) is native("Kernel32.dll") returns DWORD { * };
$RtnCode = RegQueryValueExW( $Handle, $lpValueName, int32, REG_DWORD, $lpData, $lpcbData );
"int32" returns:
Cannot unbox a type object (int32) to int in method
CALL-ME at C:\rakudo\share\perl6\sources \947BDAB9F96E0E5FCCB383124F9
23A6BF6F8D76B (NativeCall) line 587
Many thanks,
-T
To pass a pointer to a DWORD you can use a CArray[DWORD]. For example, here I created a test library libmylib.so with a foo() function taking DWORD * (aka int32_t *) argument:
#include <stdio.h>
#include <stdint.h>
void foo (int32_t *bar) {
if ( bar == NULL ) {
printf( "Got NULL pointer\n" );
}
else {
printf("Got bar: %d\n", bar[0]);
}
}
Then test a Raku interface to this library using:
use v6;
use NativeCall;
constant DWORD := int32;
sub foo(CArray[DWORD]) is native("./libmylib.so") { * };
my #bar := CArray[DWORD].new;
#bar[0] = 1;
foo(#bar);
foo(CArray[DWORD]); # <-- Use a type object to pass a NULL pointer
Output:
Got bar: 1
Got NULL pointer
JJ and Brad on the Perl6 mailing list were correct. For a NULL, just pass it a zero. I had a booboo somewhere else.
I am creating a currency converter Win32 program in Embarcadero C++Builder. I wrote a function for transforming date from format specified on user PC to YYYY-MM-DD format. I need that part because of API settings.
When I have this function inside my project it works fine, but I need to have that function inside a DLL.
This is how my code looks like:
#pragma hdrstop
#pragma argsused
#include <SysUtils.hpp>
extern DELPHI_PACKAGE void __fastcall DecodeDate(const System::TDateTime DateTime, System::Word &Year, System::Word &Month, System::Word &Day);
extern "C" UnicodeString __declspec (dllexport) __stdcall datum(TDateTime dat) {
Word dan, mjesec, godina;
UnicodeString datum, datum_dan, datum_mjesec, datum_godina;
DecodeDate(dat, godina, mjesec, dan);
if (dan<=9 && mjesec<=9) {
datum_dan="0"+IntToStr(dan);
datum_mjesec="0"+IntToStr(mjesec);
}
if (dan<=9 && mjesec>9) {
datum_dan="0"+IntToStr(dan);
datum_mjesec=IntToStr(mjesec);
}
if (dan>9 && mjesec<=9) {
datum_dan=IntToStr(dan);
datum_mjesec="0"+IntToStr(mjesec);
}
if (dan>9 && mjesec>9) {
datum_dan=IntToStr(dan);
datum_mjesec=IntToStr(mjesec);
}
datum_godina=IntToStr(godina);
return datum_godina+"-"+datum_mjesec+"-"+datum_dan;
}
extern "C" int _libmain(unsigned long reason)
{
return 1;
}
`
I've included SysUtils.hpp and declared DecodeDate() function, without those lines I have a million errors. But with code looking like this, I am getting this error, which I can't get rid of:
[bcc32 Error] File1.cpp(30): E2015 Ambiguity between '_fastcall System::Sysutils::DecodeDate(const System::TDateTime,unsigned short &,unsigned short &,unsigned short &) at c:\program files (x86)\embarcadero\studio\19.0\include\windows\rtl\System.SysUtils.hpp:3466' and '_fastcall DecodeDate(const System::TDateTime,unsigned short &,unsigned short &,unsigned short &) at File1.cpp:25'
Full parser context
File1.cpp(27): parsing: System::UnicodeString __stdcall datum(System::TDateTime)
Can you help me to get rid of that error?
The error message is self-explanatory. You have two functions with the same name in scope, and the compiler doesn't know which one you want to use on line 30 because the parameters you are passing in satisfy both function declarations.
To fix the error, you can change this line:
DecodeDate(dat, godina, mjesec, dan);
To either this:
System::Sysutils::DecodeDate(dat, godina, mjesec, dan);
Or this:
dat.DecodeDate(&godina, &mjesec, &dan);
However, either way, you should get rid of your extern declaration for DecodeDate(), as it doesn't belong in this code at all. You are not implementing DecodeDate() yourself, you are just using the one provided by the RTL. There is already a declaration for DecodeDate() in SysUtils.hpp, which you are #include'ing in your code. That is all the compiler needs.
Just make sure you are linking to the RTL/VCL libraries to resolve the function during the linker stage after compiling. You should have enabled VCL support when you created the DLL project. If you didn't, recreate your project and enable it.
BTW, there is a MUCH easier way to implement your function logic - instead of manually pulling apart the TDateTime and reconstituting its components, just use the SysUtils::FormatDateTime() function or the TDateTime::FormatString() method instead, eg:
UnicodeString __stdcall datum(TDateTime dat)
{
return FormatDateTime(_D("yyyy'-'mm'-'dd"), dat);
}
UnicodeString __stdcall datum(TDateTime dat)
{
return dat.FormatString(_D("yyyy'-'mm'-'dd"));
}
That being said, this code is still wrong, because it is not safe to pass non-POD types, like UnicodeString, over the DLL boundary like you are doing. You need to re-think your DLL function design to use only interop-safe POD types. In this case, change your function to either:
take a wchar_t* as input from the caller, and just fill in the memory block with the desired characters. Let the caller allocate the actual buffer and pass it in to your DLL for populating:
#pragma hdrstop
#pragma argsused
#include <SysUtils.hpp>
extern "C" __declspec(dllexport) int __stdcall datum(double dat, wchar_t *buffer, int buflen)
{
UnicodeString s = FormatDateTime(_D("yyyy'-'mm'-'dd"), dat);
if (!buffer) return s.Length() + 1;
StrLCopy(buffer, s.c_str(), buflen-1);
return StrLen(buffer);
}
extern "C" int _libmain(unsigned long reason)
{
return 1;
}
wchar_t buffer[12] = {};
datum(SomeDateValueHere, buffer, 12);
// use buffer as needed...
int len = datum(SomeDateValueHere, NULL, 0);
wchar_t *buffer = new wchar_t[len];
int len = datum(SomeDateValueHere, buffer, len);
// use buffer as needed...
delete[] buffer;
allocate a wchar_t[] buffer to hold the desired characters, and then return a wchar_t* pointer to that buffer to the caller. Then export a second function that the caller can pass the returned wchar_t* back to you so you can free it correctly.
#pragma hdrstop
#pragma argsused
#include <SysUtils.hpp>
extern "C" __declspec(dllexport) wchar_t* __stdcall datum(double dat)
{
UnicodeString s = FormatDateTime("yyyy'-'mm'-'dd", dat);
wchar_t* buffer = new wchar_t[s.Length()+1];
StrLCopy(buffer, s.c_str(), s.Length());
return buffer;
}
extern "C" __declspec(dllexport) void __stdcall free_datum(wchar_t *dat)
{
delete[] dat;
}
extern "C" int _libmain(unsigned long reason)
{
return 1;
}
wchar_t *buffer = datum(SomeDateValueHere);
// use buffer as needed...
free_datum(buffer);
I am trying to code an alternative to LoadLibrary function, based on the idea of calling the function LdrLoadDll from ntdll.
This function needs as a parameter the dll file to load, in a UNICODE_STRING format.
I really can't get what I am doing wrong here (string seems to be correctly initialized), but when LdrLoadDll is called, I get the following error:
Unhandled exception in "Test.exe" (NTDLL.DLL): 0xC0000005: Access Violation.
I use Visual C++ 6.0 for this test, and I am using Windows 7 64 bit.
I post full code here, thanks in advance for any help:
#include <Windows.h>
typedef LONG NTSTATUS; //To be used with VC++ 6, since NTSTATUS type is not defined
typedef struct _UNICODE_STRING { //UNICODE_STRING structure
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING;
typedef UNICODE_STRING *PUNICODE_STRING;
typedef NTSTATUS (WINAPI *fLdrLoadDll) //LdrLoadDll function prototype
(
IN PWCHAR PathToFile OPTIONAL,
IN ULONG Flags OPTIONAL,
IN PUNICODE_STRING ModuleFileName,
OUT PHANDLE ModuleHandle
);
/**************************************************************************
* RtlInitUnicodeString (NTDLL.#)
*
* Initializes a buffered unicode string.
*
* RETURNS
* Nothing.
*
* NOTES
* Assigns source to target->Buffer. The length of source is assigned to
* target->Length and target->MaximumLength. If source is NULL the length
* of source is assumed to be 0.
*/
void WINAPI RtlInitUnicodeString(
PUNICODE_STRING target, /* [I/O] Buffered unicode string to be initialized */
PCWSTR source) /* [I] '\0' terminated unicode string used to initialize target */
{
if ((target->Buffer = (PWSTR) source))
{
unsigned int length = lstrlenW(source) * sizeof(WCHAR);
if (length > 0xfffc)
length = 0xfffc;
target->Length = length;
target->MaximumLength = target->Length + sizeof(WCHAR);
}
else target->Length = target->MaximumLength = 0;
}
NTSTATUS LoadDll( LPCSTR lpFileName)
{
HMODULE hmodule = GetModuleHandleA("ntdll.dll");
fLdrLoadDll _LdrLoadDll = (fLdrLoadDll) GetProcAddress ( hmodule, "LdrLoadDll" );
int AnsiLen = lstrlenA(lpFileName);
BSTR WideStr = SysAllocStringLen(NULL, AnsiLen);
::MultiByteToWideChar(CP_ACP, 0, lpFileName, AnsiLen, WideStr, AnsiLen);
UNICODE_STRING usDllFile;
RtlInitUnicodeString(&usDllFile, WideStr); //Initialize UNICODE_STRING for LdrLoadDll function
::SysFreeString(WideStr);
NTSTATUS result = _LdrLoadDll(NULL, LOAD_WITH_ALTERED_SEARCH_PATH, &usDllFile,0); //Error on this line!
return result;
}
void main()
{
LoadDll("Kernel32.dll");
}
in
_LdrLoadDll(NULL, LOAD_WITH_ALTERED_SEARCH_PATH, &usDllFile,0);
last parameter can't be zero
you can't call SysFreeString before you call _LdrLoadDll,
since the usDllFile.buffer parameter points to this string
How can I iterate/access the vtable of COM coclass which will implement the methods of its exposed interfaces?
I need to access the part of the vtable where all addresses of exposed methods of its interfaces are stored.
e.g. Math is COM object, its exposed interface is "Operations" and "Sum" is the method of this interface, how do I get the address of "Sum"?
I'm not going to ask why are you doing it this way, but perhaps this could help...
Every COM object must implement at least the IUnknown interface. Hence, the first four bytes of the COM object instance is the pointer to IUnknown object. The first four bytes of the IUnknown object (and any other object with virtual functions) is the pointer to vtbl.
(There is no error checking in this example, so please don't split hair on that subject.)
I used an instance of IReferenceClock for demonstration.
int main()
{
CoInitialize( NULL );
IReferenceClock* pRefClock;
HRESULT hr = CoCreateInstance( CLSID_SystemClock, NULL, CLSCTX_INPROC_SERVER, IID_IReferenceClock, (void**)&pRefClock );
DWORD* pIUnknownAddress = (DWORD*)pRefClock;
DWORD* pVTBLaddress = (DWORD*)*pIUnknownAddress;
// for example, the next interface could be accessed like this
DWORD* pNextInterfaceAddress = ( (DWORD*)pRefClock ) + 1;
DWORD* pNextVTBLaddress = (DWORD*)*pNextInterfaceAddress;
// and you would access virtual functions in the same way as QueryInterface, AddRef and Release below in this example
HRESULT (__stdcall *pQueryInterfaceFunction)(void*, REFIID, void**);
ULONG (__stdcall *pAddRef)( void* );
ULONG (__stdcall *pRelease)( void* );
// IUnknown looks like this:
//
// virtual HRESULT QueryInterface( REFIID riid, void** ppvObject);
// virtual ULONG AddRef( void );
// virtual ULONG Release( void );
//
// So, the first function in vtbl is QueryInterface, the second is AddRef...
pQueryInterfaceFunction = (HRESULT (__stdcall*)(void*, REFIID, void**))*pVTBLaddress;
pAddRef = (ULONG (__stdcall *)( void* ))*( pVTBLaddress + 1 );
pRelease = (ULONG (__stdcall *)( void* ))*( pVTBLaddress + 2 );
// Note: extra void* is actually this pointer.. see below that we pass pRefClock to every call
IUnknown* pUnknown;
UINT nRefCount;
hr = pQueryInterfaceFunction( pRefClock, IID_IUnknown, (void**)&pUnknown );
if( SUCCEEDED( hr ) )
{
nRefCount = pUnknown->Release();
ATLTRACE( TEXT( "nRefCount = %d\n" ), nRefCount );
}
nRefCount = pAddRef( pRefClock );
ATLTRACE( TEXT( "nRefCount after AddRef() call = %d\n" ), nRefCount );
nRefCount = pRelease( pRefClock );
ATLTRACE( TEXT( "nRefCount after Release() call = %d\n" ), nRefCount );
nRefCount = pRefClock->Release();
CoUninitialize();
return 0;
}
Sorry to answer with a question, but I have to ask "from where?"
If you mean, how can you iterate through the vtable from a COM client, I don't think you can. On the client side, all you have is a proxy that knows how to communicate (maybe cross-apartment or cross-process) with the COM server. You could maybe probe the vtable of that proxy, but it can never tell you the addresses of the functions inside the COM server.
Of course, if the server is actually running in a different process, the address of the functions might be of little use to you. Even if the server is in the same process, but in a different apartment, getting function addresses might be dangerous: you could call the functions directly, circumventing COM's interception, and break the server class's assumptions around calling thread, etc.
I guess that iterating the vtable is a means-to-an-end...? Maybe post what you're actually trying to do and I think COM probably has a way to do it.