Using XP's CD writing support

  • Thread starter Thread starter Bob
  • Start date Start date
B

Bob

Hi there,

Can anyone point me to anything relating to using XP's built-in CD writing
support from VB.Net... or even C#, or classic VB...?

I just want to write files to the CD and finalise the session and disk.

Cheers
 
Herfried,

Thanks for the info... I'll check it out but I'd rather see something using
the other .Net languages... I don't see why it wouldn't be possible..?

Cheers
 
Hi Bob,

You are going to have to define the interface yourself in code, and then
find the GUID of the co class that implements it. Once you have that, you
can use the methods on the Marshal class and Activator class to create your
instance and get a wrapper of the appropriate type (using CreateInstance
and CreateWrapperOfType).

http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&oe=UTF-8&threadm=90079f6d
0204020218.42bff604%40posting.google.com&rnum=1&prev=/groups%3Fhl%3Den%26lr
%3D%26ie%3DUTF-8%26oe%3DUTF-8%26q%3Dxp%2Bcd%2Bburning%2B%2522c%2523%2522%26s
a%3DN%26tab%3Dwg

http://www.microsoft.com/seminar/shared/asp/view.asp?url=/seminar/en/2002091
8devt1-63/manifest.xml
slide 59 has what customer is trying to figure out.

If you have any related question please post here.

Regards,
Peter Huang
Microsoft Online Partner Support
Get Secure! www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
This response contains a reference to a third-party World Wide Web site.
Microsoft is providing this information as a convenience to you. Microsoft
does not control these sites and has not tested any software or information
found on these sites; therefore, Microsoft cannot make any representations
regarding the quality, safety, or suitability of any software or
information found there. There are inherent dangers in the use of any
software found on the Internet, and Microsoft cautions you to make sure
that you completely understand the risk before retrieving any software from
the Internet.
 
Hmmm...

Looks like a lot of work to do something fairly simple... I was thinking
more along the lines of copying the files to the CD drive and then calling
the Write Files option in the context menu (when right clicking on the
cd-writer) programatically... why reinvent the wheel...

Feasible?

Cheers
 
Hi Bob,

Another way is to convert the C++ sample into an COM object so that you can
call it from .NET.

Otherwise, you should do as I posted in last post, that is to say you may
need to implement the least interface needed to complete your task, because
the IMAPI is a set of APIs.

Interacting with IMAPI
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/devio/base/
interacting_with_imapi.asp


Regards,
Peter Huang
Microsoft Online Partner Support
Get Secure! www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
Yeah ok... still a bit stuck on that one... can you repost the google link
as it didn't seem to work... even when I fixed line breaks etc...

Not familiar enough with C++ to be converting it to anything. And I am not
sure how to declare and use the IMAPI API within VB.Net...

I'll see how I go with what you have suggested though...

Cheers
 
Ok, I had a read but it sounds like way too much crap to deal with to do
something so simple. I really am disappointed that the .Net framework has
left out so many basic things... seems that all the power that has been
added doesn't make up for the lack of basic functionality.

Anyway, I realised a while back that .Net wasn't going to deliver everything
it was claimed to. I am trying hard to introduce .Net to the organisation I
am working for (major Unix/Java/Oracle shop) but so far .Net can't really
deliver what they have asked for (working with GINA, CD writing etc). If
these guys decide to dump .Net I'm outta here and that looks like the way
they'll go if simple things like this prove to be this difficult.

In case you ask - they want to avoid C++ as much as I do. So no, I can't get
it done all in C++ - and even if I did, what does that say about the rest of
..Net... might as well stick to a language from the 70's......?????

Are you sure there is no way I can simply call the "Write files" option in
the context menu of the CD/RW drive in Explorer?

Cheers
 
Hello Bob,

I just reviewed the whole post thread. In fact, this is a FAQ in .NET
programming. Many developers may feel confused where to find corresponding
..NET framework class libraries in programming. In fact, all the framwork
class library could be found at:
http://msdn.microsoft.com/library/en-us/cpref/html/cpref_start.asp?frame=tru
e

However, .NET framework class library doesn't build in all Win32 SDK APIs
or functions. That is to say, for some Win32 functions, such as GINA,
setting default printer, burning CD, we still need to use typical Win32 API
to achieve it. In order to do so in .NET programming, we provide a method
named Platform Invoke to call typical Win32 APIs in .NET application. For
more information on PInvoke, please refer to:
http://msdn.microsoft.com/library/en-us/cpguide/html/cpconinteroperatingwith
unmanagedcode.asp?frame=true

For this question, currently we have no famework class library support for
burning CD. My suggestion for you is to write a win32 DLL to expose
funtions that you need. You could select whatever languages you like to
develop this Win32 DLL, VC++ or VB. After that, we could call this
unmanaged DLL functions from managed .NET application easily. Peter Huang
has provided an existing sample to you. I also post some useful code slice
in the end of this post. You could refer to it.

There is currently no way to do this, but keep an eye out for it in the
future. We are looking at continual improvement, and it's this kind of
feedback that let us know what things you're trying to do, that we haven't
yet exposed for you.

Keep the information coming.

Thanks very much for your understanding.

Best regards,
Yanhong Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.


Code Slice:

Below is a simple Imapi sample that works for me. I made a console "Hello
world" project and replaced it with the code below. IT takes a command
line path of a driectory to copy, and I added the string: "e:\\CDBurn.exe"
as a known file that would be in the result.

This works for me.

// cd.cpp : Defines the entry point for the console application. //

#include "stdafx.h"

#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <objbase.h>
#include <stdio.h>
#include <shlobj.h>
#include "imapi.h"

HRESULT GetStorage(LPWSTR pszDir, IStorage **ppstg)
{
IShellFolder *psfDesktop;
HRESULT hr = SHGetDesktopFolder(&psfDesktop);
if (SUCCEEDED(hr))
{
IMalloc *pm;
hr = SHGetMalloc(&pm);
if (SUCCEEDED(hr))
{
LPITEMIDLIST pidl;
hr = psfDesktop->ParseDisplayName(NULL, NULL, pszDir, NULL,
&pidl,
NULL);
if (SUCCEEDED(hr))
{
hr = psfDesktop->BindToObject(pidl, NULL, IID_IStorage,
(void**)ppstg);
pm->Free(pidl);
}
pm->Release();
}
psfDesktop->Release();
}
return hr;
}

HRESULT SetUpRecorder(IDiscMaster *pdm, IJolietDiscMaster *pjdm, LPWSTR
pszDir) {
wprintf(L"Getting recorder enumerator object.\n");

IEnumDiscRecorders *pedr;
HRESULT hr = pdm->EnumDiscRecorders(&pedr);
if (SUCCEEDED(hr))
{
wprintf(L"Finding available drive.\n");

ULONG celt;
IDiscRecorder *pdr;
// pick the first supported drive to write to.
hr = pedr->Next(1, &pdr, &celt);
if (S_OK == hr)
{
wprintf(L"Setting active disc recorder.\n");

hr = pdm->SetActiveDiscRecorder(pdr);
if (SUCCEEDED(hr))
{
IStorage *pstg;
hr = GetStorage(pszDir, &pstg);
if (SUCCEEDED(hr))
{
wprintf(L"Adding data to stash file.\n");
hr = pjdm->AddData(pstg, 1);
pstg->Release();
}
else
{
wprintf(L"Couldn't get storage, please check the
path.\n");
}
}
pdr->Release();
}
else
{
wprintf(L"No supported drives found, HRESULT = 0x%08X\n", hr);
hr = E_FAIL;
}
pedr->Release();
}
return hr;
}

void DoBurn(LPWSTR pszDir)
{
wprintf(L"Burning directory %s.\n", pszDir);

wprintf(L"CoCreating object.\n");
IDiscMaster *pdm;
HRESULT hr = CoCreateInstance(CLSID_MSDiscMasterObj, NULL, CLSCTX_ALL,
IID_IDiscMaster, (void**)&pdm);
if (SUCCEEDED(hr))
{
wprintf(L"Initializing.\n");

hr = pdm->Open();
if (SUCCEEDED(hr))
{
wprintf(L"Setting active disc master format to Joliet.\n");

IJolietDiscMaster *pjdm;
hr = pdm->SetActiveDiscMasterFormat(IID_IJolietDiscMaster,
(void**)&pjdm);
if (SUCCEEDED(hr))
{
hr = SetUpRecorder(pdm, pjdm, pszDir);
if (SUCCEEDED(hr))
{
wprintf(L"Burning disc.\n");
// first param FALSE for non-simulated burn.
// second param TRUE to eject on completion.
hr = pdm->RecordDisc(FALSE, TRUE);
}
// Get IDiscRecorder and close;
IDiscRecorder* piDR;
pdm->GetActiveDiscRecorder(&piDR);
piDR->Close();

pjdm->Release();
}
}
pdm->Release();
}

if (SUCCEEDED(hr))
{
wprintf(L"Burning succeeded.\n");
}
else
{
wprintf(L"Failure, HRESULT = 0x%08X\n", hr);
}
}

int __cdecl wmain(int argc, WCHAR *argv[])
{
if (argc != 2)
{
wprintf(L"IMAPI demo\nUsage: %s <directory to burn>\nExample: \"%s
c:\\files\"\n", argv[0], argv[0]);
}
else
{
if (SUCCEEDED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)))
{
DoBurn(argv[1]);
//===================================================================
//detect if the burn operation worked:
WIN32_FIND_DATA data;
HRESULT hr;
HANDLE hFind = FindFirstFile((LPCTSTR)"e:\\CDBurn.exe", &data);
if (hFind == INVALID_HANDLE_VALUE)
{
printf("RecordDisc did not return error but no files were burned");
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); //<====it always
comes
here
}
else
{
FindClose(hFind);
hr = S_OK;
} //===================================================================
CoUninitialize();
}
}
return 0;
}
 
Hi there,

Don't get me wrong with my last post.... .Net rocks and that's why I use
it.... problem is I can't do something simple like burn a CD (without
delving into code beyond my knowledge and interest) yet our Linux guys wrote
20 lines of code to get the job done. This has thrown the whole project into
"to .Net or not to .Net"... if I can't complete my app with this function
there is a good chance the whole project (subproject actually) will be lost
to that damn penguin....

Yes Peter, Herfield and yourself provided useful info (and I thank you all
again)... but I haven't done C for many many years (OS/2 days) and I have
never really bothered with C++ (too rigid- even if it has the power VB
lacks). Not only that, the app I am coding is being done in VB.Net because
the people that will end up supporting it only (barely) know VB (learning
VB.Net). They are not up to coding or supporting C++ (I would struggle
myself these days).

The code I am working on is part of a AUD$500 million infrastructure project
(Govt)... and while the base infrastructure will be XP and W2K3, I am the
only experienced developer used to Microsoft tools.. it is an uphill battle
for me to get .Net in the door when I have to compete with the large and
well established Unix/Jave/Oracle/Informix development section... this
prototype app could potentially save the organisation millions and it has
been fair quicker and cheaper (1 person instead of a whole dept) to develop
than the usual bloated and expensive software the dev section normally
produce (you wouldn't believe it unless you saw some of it). If I can't get
..Net in the spotlight now I may not be able to at all. And that'd really
suck for me. So something simple like this lack of functionality can have
big consequences.

Anyway, that's my rant for the month...

Maybe you guys could expand the IO capabilities of .Net some time soon... it
would also be great to have a standardised way to access USB tokens and
things like that...

Cheers, and thanks for the post...



Yan-Hong Huang said:
Hello Bob,

I just reviewed the whole post thread. In fact, this is a FAQ in .NET
programming. Many developers may feel confused where to find corresponding
NET framework class libraries in programming. In fact, all the framwork
class library could be found at:
http://msdn.microsoft.com/library/en-us/cpref/html/cpref_start.asp?frame=tru
e

However, .NET framework class library doesn't build in all Win32 SDK APIs
or functions. That is to say, for some Win32 functions, such as GINA,
setting default printer, burning CD, we still need to use typical Win32 API
to achieve it. In order to do so in .NET programming, we provide a method
named Platform Invoke to call typical Win32 APIs in .NET application. For
more information on PInvoke, please refer to:
http://msdn.microsoft.com/library/en-us/cpguide/html/cpconinteroperatingwith
unmanagedcode.asp?frame=true

For this question, currently we have no famework class library support for
burning CD. My suggestion for you is to write a win32 DLL to expose
funtions that you need. You could select whatever languages you like to
develop this Win32 DLL, VC++ or VB. After that, we could call this
unmanaged DLL functions from managed .NET application easily. Peter Huang
has provided an existing sample to you. I also post some useful code slice
in the end of this post. You could refer to it.

There is currently no way to do this, but keep an eye out for it in the
future. We are looking at continual improvement, and it's this kind of
feedback that let us know what things you're trying to do, that we haven't
yet exposed for you.

Keep the information coming.

Thanks very much for your understanding.

Best regards,
Yanhong Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.


Code Slice:

Below is a simple Imapi sample that works for me. I made a console "Hello
world" project and replaced it with the code below. IT takes a command
line path of a driectory to copy, and I added the string: "e:\\CDBurn.exe"
as a known file that would be in the result.

This works for me.

// cd.cpp : Defines the entry point for the console application. //

#include "stdafx.h"

#define _WIN32_WINNT 0x0501
#include <windows.h>
#include <objbase.h>
#include <stdio.h>
#include <shlobj.h>
#include "imapi.h"

HRESULT GetStorage(LPWSTR pszDir, IStorage **ppstg)
{
IShellFolder *psfDesktop;
HRESULT hr = SHGetDesktopFolder(&psfDesktop);
if (SUCCEEDED(hr))
{
IMalloc *pm;
hr = SHGetMalloc(&pm);
if (SUCCEEDED(hr))
{
LPITEMIDLIST pidl;
hr = psfDesktop->ParseDisplayName(NULL, NULL, pszDir, NULL,
&pidl,
NULL);
if (SUCCEEDED(hr))
{
hr = psfDesktop->BindToObject(pidl, NULL, IID_IStorage,
(void**)ppstg);
pm->Free(pidl);
}
pm->Release();
}
psfDesktop->Release();
}
return hr;
}

HRESULT SetUpRecorder(IDiscMaster *pdm, IJolietDiscMaster *pjdm, LPWSTR
pszDir) {
wprintf(L"Getting recorder enumerator object.\n");

IEnumDiscRecorders *pedr;
HRESULT hr = pdm->EnumDiscRecorders(&pedr);
if (SUCCEEDED(hr))
{
wprintf(L"Finding available drive.\n");

ULONG celt;
IDiscRecorder *pdr;
// pick the first supported drive to write to.
hr = pedr->Next(1, &pdr, &celt);
if (S_OK == hr)
{
wprintf(L"Setting active disc recorder.\n");

hr = pdm->SetActiveDiscRecorder(pdr);
if (SUCCEEDED(hr))
{
IStorage *pstg;
hr = GetStorage(pszDir, &pstg);
if (SUCCEEDED(hr))
{
wprintf(L"Adding data to stash file.\n");
hr = pjdm->AddData(pstg, 1);
pstg->Release();
}
else
{
wprintf(L"Couldn't get storage, please check the
path.\n");
}
}
pdr->Release();
}
else
{
wprintf(L"No supported drives found, HRESULT = 0x%08X\n", hr);
hr = E_FAIL;
}
pedr->Release();
}
return hr;
}

void DoBurn(LPWSTR pszDir)
{
wprintf(L"Burning directory %s.\n", pszDir);

wprintf(L"CoCreating object.\n");
IDiscMaster *pdm;
HRESULT hr = CoCreateInstance(CLSID_MSDiscMasterObj, NULL, CLSCTX_ALL,
IID_IDiscMaster, (void**)&pdm);
if (SUCCEEDED(hr))
{
wprintf(L"Initializing.\n");

hr = pdm->Open();
if (SUCCEEDED(hr))
{
wprintf(L"Setting active disc master format to Joliet.\n");

IJolietDiscMaster *pjdm;
hr = pdm->SetActiveDiscMasterFormat(IID_IJolietDiscMaster,
(void**)&pjdm);
if (SUCCEEDED(hr))
{
hr = SetUpRecorder(pdm, pjdm, pszDir);
if (SUCCEEDED(hr))
{
wprintf(L"Burning disc.\n");
// first param FALSE for non-simulated burn.
// second param TRUE to eject on completion.
hr = pdm->RecordDisc(FALSE, TRUE);
}
// Get IDiscRecorder and close;
IDiscRecorder* piDR;
pdm->GetActiveDiscRecorder(&piDR);
piDR->Close();

pjdm->Release();
}
}
pdm->Release();
}

if (SUCCEEDED(hr))
{
wprintf(L"Burning succeeded.\n");
}
else
{
wprintf(L"Failure, HRESULT = 0x%08X\n", hr);
}
}

int __cdecl wmain(int argc, WCHAR *argv[])
{
if (argc != 2)
{
wprintf(L"IMAPI demo\nUsage: %s <directory to burn>\nExample: \"%s
c:\\files\"\n", argv[0], argv[0]);
}
else
{
if (SUCCEEDED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)))
{
DoBurn(argv[1]);
//===================================================================
//detect if the burn operation worked:
WIN32_FIND_DATA data;
HRESULT hr;
HANDLE hFind = FindFirstFile((LPCTSTR)"e:\\CDBurn.exe", &data);
if (hFind == INVALID_HANDLE_VALUE)
{
printf("RecordDisc did not return error but no files were burned");
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); //<====it always
comes
here
}
else
{
FindClose(hFind);
hr = S_OK;
} //===================================================================
CoUninitialize();
}
}
return 0;
}
 
Hi Bob,

Could you please send me an email? You could reach me by removing online
from my email address. We could discuss it further offline.

Thanks very much.

Best regards,
Yanhong Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Back
Top