カクタスソフトウェア
カクタスソフトウェア
サウンド MIDI マルチメディア アプリケーション

ASIOデバイスの列挙

ASIO SDKでは、コンピュータに実装されているデバイスの管理を"AsioDriverList"クラスが担当しています。

ドライバーに関する情報は、レジストリに保存されているため、RegOpenKeyやRegEnumKeyを用いて読み取りを行います。

AsioDriverListのコンストラクタでドライバーの列挙を行っています。レジストリのHKEY_LOCAL_MACHINEの下にあるASIO_PATHキーから、順次ドライバー情報を読み出します。ドライバーはCOMで書かれているので、CoInitialize()関数で初期化を行う必要があります。

AsioDriverList::AsioDriverList ()
{
    HKEY            hkEnum = 0;
    char            keyname[MAXDRVNAMELEN];
    LPASIODRVSTRUCT pdl;
    LONG            cr;
    DWORD           index = 0;
    BOOL            fin = FALSE;

    numdrv      = 0;
    lpdrvlist   = 0;

    cr = RegOpenKey(HKEY_LOCAL_MACHINE,ASIO_PATH,&hkEnum);
    while (cr == ERROR_SUCCESS) {
        if ((cr = RegEnumKey(hkEnum,index++,(LPTSTR)keyname,MAXDRVNAMELEN))== ERROR_SUCCESS) {
            lpdrvlist = newDrvStruct (hkEnum,keyname,0,lpdrvlist);
        }
        else fin = TRUE;
    }
    if (hkEnum) RegCloseKey(hkEnum);

    pdl = lpdrvlist;
    while (pdl) {
        numdrv++;
        pdl = pdl->next;
    }

    if (numdrv) CoInitialize(0);    // initialize COM
}

以下の実装は、同様の機能をC#を用いて書き直したものです。C#は、内部でCOMの初期化を行っているため、改めてCoInitialize()を呼び出す必要はありません。

    public void InitList()
    {
        RegistryKey regkey = Registry.LocalMachine.OpenSubKey(@"software\asio", false);
        if (regkey == null)     return;

        string[] keyNames = regkey.GetSubKeyNames();

        foreach (string keyName in keyNames)
        {
            AsioDrvStruct asioDrv = NewDrvStruct(regkey, keyName, NumDrv);
            AsioDrvList.Add(asioDrv);
        }
        regkey.Close();
    }

ドライバーに関する情報を構造体へ格納する

以下の関数は、ドライバーを列挙するためのサービス関数です。各ドライバーに関する情報を構造体に保存します。

以下にドライバーの情報を保存する構造体を示します。

struct asiodrvstruct
{
    int                     drvID;
    CLSID                   clsid;
    char                    dllpath[MAXPATHLEN];
    char                    drvname[MAXDRVNAMELEN];
    LPVOID                  asiodrv;
    struct asiodrvstruct    *next;
};

ドライバーのパスを取得する関数を用いて、ドライバーの名前などを取得します。

実装されているドライバーの数が、RegEnumKeyを実行してみるまで分からないため、ポインターでチェーンする手法を用いて可変長の構造体アレーを実現しています。

static LPASIODRVSTRUCT newDrvStruct (HKEY hkey,char *keyname,int drvID,LPASIODRVSTRUCT lpdrv)
{
    HKEY    hksub;
    char    databuf[256];
    char    dllpath[MAXPATHLEN];
    WORD    wData[100];
    CLSID   clsid;
    DWORD   datatype,datasize;
    LONG    cr,rc;

    if (!lpdrv) {
        if ((cr = RegOpenKeyEx(hkey,(LPCTSTR)keyname,0,KEY_READ,&hksub)) == ERROR_SUCCESS) {

            datatype = REG_SZ; datasize = 256;
            cr = RegQueryValueEx(hksub,COM_CLSID,0,&datatype,(LPBYTE)databuf,&datasize);
            if (cr == ERROR_SUCCESS) {
                rc = findDrvPath (databuf,dllpath,MAXPATHLEN);
                if (rc == 0) {
                    lpdrv = new ASIODRVSTRUCT[1];
                    if (lpdrv) {
                        memset(lpdrv,0,sizeof(ASIODRVSTRUCT));
                        lpdrv->drvID = drvID;
                        MultiByteToWideChar(CP_ACP,0,(LPCSTR)databuf,-1,(LPWSTR)wData,100);
                        if ((cr = CLSIDFromString((LPOLESTR)wData,(LPCLSID)&clsid)) == S_OK) {
                            memcpy(&lpdrv->clsid,&clsid,sizeof(CLSID));
                        }

                        datatype = REG_SZ; datasize = 256;
                        cr = RegQueryValueEx(hksub,ASIODRV_DESC,0,&datatype,(LPBYTE)databuf,&datasize);
                        if (cr == ERROR_SUCCESS) {
                            strcpy(lpdrv->drvname,databuf);
                        }
                        else strcpy(lpdrv->drvname,keyname);
                    }
                }
            }
            RegCloseKey(hksub);
        }
    }   
    else lpdrv->next = newDrvStruct(hkey,keyname,drvID+1,lpdrv->next);

    return lpdrv;
}

以下の実装は、同様の機能をC#を用いて書き直したものです。

List<AsioDrvStruct>を用いて情報を管理するため、C#の実装ではポインターのチェーンは用いません。

    public class AsioDrvStruct
    {
        public int          drvID;
        public Guid         clsID;
        public string       dllPath;
        public string       drvName;
    }

    private AsioDrvStruct NewDrvStruct(
        RegistryKey     regkey,
        string          keyName,
        int             drvID)
    {
        RegistryKey regSubkey = regkey.OpenSubKey(keyName, false);
        string strClsid = (string)regSubkey.GetValue("CLSID");
        string strDesc = (string)regSubkey.GetValue("Description");
        regSubkey.Close();

        AsioDrvStruct asioDrv = new AsioDrvStruct();
        asioDrv.drvID = drvID;
        asioDrv.clsID = Guid.Parse(strClsid);
        asioDrv.dllPath = FindDrvPath(strClsid);
        asioDrv.drvName = strDesc;
        return asioDrv;
    }

ドライバーのパスを得る

CLSIDからドライバーのパスを取得します。

取得手順は、最初に"clsid"のルートクラスを開き、そして検索対象のCLSID、そして"InprocServer32"と階層を降りて行き、バリューを取得します。最後にドライバーファイルが存在するかどうかを確認しています。

#define ASIODRV_DESC    "description"
#define INPROC_SERVER   "InprocServer32"
#define COM_CLSID       "clsid"
#define ASIO_PATH       "software\\asio"
static LONG findDrvPath (char *clsidstr,char *dllpath,int dllpathsize)
{
    HKEY            hkEnum,hksub,hkpath;
    char            databuf[512];
    LONG            cr,rc = -1;
    DWORD           datatype,datasize;
    DWORD           index;
    OFSTRUCT        ofs;
    HFILE           hfile;
    BOOL            found = FALSE;

    CharLowerBuff(clsidstr,strlen(clsidstr));
    if ((cr = RegOpenKey(HKEY_CLASSES_ROOT,COM_CLSID,&hkEnum)) == ERROR_SUCCESS) {

        index = 0;
        while (cr == ERROR_SUCCESS && !found) {
            cr = RegEnumKey(hkEnum,index++,(LPTSTR)databuf,512);
            if (cr == ERROR_SUCCESS) {
                CharLowerBuff(databuf,strlen(databuf));
                if (!(strcmp(databuf,clsidstr))) {
                    if ((cr = RegOpenKeyEx(hkEnum,(LPCTSTR)databuf,0,KEY_READ,&hksub)) == ERROR_SUCCESS) {
                        if ((cr = RegOpenKeyEx(hksub,(LPCTSTR)INPROC_SERVER,0,KEY_READ,&hkpath)) == ERROR_SUCCESS) {
                            datatype = REG_SZ; datasize = (DWORD)dllpathsize;
                            cr = RegQueryValueEx(hkpath,0,0,&datatype,(LPBYTE)dllpath,&datasize);
                            if (cr == ERROR_SUCCESS) {
                                memset(&ofs,0,sizeof(OFSTRUCT));
                                ofs.cBytes = sizeof(OFSTRUCT); 
                                hfile = OpenFile(dllpath,&ofs,OF_EXIST);
                                if (hfile) rc = 0; 
                            }
                            RegCloseKey(hkpath);
                        }
                        RegCloseKey(hksub);
                    }
                    found = TRUE;   // break out 
                }
            }
        }               
        RegCloseKey(hkEnum);
    }
    return rc;
}

以下の実装は、同様の機能をC#を用いて書き直したものです。

    private string FindDrvPath(string clsid)
    {
        string dllPath = "";

        RegistryKey regRootKey = Registry.ClassesRoot.OpenSubKey("CLSID", false);
        if (regRootKey != null)
        {
            RegistryKey regClsidKey = regRootKey.OpenSubKey(clsid, false);
            if (regClsidKey != null)
            {
                RegistryKey regServerKey = regClsidKey.OpenSubKey("InprocServer32", false);
                if (regServerKey != null)
                {
                    dllPath = (string)regServerKey.GetValue("");
                    regServerKey.Close();
                }
                regClsidKey.Close();
            }
            regRootKey.Close();
        }
        return File.Exists(dllPath) ? dllPath : "";
    }

ドキュメントの先頭へ

カクタスソフトウェア 技術協力 資料室 資料室の広場 SourceForge.jp お問い合わせ