what's wrong in my code related to COM? - c++

*****BLOCK_1****
if( strcmpi(appName.c_str(),MSSQL)==0 ||strcmpi(appName.c_str(),MSSQL2005)==0 )
{
if (FAILED(CoCreateInstance (CLSID_SQLDMOServer, NULL, CLSCTX_INPROC_SERVER,
IID_ISQLDMOServer, (LPVOID*)&m_pSQLServer))) {
DMOAvailable=false;
IDiscoverPtr pICalc;
HRESULT hRes=CoCreateInstance(Test::CLSID_SqlClass, NULL, CLSCTX_INPROC_SERVER,Test::IID_IDiscover, reinterpret_cast<void**> (&pICalc));
if(FAILED(hRes))
{
cout << "CoCreateInstance Failed on CLSID_SQLDMOServer\n";
return FALSE;
}
***BLOCK_2***
if((strcmpi(appName.c_str(),MSSQL2008)==0 || strcmpi(appName.c_str(),MSSQL2005)==0 ) && DMOAvailable==false )
{
HRESULT hr=CoInitialize(NULL);
IDiscoverPtr pICalc(__uuidof(SqlClass));
if(FAILED(CoCreateInstance(Test::CLSID_SqlClass, NULL, CLSCTX_INPROC_SERVER,
Test::IID_IDiscover, reinterpret_cast<void**> (&pICalc))))
{
cout<<" Loading SQLSMO failed This is because of SMO not Available "<<endl;
return FALSE;
}
}
*****BLOCK_3 ****
if((strcmpi(appName.c_str(),MSSQL2008)==0 && DMOAvailable==true))
{
HRESULT hr= CoInitialize(NULL);
cout<<"\nIn Init SqlServer DMO-true and SQL2008"<<endl;
HRESULT hRes=CoCreateInstance(Test::CLSID_SqlClass, NULL, CLSCTX_INPROC_SERVER,
Test::IID_IDiscover, reinterpret_cast<void**> (&pICalc));
if(FAILED(hRes))
{
printf(" Loading SQLSMO failed This is because of SMO not Available 0x%X\n",hRes)
return FALSE;
}
else
cout<<success;
}
return TRUE;
}
I have prepared the Test.dll in c# and in that i have a an interface IDiscover and a class SqlClass implementing that interface.I have Manually assigned the Guid like this
[System.Runtime.InteropServices.Guid("D4660088-308E-49fb-AB1A-77224F3FF851")]
public interface IDiscover
{
string getSqlInstances(string HostName);
string getDB(string SQLInstanceName);
string getDatabaseInfo(string SQLInstanceName, string DBName);
};
namespace Test
{
[System.Runtime.InteropServices.Guid("46A951AC-C2D9-48e0-97BE-91F3C9E7B065")]
public class SqlClass:IDiscover
{
}
}
I also make COMVisible=true;
and register the class using RegAsm.exe Test.dll/tlb:Test.tlb /codebase
and imported the tlb in one cpp file as #import c:...\Test.tlb named_guids
This is working fine in my Machine And also in My virtual Machine for any case.if i gave sql2005 it works and i gave sql2008 it working.
and in some other machine it shows that errror code as 0x80004002 only when entering into 3rd block.if it enters 1st block and 2nd block its working fine in other machine also.what happening in 3rd block i am not understanding plzzzzzzzz help me in this regard...
Sharptooth u can plzz go through this one .....

When working with COM, your assemblies should be "Release Builds". Make sure that's the case before digging around any further.

These two statements:
IDiscoverPtr pICalc(__uuidof(SqlClass));
HRESULT hRes=CoCreateInstance(Test::CLSID_SqlClass, NULL, CLSCTX_INPROC_SERVER, Test::IID_IDiscover, reinterpret_cast<void**> (&pICalc));
do exactly the same thing, so you don't need to run them in sequence.
The first one translates the HRESULT into an exception of type _com_error. I'd try something like:
IDiscoverPtr pDiscover;
HRESULT hr = pDiscover.CreateInstance(__uuidof(SqlClass));
if (FAILED(hr))
{
printf("SQL DMO is not avilable. Error code: 0x%X\n", hr);
}
Could you post back what the error code is?

The IDiscoverPtr constructor will throw an exception if it can't instantiate the COM object. The most likely reason is that the COM object is not registered in the registry of that machine (regasm was not run for the .NET assembly that implements the IDiscover).

I have seen the error 0x80004002 E_NOINTERFACE if you expose a property of type DateTime on the com visible type you are trying to call CreateInstance() on. I've also noticed that you have to Rebuild the project that imports the tlb file instead of a Build if the tlb file changes for example.

Related

Access violation error with injected dll C++

So recently I made my own dll injector to be able to debug my other app by injecting a debug dll in it; Using c++/cli for the interface and c++ for the code.
I tested the same code I used on this project on a C++ console app project and it worked without any problems.
The injection occurs inside the Init.cpp file, which essentially gets the provided dll path under the form of C:\\user\\documents\\debug.dll and checks if it exists. After that it gets the process id by passing the name, in this case myotherapp.exe, as a parameter. If successful it then get's the Handle to the process and store's it in g.h_process, it continues by allocating readable/writable memory in the process and then writing to this memory the path of the dll and finally use's LoadLibraryA to load the dll inside the process.
Init.cpp:
void Injector::Init(void)
{
Inject::Checks((char*)g.dll_path, g.procName);//checking for dll validity
}
bool Injector::Inject::Checks(char* dll_path, PCSTR procName)
{
if (!Utils::file_exists(dll_path))
return Utils::error("File does not exist.");
Utils::successInput("Prepared DLL for injection");
Utils::getProcId(procName, g.proc_id);
if (!g.proc_id) {
return Utils::error("Could not find specified process.");
}
g.h_process = OpenProcess(PROCESS_ALL_ACCESS, NULL, g.proc_id);
if (!g.h_process) {
return Utils::error("Failed to open a handle to process");
}
g.allocatedMemory = VirtualAllocEx(g.h_process, nullptr, MAX_PATH, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);//mem_reserver reserve memory then commit memory to be able to write to that memory
Allocate(g.allocatedMemory, dll_path);
Llib();
Release(dll_path, g.allocatedMemory);
return 0;
}
bool Injector::Inject::Allocate(void* allocatedMemory, char* dll_path)
{
if (!allocatedMemory)
return Utils::error("Failed to allocate memory");
if (!WriteProcessMemory(g.h_process, g.allocatedMemory, g.dll_path, MAX_PATH, nullptr))
return Utils::error("Failed to write process");
return true;
}
bool Injector::Inject::Llib() {
HANDLE h_thread = CreateRemoteThread(g.h_process, nullptr, NULL, LPTHREAD_START_ROUTINE(LoadLibraryA), g.allocatedMemory, NULL, nullptr);
if (!h_thread)
return Utils::error("Failed to create remote thread");
return true;
}
bool Injector::Inject::Release(PCSTR dll_path, void* allocatedMemory)
{
CloseHandle(g.h_process);
VirtualFreeEx(g.h_process, allocatedMemory, NULL, MEM_RELEASE);
return true;
}
The g.debug is just a flag which tells us if the console is enabled or not. found in the globals.hpp which just contains global variables.
You can also check the Utils namespace here.
The error:
The problem I'm experiencing here is whenever I inject my DLL into the process, my injector works fine with no errors but when I attach vs to the process I want to inject to I get an Access Violation error with the process exiting with an error code.
I don't understand, I can't see where I am accessing invalid memory.
Thanks in advance.

Calling GetDisplayName returns same result as GetIconPath

I currently have this code, iterating over the audio session controls of the default device (not shown):
int sessionCount;
hr = audioSessionEnumerator->GetCount(&sessionCount);
if (FAILED(hr)) {
throw HRESULTException("audioSessionEnumerator->GetCount", hr);
}
IAudioSessionControl *audioSessionControl;
for (int i = 0; i < sessionCount; ++i) {
hr = audioSessionEnumerator->GetSession(i, &audioSessionControl);
if (FAILED(hr)) {
throw HRESULTException("audioSessionEnumerator->GetSession", hr);
}
LPWSTR displayName;
hr = audioSessionControl->GetDisplayName(&displayName);
if (FAILED(hr)) {
throw HRESULTException("audioSessionControl->GetDisplayName", hr);
}
std::wcout << displayName << std::endl;
CoTaskMemFree(displayName);
audioSessionControl->Release();
}
audioSessionEnumerator->Release();
My mixer currently looks like this:
The expected output is:
Steam Client Bootstrapper
melodysheep - The Face of Creation
System Sounds
However, the output seen is:
(blank line)
(blank line)
#%SystemRoot%\System32\AudioSrv.Dll,-202
Which is the same as the output when GetDisplayName is replaced with GetIconPath.
What problem occurs in the code above to cause this issue? If more code must be shown, please inform me.
If you read the remarks for both GetDisplayName and GetIconName in MSDN you'll see that the functions can return NULL if no-one has set them. The GetIconName page also then remarks that the sndvol application (which you've got a screenshot of) will actually look up the icon of the main window if it's NULL, and therefore by induction will lookup the main window title for the display name if it doesn't exist.
You probably want to query for the IAudioSessionControl2 interface which has a GetProcessId method which might return you the client process id. At which point you can use things like this and this to try and extract the values from the main window to be consistent.

What is the different between system and Administrator account when call SHGetSpecialFolderLocation() function?

I write two program, one is windows service run in system account(named xxService) and the other one is common application run in Administrator account(named xx);
They use the same code to get CSIDL_COMMON_DOCUMENTS directory. In most machine , they run well.
But some machine, the xxService can get the correct directory, the xx have failure in SHGetSpecialFolderLocation();
edit:
the program only run on Windows XP(sp3).
edit2:
Use SHGetFolderPathA() function to solve this problem.
My english is poor, everybody excuse me!
log:
[2964] [db](tid=1108)(pid=2964): SHGetSpecialFolderLocation() fail.hr=0x80070057, ierr=122
the detail error info:
//
// MessageId: E_INVALIDARG
//
// MessageText:
//
// One or more arguments are invalid
//
#define E_INVALIDARG _HRESULT_TYPEDEF_(0x80070057L)
ERROR_INSUFFICIENT_BUFFER
122 (0x7A)
The data area passed to a system call is too small.
code:
//C:\Users\Public\Documents
LPITEMIDLIST pidl;
LPMALLOC pShellMalloc;
HRESULT hr = S_FALSE;
hr = SHGetMalloc(&pShellMalloc);
if(SUCCEEDED(hr))
{
hr = SHGetSpecialFolderLocation(NULL,CSIDL_COMMON_DOCUMENTS,&pidl);
if(SUCCEEDED(hr))
{
if(!SHGetPathFromIDListW(pidl, strDbFilePath))
{
int ierr=GetLastError();
DebugMsgW((L"SHGetPathFromIDListW() fail., ierr=%d"), ierr);
}
DebugMsgW(L"DBpath=%s",strDbFilePath);
pShellMalloc->Free(pidl);
}
else
{
int ierr=GetLastError();
DebugMsgW((L"SHGetSpecialFolderLocation() fail.hr=0x%x, ierr=%d"), hr, ierr);
}
pShellMalloc->Release();
}
else
{
int ierr=GetLastError();
DebugMsgW((L"SHGetMalloc() fail.hr=0x%x, ierr=%d"), hr, ierr);
}
SHGetSpecialFolderLocation() (and any other function that returns an HRESULT) does not use GetLastError() to report error codes, since the HRESULT is the error code. Even SHGetPathFromIDList() is not documented as using GetLastError(), either. So the return value of GetLastError() is irrelevant in your example and needs to be removed to avoid confusion.
As for the E_INVALIDARG error, you are using a legacy function. CSIDL_COMMON_DOCUMENTS is known to fail in SHGetSpecialFolderLocation() on some systems. You need to use a newer function, such as SHGetFolderPath(), or SHGetKnownFolderPath() on Vista+.

E_NOINTERFACE when calling CreateDXGIFactory1

I am relatively new to C++ in general, and very new to Windows development.
I am writing a program that uses the DXGI library - it compiles just fine, but when I run the executable, the HRESULT from the CreateDXGIFactory1 comes out as 0x80004002, or E_NOINTERFACE.
Am I missing some sort of library, or is there a deeper issue at play here?
The code I am using follows:
Output is "Error: 0x80004002".
//Initialize a UUID
GUID uuid;
HRESULT hCreateUUID = CoCreateGuid(&uuid);
//Convert the UUID to string
LPOLESTR stringUUID;
HRESULT hStringToUUID = StringFromCLSID(uuid, &stringUUID);
//Initialize the factory pointer
IDXGIFactory1* pFactory;
//Actually create it
HRESULT hCreateFactory = CreateDXGIFactory1(uuid, (void**)(&pFactory));
if (hCreateFactory == S_OK) {
printf("Factory creation was a success\n");
} else {
printf("ERROR: 0x%X\n", hCreateFactory);
}
You are passing a random, freshly created GUID. This makes no sense. You are supposed to pass the IID of the interface you wish to obtain - namely, __uuidof(IDXGIFactory1). The example in the documentation shows just that.

Direct2d CreateBitmapfromWICBitmap giving assert error within ATL

I have a simple function that loads a Png file and returns it as a ID2D1Bitmap. But when it tries to call the CreateBitmapfromWicBitmap function, it gives a debug assert error. The funny thing is that I first made an imageload function in a seperate project, and it works fine in there. Both of these functions have the same code, while the second one is giving errors.
Here's the erroring code:
ID2D1Bitmap* Wnd::LoadPng(LPCWSTR Path) {
CComPtr<IWICBitmapDecoder> pDecoder;
CComPtr<IWICBitmapFrameDecode> pFrame;
CComPtr<ID2D1Bitmap> pBit;
CComPtr<IWICFormatConverter> pConv;
HRESULT Hr;
Hr = m_pWICFactory->CreateDecoderFromFilename(Path,NULL,GENERIC_READ,WICDecodeMetadataCacheOnDemand,&pDecoder);
if (SUCCEEDED(Hr)) {
Hr = m_pWICFactory->CreateFormatConverter(&pConv);
}
if (SUCCEEDED(Hr)) {
Hr = pDecoder->GetFrame(0,&pFrame);
}
if (SUCCEEDED(Hr)) {
Hr = pConv->Initialize(pFrame,GUID_WICPixelFormat32bppPBGRA,WICBitmapDitherTypeNone,0,0.f,WICBitmapPaletteTypeCustom);
}
if (SUCCEEDED(Hr)) {
Hr = m_pRT->CreateBitmapFromWicBitmap(pConv,0,&pBit);
}
return pBit;
}
The error happens in atlcomcli.h at line 182 in function _NoAddRefReleaseOnCComPtr.
I double-checked all headers and libraries and they're the same in both projects (With some extra headers in the second project).
Here's the code that WORKS:
CComPtr<IWICFormatConverter> Conv;
m_pWICFactory->CreateFormatConverter(&Conv);
CComPtr<IWICBitmapFrameDecode> Frame;
m_pDecoder->GetFrame(0,&Frame);
Frame->GetSize(&W,&H);
Conv->Initialize(Frame,GUID_WICPixelFormat32bppPBGRA,WICBitmapDitherTypeNone,0,0.f,WICBitmapPaletteTypeCustom);
CComPtr<ID2D1Bitmap> Bit;
Hr = m_pRT->CreateBitmapFromWicBitmap(Conv,0,&Bit);
m_pBitmap.push_back(Bit);
BitmapDecoder is predefined here, but it's exactly the same as in the first snippet.
------------------------------- FIXED ----------------------------
Third time I forgot to call the init function for my rendertarget.
The assertion failure warns you that you are trying to "use" a NULL interface pointer through CComPtr template. You should look up on the call stack which exactly line of your code you are at, and what variable holds NULL pointer which you expect to be non-NULL. Or otherwise just step through your code with debugger.